Merge git://git.kernel.org/pub/scm/linux/kernel/git/bunk/trivial
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
index 68a711f..1537842 100644
--- a/Documentation/cciss.txt
+++ b/Documentation/cciss.txt
@@ -133,3 +133,32 @@
 access these devices too, as if the array controller were merely a SCSI 
 controller in the same way that we are allowing it to access SCSI tape drives.
 
+SCSI error handling for tape drives and medium changers
+-------------------------------------------------------
+
+The linux SCSI mid layer provides an error handling protocol which
+kicks into gear whenever a SCSI command fails to complete within a
+certain amount of time (which can vary depending on the command).
+The cciss driver participates in this protocol to some extent.  The
+normal protocol is a four step process.  First the device is told
+to abort the command.  If that doesn't work, the device is reset.
+If that doesn't work, the SCSI bus is reset.  If that doesn't work
+the host bus adapter is reset.  Because the cciss driver is a block
+driver as well as a SCSI driver and only the tape drives and medium
+changers are presented to the SCSI mid layer, and unlike more 
+straightforward SCSI drivers, disk i/o continues through the block
+side during the SCSI error recovery process, the cciss driver only
+implements the first two of these actions, aborting the command, and
+resetting the device.  Additionally, most tape drives will not oblige 
+in aborting commands, and sometimes it appears they will not even 
+obey a reset coommand, though in most circumstances they will.  In
+the case that the command cannot be aborted and the device cannot be 
+reset, the device will be set offline.
+
+In the event the error handling code is triggered and a tape drive is
+successfully reset or the tardy command is successfully aborted, the 
+tape drive may still not allow i/o to continue until some command
+is issued which positions the tape to a known position.  Typically you
+must rewind the tape (by issuing "mt -f /dev/st0 rewind" for example)
+before i/o can proceed again to a tape drive which was reset.
+
diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c
index b7de82e..3e73231 100644
--- a/Documentation/connector/cn_test.c
+++ b/Documentation/connector/cn_test.c
@@ -25,7 +25,7 @@
 #include <linux/skbuff.h>
 #include <linux/timer.h>
 
-#include "connector.h"
+#include <linux/connector.h>
 
 static struct cb_id cn_test_id = { 0x123, 0x456 };
 static char cn_test_name[] = "cn_test";
@@ -104,7 +104,7 @@
 	req->first = cn_test_id.val + 20;
 	req->range = 10;
 
-	NETLINK_CB(skb).dst_groups = ctl->group;
+	NETLINK_CB(skb).dst_group = ctl->group;
 	//netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC);
 	netlink_unicast(nls, skb, 0, 0);
 
diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt
index cb63b7a..df6c054 100644
--- a/Documentation/dvb/bt8xx.txt
+++ b/Documentation/dvb/bt8xx.txt
@@ -1,5 +1,5 @@
-How to get the Nebula, PCTV and Twinhan DST cards working
-=========================================================
+How to get the Nebula, PCTV, FusionHDTV Lite and Twinhan DST cards working
+==========================================================================
 
 This class of cards has a bt878a as the PCI interface, and
 require the bttv driver.
@@ -26,27 +26,31 @@
 
 In general you need to load the bttv driver, which will handle the gpio and
 i2c communication for us, plus the common dvb-bt8xx device driver.
-The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and
-TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
+The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110), TwinHan (dst),
+FusionHDTV DVB-T Lite (mt352) and FusionHDTV5 Lite (lgdt330x) are loaded
+automatically by the dvb-bt8xx device driver.
 
-3a) Nebula / Pinnacle PCTV
---------------------------
+3a) Nebula / Pinnacle PCTV / FusionHDTV Lite
+---------------------------------------------
 
    $ modprobe bttv (normally bttv is being loaded automatically by kmod)
-   $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading)
+   $ modprobe dvb-bt8xx
+
+(or just place dvb-bt8xx in /etc/modules for automatic loading)
 
 
 3b) TwinHan and Clones
 --------------------------
 
-   $ modprobe bttv i2c_hw=1 card=0x71
+   $ modprobe bttv card=0x71
    $ modprobe dvb-bt8xx
    $ modprobe dst
 
 The value 0x71 will override the PCI type detection for dvb-bt8xx,
-which  is necessary for TwinHan cards.
+which  is necessary for TwinHan cards. Omission of this parameter might result
+in a system lockup.
 
-If you're having an older card (blue color circuit) and card=0x71 locks
+If you're having an older card (blue color PCB) and card=0x71 locks up
 your machine, try using 0x68, too. If that does not work, ask on the
 mailing list.
 
@@ -64,11 +68,47 @@
 dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card.
 0x20 means it has a Conditional Access slot.
 
-The autodected values are determined bythe cards 'response
-string' which you can see in your logs e.g.
+The autodetected values are determined by the cards 'response string'
+which you can see in your logs e.g.
 
 dst_get_device_id: Recognise [DSTMCI]
 
+If you need to sent in bug reports on the dst, please do send in a complete
+log with the verbose=4 module parameter. For general usage, the default setting
+of verbose=1 is ideal.
+
+
+4) Multiple cards
+--------------------------
+
+If you happen to be running multiple cards, it would be advisable to load
+the bttv module with the card id. This would help to solve any module loading
+problems that you might face.
+
+For example, if you have a Twinhan and Clones card along with a FusionHDTV5 Lite
+
+	$ modprobe bttv card=0x71 card=0x87
+
+Here the order of the card id is important and should be the same as that of the
+physical order of the cards. Here card=0x71 represents the Twinhan and clones
+and card=0x87 represents Fusion HDTV5 Lite. These arguments can also be
+specified in decimal, rather than hex:
+
+	$ modprobe bttv card=113 card=135
+
+Some examples of card-id's
+
+Pinnacle Sat		0x5e  (94)
+Nebula Digi TV		0x68  (104)
+PC HDTV			0x70  (112)
+Twinhan			0x71  (113)
+FusionHDTV DVB-T Lite	0x80  (128)
+FusionHDTV5 Lite	0x87  (135)
+
+For a full list of card-id's, see the V4L Documentation within the kernel
+source:  linux/Documentation/video4linux/CARDLIST.bttv
+
+If you have problems with this please do ask on the mailing list.
 
 --
 Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham
diff --git a/Documentation/dvb/cards.txt b/Documentation/dvb/cards.txt
index efdc4ee..19329cf 100644
--- a/Documentation/dvb/cards.txt
+++ b/Documentation/dvb/cards.txt
@@ -41,6 +41,12 @@
    - dib3000mb	: DiBcom 3000-MB demodulator
   DVB-S/C/T:
    - dst		: TwinHan DST Frontend
+  ATSC:
+   - nxt200x		: Nxtwave NXT2002 & NXT2004
+   - or51211		: or51211 based (pcHDTV HD2000 card)
+   - or51132		: or51132 based (pcHDTV HD3000 card)
+   - bcm3510		: Broadcom BCM3510
+   - lgdt330x		: LG Electronics DT3302 & DT3303
 
 
 o Cards based on the Phillips saa7146 multimedia PCI bridge chip:
@@ -62,6 +68,10 @@
   - Nebula Electronics DigiTV
   - TwinHan DST
   - Avermedia DVB-T
+  - ChainTech digitop DST-1000 DVB-S
+  - pcHDTV HD-2000 TV
+  - DViCO FusionHDTV DVB-T Lite
+  - DViCO FusionHDTV5 Lite
 
 o Technotrend / Hauppauge DVB USB devices:
   - Nova USB
@@ -83,3 +93,30 @@
   - DiBcom USB2.0 DVB-T reference device (non-public)
 
 o Experimental support for the analog module of the Siemens DVB-C PCI card
+
+o Cards based on the Conexant cx2388x PCI bridge:
+  - ADS Tech Instant TV DVB-T PCI
+  - ATI HDTV Wonder
+  - digitalnow DNTV Live! DVB-T
+  - DViCO FusionHDTV DVB-T1
+  - DViCO FusionHDTV DVB-T Plus
+  - DViCO FusionHDTV3 Gold-Q
+  - DViCO FusionHDTV3 Gold-T
+  - DViCO FusionHDTV5 Gold
+  - Hauppauge Nova-T DVB-T
+  - KWorld/VStream XPert DVB-T
+  - pcHDTV HD3000 HDTV
+  - TerraTec Cinergy 1400 DVB-T
+  - WinFast DTV1000-T
+
+o Cards based on the Phillips saa7134 PCI bridge:
+  - Medion 7134
+  - Pinnacle PCTV 300i DVB-T + PAL
+  - LifeView FlyDVB-T DUO
+  - Typhoon DVB-T Duo Digital/Analog Cardbus
+  - Philips TOUGH DVB-T reference design
+  - Philips EUROPA V3 reference design
+  - Compro Videomate DVB-T300
+  - Compro Videomate DVB-T200
+  - AVerMedia AVerTVHD MCE A180
+
diff --git a/Documentation/dvb/contributors.txt b/Documentation/dvb/contributors.txt
index c9d5ce3..2cbd2d0 100644
--- a/Documentation/dvb/contributors.txt
+++ b/Documentation/dvb/contributors.txt
@@ -75,5 +75,22 @@
 Peter Beutner <p.beutner@gmx.net>
   for the IR code for the ttusb-dec driver
 
+Wilson Michaels <wilsonmichaels@earthlink.net>
+  for the lgdt330x frontend driver, and various bugfixes
+
+Michael Krufky <mkrufky@m1k.net>
+  for maintaining v4l/dvb inter-tree dependencies
+
+Taylor Jacob <rtjacob@earthlink.net>
+  for the nxt2002 frontend driver
+
+Jean-Francois Thibert <jeanfrancois@sagetv.com>
+  for the nxt2004 frontend driver
+
+Kirk Lapray <kirk.lapray@gmail.com>
+  for the or51211 and or51132 frontend drivers, and
+  for merging the nxt2002 and nxt2004 modules into a
+  single nxt200x frontend driver.
+
 (If you think you should be in this list, but you are not, drop a
  line to the DVB mailing list)
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index a750f01..be6eb4c 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -22,7 +22,7 @@
 use IO::Handle;
 
 @components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
-		"dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002",
+		"dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
 		"or51211", "or51132_qam", "or51132_vsb");
 
 # Check args
@@ -252,6 +252,23 @@
     $outfile;
 }
 
+sub nxt2004 {
+    my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip";
+    my $url = "http://www.aver.com/support/Drivers/$sourcefile";
+    my $hash = "111cb885b1e009188346d72acfed024c";
+    my $outfile = "dvb-fe-nxt2004.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/3xHybrid.sys", $hash);
+    extract("$tmpdir/3xHybrid.sys", 465304, 9584, $outfile);
+
+    $outfile;
+}
+
 sub or51211 {
     my $fwfile = "dvb-fe-or51211.fw";
     my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
diff --git a/Documentation/fb/fbcon.txt b/Documentation/fb/fbcon.txt
new file mode 100644
index 0000000..08dce0f
--- /dev/null
+++ b/Documentation/fb/fbcon.txt
@@ -0,0 +1,152 @@
+The Framebuffer Console
+=======================
+
+	The framebuffer console (fbcon), as its name implies, is a text
+console running on top of the framebuffer device. It has the functionality of
+any standard text console driver, such as the VGA console, with the added
+features that can be attributed to the graphical nature of the framebuffer.
+
+	 In the x86 architecture, the framebuffer console is optional, and
+some even treat it as a toy. For other architectures, it is the only available
+display device, text or graphical.
+
+	 What are the features of fbcon?  The framebuffer console supports
+high resolutions, varying font types, display rotation, primitive multihead,
+etc. Theoretically, multi-colored fonts, blending, aliasing, and any feature
+made available by the underlying graphics card are also possible.
+
+A. Configuration
+
+	The framebuffer console can be enabled by using your favorite kernel
+configuration tool.  It is under Device Drivers->Graphics Support->Support for
+framebuffer devices->Framebuffer Console Support. Select 'y' to compile
+support statically, or 'm' for module support.  The module will be fbcon.
+
+	In order for fbcon to activate, at least one framebuffer driver is
+required, so choose from any of the numerous drivers available. For x86
+systems, they almost universally have VGA cards, so vga16fb and vesafb will
+always be available. However, using a chipset-specific driver will give you
+more speed and features, such as the ability to change the video mode
+dynamically.
+
+	To display the penguin logo, choose any logo available in Logo
+Configuration->Boot up logo.
+
+	Also, you will need to select at least one compiled-in fonts, but if
+you don't do anything, the kernel configuration tool will select one for you,
+usually an 8x16 font.
+
+GOTCHA: A common bug report is enabling the framebuffer without enabling the
+framebuffer console.  Depending on the driver, you may get a blanked or
+garbled display, but the system still boots to completion.  If you are
+fortunate to have a driver that does not alter the graphics chip, then you
+will still get a VGA console.
+
+B. Loading
+
+Possible scenarios:
+
+1. Driver and fbcon are compiled statically
+
+	 Usually, fbcon will automatically take over your console. The notable
+	 exception is vesafb.  It needs to be explicitly activated with the
+	 vga= boot option parameter.
+
+2. Driver is compiled statically, fbcon is compiled as a module
+
+	 Depending on the driver, you either get a standard console, or a
+	 garbled display, as mentioned above.  To get a framebuffer console,
+	 do a 'modprobe fbcon'.
+
+3. Driver is compiled as a module, fbcon is compiled statically
+
+	 You get your standard console.  Once the driver is loaded with
+	 'modprobe xxxfb', fbcon automatically takes over the console with
+	 the possible exception of using the fbcon=map:n option. See below.
+
+4. Driver and fbcon are compiled as a module.
+
+	 You can load them in any order. Once both are loaded, fbcon will take
+	 over the console.
+
+C. Boot options
+
+         The framebuffer console has several, largely unknown, boot options
+         that can change its behavior.
+
+1. fbcon=font:<name>
+
+        Select the initial font to use. The value 'name' can be any of the
+        compiled-in fonts: VGA8x16, 7x14, 10x18, VGA8x8, MINI4x6, RomanLarge,
+        SUN8x16, SUN12x22, ProFont6x11, Acorn8x8, PEARL8x8.
+
+	Note, not all drivers can handle font with widths not divisible by 8,
+        such as vga16fb.
+
+2. fbcon=scrollback:<value>[k]
+
+        The scrollback buffer is memory that is used to preserve display
+        contents that has already scrolled past your view.  This is accessed
+        by using the Shift-PageUp key combination.  The value 'value' is any
+        integer. It defaults to 32KB.  The 'k' suffix is optional, and will
+        multiply the 'value' by 1024.
+
+3. fbcon=map:<0123>
+
+        This is an interesting option. It tells which driver gets mapped to
+        which console. The value '0123' is a sequence that gets repeated until
+        the total length is 64 which is the number of consoles available. In
+        the above example, it is expanded to 012301230123... and the mapping
+        will be:
+
+		tty | 1 2 3 4 5 6 7 8 9 ...
+		fb  | 0 1 2 3 0 1 2 3 0 ...
+
+		('cat /proc/fb' should tell you what the fb numbers are)
+
+	One side effect that may be useful is using a map value that exceeds
+	the number of loaded fb drivers. For example, if only one driver is
+	available, fb0, adding fbcon=map:1 tells fbcon not to take over the
+	console.
+
+	Later on, when you want to map the console the to the framebuffer
+	device, you can use the con2fbmap utility.
+
+4. fbcon=vc:<n1>-<n2>
+
+	This option tells fbcon to take over only a range of consoles as
+	specified by the values 'n1' and 'n2'. The rest of the consoles
+	outside the given range will still be controlled by the standard
+	console driver.
+
+	NOTE: For x86 machines, the standard console is the VGA console which
+	is typically located on the same video card.  Thus, the consoles that
+	are controlled by the VGA console will be garbled.
+
+4. fbcon=rotate:<n>
+
+        This option changes the orientation angle of the console display. The
+        value 'n' accepts the following:
+
+	      0 - normal orientation (0 degree)
+	      1 - clockwise orientation (90 degrees)
+	      2 - upside down orientation (180 degrees)
+	      3 - counterclockwise orientation (270 degrees)
+
+	The angle can be changed anytime afterwards by 'echoing' the same
+	numbers to any one of the 2 attributes found in
+	/sys/class/graphics/fb{x}
+
+		con_rotate     - rotate the display of the active console
+		con_rotate_all - rotate the display of all consoles
+
+	Console rotation will only become available if Console Rotation
+	Support is compiled in your kernel.
+
+	NOTE: This is purely console rotation.  Any other applications that
+	use the framebuffer will remain at their 'normal'orientation.
+	Actually, the underlying fb driver is totally ignorant of console
+	rotation.
+
+---
+Antonino Daplas <adaplas@pol.net>
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index decdf99..429db4b 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -25,6 +25,13 @@
 
 ---------------------------
 
+What:	drivers depending on OBSOLETE_OSS_DRIVER
+When:	January 2006
+Why:	OSS drivers with ALSA replacements
+Who:	Adrian Bunk <bunk@stusta.de>
+
+---------------------------
+
 What:	RCU API moves to EXPORT_SYMBOL_GPL
 When:	April 2006
 Files:	include/linux/rcupdate.h, kernel/rcupdate.c
@@ -60,6 +67,21 @@
 
 ---------------------------
 
+What:	Video4Linux API 1 ioctls and video_decoder.h from Video devices.
+When:	July 2006
+Why:	V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
+	series. The old API have lots of drawbacks and don't provide enough
+	means to work with all video and audio standards. The newer API is
+	already available on the main drivers and should be used instead.
+	Newer drivers should use v4l_compat_translate_ioctl function to handle
+	old calls, replacing to newer ones.
+	Decoder iocts are using internally to allow video drivers to
+	communicate with video decoders. This should also be improved to allow
+	V4L2 calls being translated into compatible internal ioctls.
+Who:	Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+
+---------------------------
+
 What:	i2c sysfs name change: in1_ref, vid deprecated in favour of cpu0_vid
 When:	November 2005
 Files:	drivers/i2c/chips/adm1025.c, drivers/i2c/chips/adm1026.c
@@ -111,3 +133,10 @@
 	to link against API-compatible library on top of libnfnetlink_queue 
 	instead of the current 'libipq'.
 Who:	Harald Welte <laforge@netfilter.org>
+
+---------------------------
+
+What:	EXPORT_SYMBOL(lookup_hash)
+When:	January 2006
+Why:	Too low-level interface.  Use lookup_one_len or lookup_create instead.
+Who:	Christoph Hellwig <hch@lst.de>
diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt
index d16334e..a8edb37 100644
--- a/Documentation/filesystems/ext2.txt
+++ b/Documentation/filesystems/ext2.txt
@@ -17,8 +17,6 @@
 bsddf			(*)	Makes `df' act like BSD.
 minixdf				Makes `df' act like Minix.
 
-check				Check block and inode bitmaps at mount time
-				(requires CONFIG_EXT2_CHECK).
 check=none, nocheck	(*)	Don't do extra checking of bitmaps on mount
 				(check=normal and check=strict options removed)
 
diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
index 9363b8b..1677566 100644
--- a/Documentation/i2c/busses/i2c-viapro
+++ b/Documentation/i2c/busses/i2c-viapro
@@ -7,12 +7,10 @@
   * VIA Technologies, Inc. VT82C686A/B
     Datasheet: Sometimes available at the VIA website
 
-  * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237
-    Datasheet: available on request from Via
+  * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237R
+    Datasheet: available on request from VIA
 
 Authors:
-	Frodo Looijaard <frodol@dds.nl>,
-	Philip Edelbrock <phil@netroedge.com>,
 	Kyösti Mälkki <kmalkki@cc.hut.fi>,
 	Mark D. Studebaker <mdsxyz123@yahoo.com>,
 	Jean Delvare <khali@linux-fr.org>
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index cff7b65..d19993c 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -412,7 +412,7 @@
         release_region(address,FOO_EXTENT);
     /* SENSORS ONLY END */
     ERROR1:
-      kfree(new_client);
+      kfree(data);
     ERROR0:
       return err;
   }
@@ -443,7 +443,7 @@
       release_region(client->addr,LM78_EXTENT);
     /* HYBRID SENSORS CHIP ONLY END */
 
-    kfree(data);
+    kfree(i2c_get_clientdata(client));
     return 0;
   }
 
diff --git a/Documentation/md.txt b/Documentation/md.txt
index e2b5369..23e6cce 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -116,3 +116,122 @@
 
 Once started with RUN_ARRAY, uninitialized spares can be added with
 HOT_ADD_DISK.
+
+
+
+MD devices in sysfs
+-------------------
+md devices appear in sysfs (/sys) as regular block devices,
+e.g.
+   /sys/block/md0
+
+Each 'md' device will contain a subdirectory called 'md' which
+contains further md-specific information about the device.
+
+All md devices contain:
+  level
+     a text file indicating the 'raid level'.  This may be a standard
+     numerical level prefixed by "RAID-" - e.g. "RAID-5", or some
+     other name such as "linear" or "multipath".
+     If no raid level has been set yet (array is still being
+     assembled), this file will be empty.
+
+  raid_disks
+     a text file with a simple number indicating the number of devices
+     in a fully functional array.  If this is not yet known, the file
+     will be empty.  If an array is being resized (not currently
+     possible) this will contain the larger of the old and new sizes.
+
+As component devices are added to an md array, they appear in the 'md'
+directory as new directories named
+      dev-XXX
+where XXX is a name that the kernel knows for the device, e.g. hdb1.
+Each directory contains:
+
+      block
+        a symlink to the block device in /sys/block, e.g.
+	     /sys/block/md0/md/dev-hdb1/block -> ../../../../block/hdb/hdb1
+
+      super
+        A file containing an image of the superblock read from, or
+        written to, that device.
+
+      state
+        A file recording the current state of the device in the array
+	which can be a comma separated list of
+	      faulty   - device has been kicked from active use due to
+                         a detected fault
+	      in_sync  - device is a fully in-sync member of the array
+	      spare    - device is working, but not a full member.
+			 This includes spares that are in the process
+			 of being recoverred to
+	This list make grow in future.
+
+
+An active md device will also contain and entry for each active device
+in the array.  These are named
+
+    rdNN
+
+where 'NN' is the possition in the array, starting from 0.
+So for a 3 drive array there will be rd0, rd1, rd2.
+These are symbolic links to the appropriate 'dev-XXX' entry.
+Thus, for example,
+       cat /sys/block/md*/md/rd*/state
+will show 'in_sync' on every line.
+
+
+
+Active md devices for levels that support data redundancy (1,4,5,6)
+also have
+
+   sync_action
+     a text file that can be used to monitor and control the rebuild
+     process.  It contains one word which can be one of:
+       resync        - redundancy is being recalculated after unclean
+                       shutdown or creation
+       recover       - a hot spare is being built to replace a
+                       failed/missing device
+       idle          - nothing is happening
+       check         - A full check of redundancy was requested and is
+                       happening.  This reads all block and checks
+                       them. A repair may also happen for some raid
+                       levels.
+       repair        - A full check and repair is happening.  This is
+                       similar to 'resync', but was requested by the
+                       user, and the write-intent bitmap is NOT used to
+		       optimise the process.
+
+      This file is writable, and each of the strings that could be
+      read are meaningful for writing.
+
+       'idle' will stop an active resync/recovery etc.  There is no
+           guarantee that another resync/recovery may not be automatically
+	   started again, though some event will be needed to trigger
+           this.
+	'resync' or 'recovery' can be used to restart the
+           corresponding operation if it was stopped with 'idle'.
+	'check' and 'repair' will start the appropriate process
+           providing the current state is 'idle'.
+
+   mismatch_count
+      When performing 'check' and 'repair', and possibly when
+      performing 'resync', md will count the number of errors that are
+      found.  The count in 'mismatch_cnt' is the number of sectors
+      that were re-written, or (for 'check') would have been
+      re-written.  As most raid levels work in units of pages rather
+      than sectors, this my be larger than the number of actual errors
+      by a factor of the number of sectors in a page.
+
+Each active md device may also have attributes specific to the
+personality module that manages it.
+These are specific to the implementation of the module and could
+change substantially if the implementation changes.
+
+These currently include
+
+  stripe_cache_size  (currently raid5 only)
+      number of entries in the stripe cache.  This is writable, but
+      there are upper and lower limits (32768, 16).  Default is 128.
+  strip_cache_active (currently raid5 only)
+      number of active entries in the stripe cache
diff --git a/Documentation/networking/README.ipw2100 b/Documentation/networking/README.ipw2100
index 2046948..3ab4037 100644
--- a/Documentation/networking/README.ipw2100
+++ b/Documentation/networking/README.ipw2100
@@ -1,27 +1,82 @@
 
-===========================
-Intel(R) PRO/Wireless 2100 Network Connection Driver for Linux
+Intel(R) PRO/Wireless 2100 Driver for Linux in support of:
+
+Intel(R) PRO/Wireless 2100 Network Connection
+
+Copyright (C) 2003-2005, Intel Corporation
+
 README.ipw2100
 
-March 14, 2005
+Version: 1.1.3
+Date   : October 17, 2005
 
-===========================
 Index
----------------------------
-0. Introduction
-1. Release 1.1.0 Current Features
-2. Command Line Parameters
-3. Sysfs Helper Files
-4. Radio Kill Switch
-5. Dynamic Firmware
-6. Power Management
-7. Support
-8. License
+-----------------------------------------------
+0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
+1. Introduction
+2. Release 1.1.3 Current Features
+3. Command Line Parameters
+4. Sysfs Helper Files
+5. Radio Kill Switch
+6. Dynamic Firmware
+7. Power Management
+8. Support
+9. License
 
 
-===========================
-0. Introduction
------------- -----   -----       ----       ---       --         -     
+0.   IMPORTANT INFORMATION BEFORE USING THIS DRIVER
+-----------------------------------------------
+
+Important Notice FOR ALL USERS OR DISTRIBUTORS!!!!
+
+Intel wireless LAN adapters are engineered, manufactured, tested, and
+quality checked to ensure that they meet all necessary local and
+governmental regulatory agency requirements for the regions that they
+are designated and/or marked to ship into. Since wireless LANs are
+generally unlicensed devices that share spectrum with radars,
+satellites, and other licensed and unlicensed devices, it is sometimes
+necessary to dynamically detect, avoid, and limit usage to avoid
+interference with these devices. In many instances Intel is required to
+provide test data to prove regional and local compliance to regional and
+governmental regulations before certification or approval to use the
+product is granted. Intel's wireless LAN's EEPROM, firmware, and
+software driver are designed to carefully control parameters that affect
+radio operation and to ensure electromagnetic compliance (EMC). These
+parameters include, without limitation, RF power, spectrum usage,
+channel scanning, and human exposure.
+
+For these reasons Intel cannot permit any manipulation by third parties
+of the software provided in binary format with the wireless WLAN
+adapters (e.g., the EEPROM and firmware). Furthermore, if you use any
+patches, utilities, or code with the Intel wireless LAN adapters that
+have been manipulated by an unauthorized party (i.e., patches,
+utilities, or code (including open source code modifications) which have
+not been validated by Intel), (i) you will be solely responsible for
+ensuring the regulatory compliance of the products, (ii) Intel will bear
+no liability, under any theory of liability for any issues associated
+with the modified products, including without limitation, claims under
+the warranty and/or issues arising from regulatory non-compliance, and
+(iii) Intel will not provide or be required to assist in providing
+support to any third parties for such modified products.
+
+Note: Many regulatory agencies consider Wireless LAN adapters to be
+modules, and accordingly, condition system-level regulatory approval
+upon receipt and review of test data documenting that the antennas and
+system configuration do not cause the EMC and radio operation to be
+non-compliant.
+
+The drivers available for download from SourceForge are provided as a
+part of a development project.  Conformance to local regulatory
+requirements is the responsibility of the individual developer.  As
+such, if you are interested in deploying or shipping a driver as part of
+solution intended to be used for purposes other than development, please
+obtain a tested driver from Intel Customer Support at:
+
+http://support.intel.com/support/notebook/sb/CS-006408.htm
+
+
+1. Introduction
+-----------------------------------------------
 
 This document provides a brief overview of the features supported by the 
 IPW2100 driver project.  The main project website, where the latest 
@@ -34,9 +89,8 @@
 for the driver project.
 
 
-===========================
-1. Release 1.1.0 Current Supported Features
----------------------------     
+2. Release 1.1.3 Current Supported Features
+-----------------------------------------------
 - Managed (BSS) and Ad-Hoc (IBSS)
 - WEP (shared key and open)
 - Wireless Tools support 
@@ -51,9 +105,8 @@
 performed on a given feature.
 
 
-===========================
-2. Command Line Parameters
----------------------------     
+3. Command Line Parameters
+-----------------------------------------------
 
 If the driver is built as a module, the following optional parameters are used
 by entering them on the command line with the modprobe command using this
@@ -75,9 +128,9 @@
 disable		boolean		disable=1 /* Do not power the HW */
 
 
-===========================
-3. Sysfs Helper Files
+4. Sysfs Helper Files
 ---------------------------     
+-----------------------------------------------
 
 There are several ways to control the behavior of the driver.  Many of the 
 general capabilities are exposed through the Wireless Tools (iwconfig).  There
@@ -120,9 +173,8 @@
   	based RF kill from ON -> OFF -> ON, the radio will NOT come back on
 
 
-===========================
-4. Radio Kill Switch
----------------------------
+5. Radio Kill Switch
+-----------------------------------------------
 Most laptops provide the ability for the user to physically disable the radio.
 Some vendors have implemented this as a physical switch that requires no
 software to turn the radio off and on.  On other laptops, however, the switch
@@ -134,9 +186,8 @@
 on your system.
 
 
-===========================
-5. Dynamic Firmware
----------------------------     
+6. Dynamic Firmware
+-----------------------------------------------
 As the firmware is licensed under a restricted use license, it can not be 
 included within the kernel sources.  To enable the IPW2100 you will need a 
 firmware image to load into the wireless NIC's processors.
@@ -146,9 +197,8 @@
 See INSTALL for instructions on installing the firmware.
 
 
-===========================
-6. Power Management
----------------------------     
+7. Power Management
+-----------------------------------------------
 The IPW2100 supports the configuration of the Power Save Protocol 
 through a private wireless extension interface.  The IPW2100 supports 
 the following different modes:
@@ -200,9 +250,8 @@
 level if `iwconfig eth1 power on` is invoked.
 
 
-===========================
-7. Support
----------------------------     
+8. Support
+-----------------------------------------------
 
 For general development information and support,
 go to:
@@ -218,9 +267,8 @@
 
     http://supportmail.intel.com
 
-===========================
-8. License
----------------------------     
+9. License
+-----------------------------------------------
 
   Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
 
diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200
index 6916080..c6492d3 100644
--- a/Documentation/networking/README.ipw2200
+++ b/Documentation/networking/README.ipw2200
@@ -1,33 +1,89 @@
 
 Intel(R) PRO/Wireless 2915ABG Driver for Linux in support of:
 
-Intel(R) PRO/Wireless 2200BG Network Connection 
-Intel(R) PRO/Wireless 2915ABG Network Connection 
+Intel(R) PRO/Wireless 2200BG Network Connection
+Intel(R) PRO/Wireless 2915ABG Network Connection
 
-Note: The Intel(R) PRO/Wireless 2915ABG Driver for Linux and Intel(R) 
-PRO/Wireless 2200BG Driver for Linux is a unified driver that works on 
-both hardware adapters listed above. In this document the Intel(R) 
-PRO/Wireless 2915ABG Driver for Linux will be used to reference the 
+Note: The Intel(R) PRO/Wireless 2915ABG Driver for Linux and Intel(R)
+PRO/Wireless 2200BG Driver for Linux is a unified driver that works on
+both hardware adapters listed above. In this document the Intel(R)
+PRO/Wireless 2915ABG Driver for Linux will be used to reference the
 unified driver.
 
 Copyright (C) 2004-2005, Intel Corporation
 
 README.ipw2200
 
-Version: 1.0.0
-Date   : January 31, 2005
+Version: 1.0.8
+Date   : October 20, 2005
 
 
 Index
 -----------------------------------------------
+0.   IMPORTANT INFORMATION BEFORE USING THIS DRIVER
 1.   Introduction
 1.1. Overview of features
 1.2. Module parameters
 1.3. Wireless Extension Private Methods
 1.4. Sysfs Helper Files
-2.   About the Version Numbers
-3.   Support
-4.   License
+2.   Ad-Hoc Networking
+3.   Interacting with Wireless Tools
+3.1. iwconfig mode
+4.   About the Version Numbers
+5.   Firmware installation
+6.   Support
+7.   License
+
+
+0.   IMPORTANT INFORMATION BEFORE USING THIS DRIVER
+-----------------------------------------------
+
+Important Notice FOR ALL USERS OR DISTRIBUTORS!!!! 
+
+Intel wireless LAN adapters are engineered, manufactured, tested, and
+quality checked to ensure that they meet all necessary local and
+governmental regulatory agency requirements for the regions that they
+are designated and/or marked to ship into. Since wireless LANs are
+generally unlicensed devices that share spectrum with radars,
+satellites, and other licensed and unlicensed devices, it is sometimes
+necessary to dynamically detect, avoid, and limit usage to avoid
+interference with these devices. In many instances Intel is required to
+provide test data to prove regional and local compliance to regional and
+governmental regulations before certification or approval to use the
+product is granted. Intel's wireless LAN's EEPROM, firmware, and
+software driver are designed to carefully control parameters that affect
+radio operation and to ensure electromagnetic compliance (EMC). These
+parameters include, without limitation, RF power, spectrum usage,
+channel scanning, and human exposure. 
+
+For these reasons Intel cannot permit any manipulation by third parties
+of the software provided in binary format with the wireless WLAN
+adapters (e.g., the EEPROM and firmware). Furthermore, if you use any
+patches, utilities, or code with the Intel wireless LAN adapters that
+have been manipulated by an unauthorized party (i.e., patches,
+utilities, or code (including open source code modifications) which have
+not been validated by Intel), (i) you will be solely responsible for
+ensuring the regulatory compliance of the products, (ii) Intel will bear
+no liability, under any theory of liability for any issues associated
+with the modified products, including without limitation, claims under
+the warranty and/or issues arising from regulatory non-compliance, and
+(iii) Intel will not provide or be required to assist in providing
+support to any third parties for such modified products.  
+
+Note: Many regulatory agencies consider Wireless LAN adapters to be
+modules, and accordingly, condition system-level regulatory approval
+upon receipt and review of test data documenting that the antennas and
+system configuration do not cause the EMC and radio operation to be
+non-compliant.
+
+The drivers available for download from SourceForge are provided as a 
+part of a development project.  Conformance to local regulatory 
+requirements is the responsibility of the individual developer.  As 
+such, if you are interested in deploying or shipping a driver as part of 
+solution intended to be used for purposes other than development, please 
+obtain a tested driver from Intel Customer Support at:
+
+http://support.intel.com/support/notebook/sb/CS-006408.htm
 
 
 1.   Introduction
@@ -45,7 +101,7 @@
 
 1.1. Overview of Features
 -----------------------------------------------
-The current release (1.0.0) supports the following features:
+The current release (1.0.8) supports the following features:
 
 + BSS mode (Infrastructure, Managed)
 + IBSS mode (Ad-Hoc)
@@ -56,17 +112,27 @@
 + Full A rate support (2915 only)
 + Transmit power control
 + S state support (ACPI suspend/resume)
+
+The following features are currently enabled, but not officially
+supported:
+
++ WPA
 + long/short preamble support
++ Monitor mode (aka RFMon)
+
+The distinction between officially supported and enabled is a reflection 
+on the amount of validation and interoperability testing that has been
+performed on a given feature. 
 
 
 
 1.2. Command Line Parameters
 -----------------------------------------------
 
-Like many modules used in the Linux kernel, the Intel(R) PRO/Wireless 
-2915ABG Driver for Linux allows certain configuration options to be 
-provided as module parameters.  The most common way to specify a module 
-parameter is via the command line.  
+Like many modules used in the Linux kernel, the Intel(R) PRO/Wireless
+2915ABG Driver for Linux allows configuration options to be provided 
+as module parameters.  The most common way to specify a module parameter 
+is via the command line.  
 
 The general form is:
 
@@ -96,14 +162,18 @@
 
   debug
 	If using a debug build, this is used to control the amount of debug
-	info is logged.  See the 'dval' and 'load' script for more info on
-	how to use this (the dval and load scripts are provided as part 
+	info is logged.  See the 'dvals' and 'load' script for more info on
+	how to use this (the dvals and load scripts are provided as part 
 	of the ipw2200 development snapshot releases available from the 
 	SourceForge project at http://ipw2200.sf.net)
+  
+  led
+	Can be used to turn on experimental LED code.
+	0 = Off, 1 = On.  Default is 0.
 
   mode
 	Can be used to set the default mode of the adapter.  
-	0 = Managed, 1 = Ad-Hoc
+	0 = Managed, 1 = Ad-Hoc, 2 = Monitor
 
 
 1.3. Wireless Extension Private Methods
@@ -164,8 +234,8 @@
 -----------------------------------------------
 
 The Linux kernel provides a pseudo file system that can be used to 
-access various components of the operating system.  The Intel(R) 
-PRO/Wireless 2915ABG Driver for Linux exposes several configuration 
+access various components of the operating system.  The Intel(R)
+PRO/Wireless 2915ABG Driver for Linux exposes several configuration
 parameters through this mechanism.
 
 An entry in the sysfs can support reading and/or writing.  You can 
@@ -184,13 +254,13 @@
 
 Where $VALUE would be a number in the case of this sysfs entry.  The 
 input to sysfs files does not have to be a number.  For example, the 
-firmware loader used by hotplug utilizes sysfs entries for transferring 
+firmware loader used by hotplug utilizes sysfs entries for transfering 
 the firmware image from user space into the driver.
 
 The Intel(R) PRO/Wireless 2915ABG Driver for Linux exposes sysfs entries 
-at two levels -- driver level, which apply to all instances of the 
-driver (in the event that there are more than one device installed) and 
-device level, which applies only to the single specific instance.
+at two levels -- driver level, which apply to all instances of the driver 
+(in the event that there are more than one device installed) and device 
+level, which applies only to the single specific instance.
 
 
 1.4.1 Driver Level Sysfs Helper Files
@@ -203,6 +273,7 @@
 	This controls the same global as the 'debug' module parameter
 
 
+
 1.4.2 Device Level Sysfs Helper Files
 -----------------------------------------------
 
@@ -213,7 +284,7 @@
 For example:
 	/sys/bus/pci/drivers/ipw2200/0000:02:01.0
 
-For the device level files, see /sys/bus/pci/[drivers/ipw2200:
+For the device level files, see /sys/bus/pci/drivers/ipw2200:
 
   rf_kill
 	read - 
@@ -231,8 +302,59 @@
   ucode 
 	read-only access to the ucode version number
 
+  led
+	read -
+	0 = LED code disabled
+	1 = LED code enabled
+	write -
+	0 = Disable LED code
+	1 = Enable LED code
 
-2.   About the Version Numbers
+	NOTE: The LED code has been reported to hang some systems when 
+	running ifconfig and is therefore disabled by default.
+
+
+2.   Ad-Hoc Networking
+-----------------------------------------------
+
+When using a device in an Ad-Hoc network, it is useful to understand the 
+sequence and requirements for the driver to be able to create, join, or 
+merge networks.
+
+The following attempts to provide enough information so that you can 
+have a consistent experience while using the driver as a member of an 
+Ad-Hoc network.
+
+2.1. Joining an Ad-Hoc Network
+-----------------------------------------------
+
+The easiest way to get onto an Ad-Hoc network is to join one that 
+already exists.
+
+2.2. Creating an Ad-Hoc Network
+-----------------------------------------------
+
+An Ad-Hoc networks is created using the syntax of the Wireless tool.
+
+For Example:
+iwconfig eth1 mode ad-hoc essid testing channel 2
+
+2.3. Merging Ad-Hoc Networks
+-----------------------------------------------
+
+
+3.  Interaction with Wireless Tools
+-----------------------------------------------
+
+3.1 iwconfig mode
+-----------------------------------------------
+
+When configuring the mode of the adapter, all run-time configured parameters
+are reset to the value used when the module was loaded.  This includes
+channels, rates, ESSID, etc.
+
+
+4.   About the Version Numbers
 -----------------------------------------------
 
 Due to the nature of open source development projects, there are 
@@ -259,12 +381,23 @@
 The major version number will be incremented when significant changes
 are made to the driver.  Currently, there are no major changes planned.
 
+5.  Firmware installation
+----------------------------------------------
 
-3.  Support
+The driver requires a firmware image, download it and extract the
+files under /lib/firmware (or wherever your hotplug's firmware.agent
+will look for firmware files)
+
+The firmware can be downloaded from the following URL:
+
+    http://ipw2200.sf.net/
+
+
+6.  Support
 -----------------------------------------------
 
-For installation support of the 1.0.0 version, you can contact 
-http://supportmail.intel.com, or you can use the open source project 
+For direct support of the 1.0.0 version, you can contact 
+http://supportmail.intel.com, or you can use the open source project
 support.
 
 For general information and support, go to:
@@ -272,7 +405,7 @@
     http://ipw2200.sf.net/
 
 
-4.  License
+7.  License
 -----------------------------------------------
 
   Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
@@ -297,4 +430,3 @@
   James P. Ketrenos <ipw2100-admin@linux.intel.com>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
-
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
new file mode 100644
index 0000000..c45daab
--- /dev/null
+++ b/Documentation/networking/dccp.txt
@@ -0,0 +1,56 @@
+DCCP protocol
+============
+
+Last updated: 10 November 2005
+
+Contents
+========
+
+- Introduction
+- Missing features
+- Socket options
+- Notes
+
+Introduction
+============
+
+Datagram Congestion Control Protocol (DCCP) is an unreliable, connection
+based protocol designed to solve issues present in UDP and TCP particularly
+for real time and multimedia traffic.
+
+It has a base protocol and pluggable congestion control IDs (CCIDs).
+
+It is at draft RFC status and the homepage for DCCP as a protocol is at:
+	http://www.icir.org/kohler/dcp/
+
+Missing features
+================
+
+The DCCP implementation does not currently have all the features that are in
+the draft RFC.
+
+In particular the following are missing:
+- CCID2 support
+- feature negotiation
+
+When testing against other implementations it appears that elapsed time
+options are not coded compliant to the specification.
+
+Socket options
+==============
+
+DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
+calculations.
+
+DCCP_SOCKOPT_SERVICE sets the service. This is compulsory as per the
+specification. If you don't set it you will get EPROTO.
+
+Notes
+=====
+
+SELinux does not yet have support for DCCP. You will need to turn it off or
+else you will get EACCES.
+
+DCCP does not travel through NAT successfully at present. This is because
+the checksum covers the psuedo-header as per TCP and UDP. It should be
+relatively trivial to add Linux NAT support for DCCP.
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 65895bb..ebc09a1 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -78,6 +78,11 @@
 
 TCP variables: 
 
+tcp_abc - INTEGER
+	Controls Appropriate Byte Count defined in RFC3465. If set to
+	0 then does congestion avoid once per ack. 1 is conservative
+	value, and 2 is more agressive.
+
 tcp_syn_retries - INTEGER
 	Number of times initial SYNs for an active TCP connection attempt
 	will be retransmitted. Should not be higher than 255. Default value
diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
index adbfe62..844c03f 100644
--- a/Documentation/s390/Debugging390.txt
+++ b/Documentation/s390/Debugging390.txt
@@ -871,7 +871,7 @@
 
 
 
-extern inline void spin_lock(spinlock_t *lp)
+static inline void spin_lock(spinlock_t *lp)
 {
       a0:       18 34           lr      %r3,%r4
       a2:       a7 3a 03 bc     ahi     %r3,956
diff --git a/Documentation/sched-arch.txt b/Documentation/sched-arch.txt
new file mode 100644
index 0000000..941615a
--- /dev/null
+++ b/Documentation/sched-arch.txt
@@ -0,0 +1,89 @@
+	CPU Scheduler implementation hints for architecture specific code
+
+	Nick Piggin, 2005
+
+Context switch
+==============
+1. Runqueue locking
+By default, the switch_to arch function is called with the runqueue
+locked. This is usually not a problem unless switch_to may need to
+take the runqueue lock. This is usually due to a wake up operation in
+the context switch. See include/asm-ia64/system.h for an example.
+
+To request the scheduler call switch_to with the runqueue unlocked,
+you must `#define __ARCH_WANT_UNLOCKED_CTXSW` in a header file
+(typically the one where switch_to is defined).
+
+Unlocked context switches introduce only a very minor performance
+penalty to the core scheduler implementation in the CONFIG_SMP case.
+
+2. Interrupt status
+By default, the switch_to arch function is called with interrupts
+disabled. Interrupts may be enabled over the call if it is likely to
+introduce a significant interrupt latency by adding the line
+`#define __ARCH_WANT_INTERRUPTS_ON_CTXSW` in the same place as for
+unlocked context switches. This define also implies
+`__ARCH_WANT_UNLOCKED_CTXSW`. See include/asm-arm/system.h for an
+example.
+
+
+CPU idle
+========
+Your cpu_idle routines need to obey the following rules:
+
+1. Preempt should now disabled over idle routines. Should only
+   be enabled to call schedule() then disabled again.
+
+2. need_resched/TIF_NEED_RESCHED is only ever set, and will never
+   be cleared until the running task has called schedule(). Idle
+   threads need only ever query need_resched, and may never set or
+   clear it.
+
+3. When cpu_idle finds (need_resched() == 'true'), it should call
+   schedule(). It should not call schedule() otherwise.
+
+4. The only time interrupts need to be disabled when checking
+   need_resched is if we are about to sleep the processor until
+   the next interrupt (this doesn't provide any protection of
+   need_resched, it prevents losing an interrupt).
+
+	4a. Common problem with this type of sleep appears to be:
+	        local_irq_disable();
+	        if (!need_resched()) {
+	                local_irq_enable();
+	                *** resched interrupt arrives here ***
+	                __asm__("sleep until next interrupt");
+	        }
+
+5. TIF_POLLING_NRFLAG can be set by idle routines that do not
+   need an interrupt to wake them up when need_resched goes high.
+   In other words, they must be periodically polling need_resched,
+   although it may be reasonable to do some background work or enter
+   a low CPU priority.
+
+   	5a. If TIF_POLLING_NRFLAG is set, and we do decide to enter
+	    an interrupt sleep, it needs to be cleared then a memory
+	    barrier issued (followed by a test of need_resched with
+	    interrupts disabled, as explained in 3).
+
+arch/i386/kernel/process.c has examples of both polling and
+sleeping idle functions.
+
+
+Possible arch/ problems
+=======================
+
+Possible arch problems I found (and either tried to fix or didn't):
+
+h8300 - Is such sleeping racy vs interrupts? (See #4a).
+        The H8/300 manual I found indicates yes, however disabling IRQs
+        over the sleep mean only NMIs can wake it up, so can't fix easily
+        without doing spin waiting.
+
+ia64 - is safe_halt call racy vs interrupts? (does it sleep?) (See #4a)
+
+sh64 - Is sleeping racy vs interrupts? (See #4a)
+
+sparc - IRQs on at this point(?), change local_irq_save to _disable.
+      - TODO: needs secondary CPUs to disable preempt (See #1)
+
diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX
index fef92eb..e7da8c3 100644
--- a/Documentation/scsi/00-INDEX
+++ b/Documentation/scsi/00-INDEX
@@ -52,8 +52,6 @@
 	- info on driver for IOmega zip drive
 qlogicfas.txt
 	- info on driver for QLogic FASxxx based adapters
-qlogicisp.txt
-	- info on driver for QLogic ISP 1020 based adapters
 scsi-generic.txt
 	- info on the sg driver for generic (non-disk/CD/tape) SCSI devices.
 scsi.txt
diff --git a/Documentation/scsi/qlogicfas.txt b/Documentation/scsi/qlogicfas.txt
index 398f991..c211d82 100644
--- a/Documentation/scsi/qlogicfas.txt
+++ b/Documentation/scsi/qlogicfas.txt
@@ -11,8 +11,7 @@
 	* IQ-PCI-10
 	* IQ-PCI-D
 
-is provided by the qlogicisp.c driver.  Check README.qlogicisp for
-details.
+is provided by the qla1280 driver.
 
 Nor does it support the PCI-Basic, which is supported by the
 'am53c974' driver.
diff --git a/Documentation/scsi/qlogicisp.txt b/Documentation/scsi/qlogicisp.txt
deleted file mode 100644
index 6920f6c7..0000000
--- a/Documentation/scsi/qlogicisp.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-Notes for the QLogic ISP1020 PCI SCSI Driver:
-
-This driver works well in practice, but does not support disconnect/
-reconnect, which makes using it with tape drives impractical.
-
-It should work for most host adaptors with the ISP1020 chip.  The
-QLogic Corporation produces several PCI SCSI adapters which should
-work:
-
-	* IQ-PCI
-	* IQ-PCI-10
-	* IQ-PCI-D
-
-This driver may work with boards containing the ISP1020A or ISP1040A
-chips, but that has not been tested.
-
-This driver will NOT work with:
-
-	* ISA or VL Bus Qlogic cards (they use the 'qlogicfas' driver)
-	* PCI-basic (it uses the 'am53c974' driver)
-
-Much thanks to QLogic's tech support for providing the latest ISP1020
-firmware, and for taking the time to review my code.
-
-Erik Moe
-ehm@cris.com
-
-Revised:
-Michael A. Griffith
-grif@cs.ucr.edu
diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt
index 534a509..331afd7 100644
--- a/Documentation/scsi/scsi_eh.txt
+++ b/Documentation/scsi/scsi_eh.txt
@@ -83,11 +83,11 @@
  The timeout handler is scsi_times_out().  When a timeout occurs, this
 function
 
- 1. invokes optional hostt->eh_timedout() callback.  Return value can
+ 1. invokes optional hostt->eh_timed_out() callback.  Return value can
     be one of
 
     - EH_HANDLED
-	This indicates that eh_timedout() dealt with the timeout.  The
+	This indicates that eh_timed_out() dealt with the timeout.  The
 	scmd is passed to __scsi_done() and thus linked into per-cpu
 	scsi_done_q.  Normal command completion described in [1-2-1]
 	follows.
@@ -105,7 +105,7 @@
 	command will time out again.
 
     - EH_NOT_HANDLED
-	This is the same as when eh_timedout() callback doesn't exist.
+	This is the same as when eh_timed_out() callback doesn't exist.
 	Step #2 is taken.
 
  2. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the
@@ -142,7 +142,7 @@
  Note that this does not mean lower layers are quiescent.  If a LLDD
 completed a scmd with error status, the LLDD and lower layers are
 assumed to forget about the scmd at that point.  However, if a scmd
-has timed out, unless hostt->eh_timedout() made lower layers forget
+has timed out, unless hostt->eh_timed_out() made lower layers forget
 about the scmd, which currently no LLDD does, the command is still
 active as long as lower layers are concerned and completion could
 occur at any time.  Of course, all such completions are ignored as the
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
index 44df89c..66565d4 100644
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -346,7 +346,7 @@
 struct tags. Both can be still found in the SCSI subsystem, but
 the typedefs have been moved to a single file, scsi_typedefs.h to
 make their future removal easier, for example: 
-"typedef struct scsi_host_template Scsi_Host_Template;"
+"typedef struct scsi_cmnd Scsi_Cmnd;"
 
 Also, most C99 enhancements are encouraged to the extent they are supported
 by the relevant gcc compilers. So C99 style structure and array
@@ -718,7 +718,7 @@
  *
  *      Defined in: drivers/scsi/scsi.c .
  **/
-int scsi_track_queue_full(Scsi_Device *sdev, int depth)
+int scsi_track_queue_full(struct scsi_device *sdev, int depth)
 
 
 /**
diff --git a/Documentation/video4linux/API.html b/Documentation/video4linux/API.html
index 441407b..afbe9ae 100644
--- a/Documentation/video4linux/API.html
+++ b/Documentation/video4linux/API.html
@@ -8,7 +8,7 @@
 </td><td>
 Obsoleted by V4L2 API
 </td></tr><tr><td>
-<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API.html>
+<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API>
 V4L2 API</a>
 </td><td>
 Should be used for new projects
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index ec785f9..2404099 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -1,137 +1,142 @@
-card=0 -  *** UNKNOWN/GENERIC ***
-card=1 - MIRO PCTV
-card=2 - Hauppauge (bt848)
-card=3 - STB, Gateway P/N 6000699 (bt848)
-card=4 - Intel Create and Share PCI/ Smart Video Recorder III
-card=5 - Diamond DTV2000
-card=6 - AVerMedia TVPhone
-card=7 - MATRIX-Vision MV-Delta
-card=8 - Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26
-card=9 - IMS/IXmicro TurboTV
-card=10 - Hauppauge (bt878)
-card=11 - MIRO PCTV pro
-card=12 - ADS Technologies Channel Surfer TV (bt848)
-card=13 - AVerMedia TVCapture 98
-card=14 - Aimslab Video Highway Xtreme (VHX)
-card=15 - Zoltrix TV-Max
-card=16 - Prolink Pixelview PlayTV (bt878)
-card=17 - Leadtek WinView 601
-card=18 - AVEC Intercapture
-card=19 - Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)
-card=20 - CEI Raffles Card
-card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
-card=22 - Askey CPH050/ Phoebe Tv Master + FM
-card=23 - Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878
-card=24 - Askey CPH05X/06X (bt878) [many vendors]
-card=25 - Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar
-card=26 - Hauppauge WinCam newer (bt878)
-card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
-card=28 - Terratec TerraTV+ Version 1.1 (bt878)
-card=29 - Imagenation PXC200
-card=30 - Lifeview FlyVideo 98 LR50
-card=31 - Formac iProTV, Formac ProTV I (bt848)
-card=32 - Intel Create and Share PCI/ Smart Video Recorder III
-card=33 - Terratec TerraTValue Version Bt878
-card=34 - Leadtek WinFast 2000/ WinFast 2000 XP
-card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II
-card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner
-card=37 - Prolink PixelView PlayTV pro
-card=38 - Askey CPH06X TView99
-card=39 - Pinnacle PCTV Studio/Rave
-card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100
-card=41 - AVerMedia TVPhone 98
-card=42 - ProVideo PV951
-card=43 - Little OnAir TV
-card=44 - Sigma TVII-FM
-card=45 - MATRIX-Vision MV-Delta 2
-card=46 - Zoltrix Genie TV/FM
-card=47 - Terratec TV/Radio+
-card=48 - Askey CPH03x/ Dynalink Magic TView
-card=49 - IODATA GV-BCTV3/PCI
-card=50 - Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP
-card=51 - Eagle Wireless Capricorn2 (bt878A)
-card=52 - Pinnacle PCTV Studio Pro
-card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS
-card=54 - Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]
-card=55 - Askey CPH031/ BESTBUY Easy TV
-card=56 - Lifeview FlyVideo 98FM LR50
-card=57 - GrandTec 'Grand Video Capture' (Bt848)
-card=58 - Askey CPH060/ Phoebe TV Master Only (No FM)
-card=59 - Askey CPH03x TV Capturer
-card=60 - Modular Technology MM100PCTV
-card=61 - AG Electronics GMV1
-card=62 - Askey CPH061/ BESTBUY Easy TV (bt878)
-card=63 - ATI TV-Wonder
-card=64 - ATI TV-Wonder VE
-card=65 - Lifeview FlyVideo 2000S LR90
-card=66 - Terratec TValueRadio
-card=67 - IODATA GV-BCTV4/PCI
-card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)
-card=69 - Active Imaging AIMMS
-card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
-card=71 - Lifeview FlyVideo 98EZ (capture only) LR51
-card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
-card=73 - Sensoray 311
-card=74 - RemoteVision MX (RV605)
-card=75 - Powercolor MTV878/ MTV878R/ MTV878F
-card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)
-card=77 - GrandTec Multi Capture Card (Bt878)
-card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF
-card=79 - DSP Design TCVIDEO
-card=80 - Hauppauge WinTV PVR
-card=81 - IODATA GV-BCTV5/PCI
-card=82 - Osprey 100/150 (878)
-card=83 - Osprey 100/150 (848)
-card=84 - Osprey 101 (848)
-card=85 - Osprey 101/151
-card=86 - Osprey 101/151 w/ svid
-card=87 - Osprey 200/201/250/251
-card=88 - Osprey 200/250
-card=89 - Osprey 210/220
-card=90 - Osprey 500
-card=91 - Osprey 540
-card=92 - Osprey 2000
-card=93 - IDS Eagle
-card=94 - Pinnacle PCTV Sat
-card=95 - Formac ProTV II (bt878)
-card=96 - MachTV
-card=97 - Euresys Picolo
-card=98 - ProVideo PV150
-card=99 - AD-TVK503
-card=100 - Hercules Smart TV Stereo
-card=101 - Pace TV & Radio Card
-card=102 - IVC-200
-card=103 - Grand X-Guard / Trust 814PCI
-card=104 - Nebula Electronics DigiTV
-card=105 - ProVideo PV143
-card=106 - PHYTEC VD-009-X1 MiniDIN (bt878)
-card=107 - PHYTEC VD-009-X1 Combi (bt878)
-card=108 - PHYTEC VD-009 MiniDIN (bt878)
-card=109 - PHYTEC VD-009 Combi (bt878)
-card=110 - IVC-100
-card=111 - IVC-120G
-card=112 - pcHDTV HD-2000 TV
-card=113 - Twinhan DST + clones
-card=114 - Winfast VC100
-card=115 - Teppro TEV-560/InterVision IV-560
-card=116 - SIMUS GVC1100
-card=117 - NGS NGSTV+
-card=118 - LMLBT4
-card=119 - Tekram M205 PRO
-card=120 - Conceptronic CONTVFMi
-card=121 - Euresys Picolo Tetra
-card=122 - Spirit TV Tuner
-card=123 - AVerMedia AVerTV DVB-T 771
-card=124 - AverMedia AverTV DVB-T 761
-card=125 - MATRIX Vision Sigma-SQ
-card=126 - MATRIX Vision Sigma-SLC
-card=127 - APAC Viewcomp 878(AMAX)
-card=128 - DViCO FusionHDTV DVB-T Lite
-card=129 - V-Gear MyVCD
-card=130 - Super TV Tuner
-card=131 - Tibet Systems 'Progress DVR' CS16
-card=132 - Kodicom 4400R (master)
-card=133 - Kodicom 4400R (slave)
-card=134 - Adlink RTV24
-card=135 - DViCO FusionHDTV 5 Lite
-card=136 - Acorp Y878F
+  0 ->  *** UNKNOWN/GENERIC ***
+  1 -> MIRO PCTV
+  2 -> Hauppauge (bt848)
+  3 -> STB, Gateway P/N 6000699 (bt848)
+  4 -> Intel Create and Share PCI/ Smart Video Recorder III
+  5 -> Diamond DTV2000
+  6 -> AVerMedia TVPhone
+  7 -> MATRIX-Vision MV-Delta
+  8 -> Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26
+  9 -> IMS/IXmicro TurboTV
+ 10 -> Hauppauge (bt878)                                   [0070:13eb,0070:3900,2636:10b4]
+ 11 -> MIRO PCTV pro
+ 12 -> ADS Technologies Channel Surfer TV (bt848)
+ 13 -> AVerMedia TVCapture 98                              [1461:0002,1461:0004,1461:0300]
+ 14 -> Aimslab Video Highway Xtreme (VHX)
+ 15 -> Zoltrix TV-Max                                      [a1a0:a0fc]
+ 16 -> Prolink Pixelview PlayTV (bt878)
+ 17 -> Leadtek WinView 601
+ 18 -> AVEC Intercapture
+ 19 -> Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)
+ 20 -> CEI Raffles Card
+ 21 -> Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
+ 22 -> Askey CPH050/ Phoebe Tv Master + FM                 [14ff:3002]
+ 23 -> Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878 [14c7:0101]
+ 24 -> Askey CPH05X/06X (bt878) [many vendors]             [144f:3002,144f:3005,144f:5000,14ff:3000]
+ 25 -> Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar
+ 26 -> Hauppauge WinCam newer (bt878)
+ 27 -> Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
+ 28 -> Terratec TerraTV+ Version 1.1 (bt878)               [153b:1127,1852:1852]
+ 29 -> Imagenation PXC200                                  [1295:200a]
+ 30 -> Lifeview FlyVideo 98 LR50                           [1f7f:1850]
+ 31 -> Formac iProTV, Formac ProTV I (bt848)
+ 32 -> Intel Create and Share PCI/ Smart Video Recorder III
+ 33 -> Terratec TerraTValue Version Bt878                  [153b:1117,153b:1118,153b:1119,153b:111a,153b:1134,153b:5018]
+ 34 -> Leadtek WinFast 2000/ WinFast 2000 XP               [107d:6606,107d:6609,6606:217d,f6ff:fff6]
+ 35 -> Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II [1851:1850,1851:a050]
+ 36 -> Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner [1852:1852]
+ 37 -> Prolink PixelView PlayTV pro
+ 38 -> Askey CPH06X TView99                                [144f:3000,144f:a005,a04f:a0fc]
+ 39 -> Pinnacle PCTV Studio/Rave                           [11bd:0012,bd11:1200,bd11:ff00,11bd:ff12]
+ 40 -> STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100 [10b4:2636,10b4:2645,121a:3060]
+ 41 -> AVerMedia TVPhone 98                                [1461:0001,1461:0003]
+ 42 -> ProVideo PV951                                      [aa0c:146c]
+ 43 -> Little OnAir TV
+ 44 -> Sigma TVII-FM
+ 45 -> MATRIX-Vision MV-Delta 2
+ 46 -> Zoltrix Genie TV/FM                                 [15b0:4000,15b0:400a,15b0:400d,15b0:4010,15b0:4016]
+ 47 -> Terratec TV/Radio+                                  [153b:1123]
+ 48 -> Askey CPH03x/ Dynalink Magic TView
+ 49 -> IODATA GV-BCTV3/PCI                                 [10fc:4020]
+ 50 -> Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP
+ 51 -> Eagle Wireless Capricorn2 (bt878A)
+ 52 -> Pinnacle PCTV Studio Pro
+ 53 -> Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS
+ 54 -> Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]
+ 55 -> Askey CPH031/ BESTBUY Easy TV
+ 56 -> Lifeview FlyVideo 98FM LR50                         [a051:41a0]
+ 57 -> GrandTec 'Grand Video Capture' (Bt848)              [4344:4142]
+ 58 -> Askey CPH060/ Phoebe TV Master Only (No FM)
+ 59 -> Askey CPH03x TV Capturer
+ 60 -> Modular Technology MM100PCTV
+ 61 -> AG Electronics GMV1                                 [15cb:0101]
+ 62 -> Askey CPH061/ BESTBUY Easy TV (bt878)
+ 63 -> ATI TV-Wonder                                       [1002:0001]
+ 64 -> ATI TV-Wonder VE                                    [1002:0003]
+ 65 -> Lifeview FlyVideo 2000S LR90
+ 66 -> Terratec TValueRadio                                [153b:1135,153b:ff3b]
+ 67 -> IODATA GV-BCTV4/PCI                                 [10fc:4050]
+ 68 -> 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)         [121a:3000,10b4:2637]
+ 69 -> Active Imaging AIMMS
+ 70 -> Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
+ 71 -> Lifeview FlyVideo 98EZ (capture only) LR51          [1851:1851]
+ 72 -> Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM) [1554:4011]
+ 73 -> Sensoray 311                                        [6000:0311]
+ 74 -> RemoteVision MX (RV605)
+ 75 -> Powercolor MTV878/ MTV878R/ MTV878F
+ 76 -> Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP) [0e11:0079]
+ 77 -> GrandTec Multi Capture Card (Bt878)
+ 78 -> Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF   [0a01:17de]
+ 79 -> DSP Design TCVIDEO
+ 80 -> Hauppauge WinTV PVR                                 [0070:4500]
+ 81 -> IODATA GV-BCTV5/PCI                                 [10fc:4070,10fc:d018]
+ 82 -> Osprey 100/150 (878)                                [0070:ff00]
+ 83 -> Osprey 100/150 (848)
+ 84 -> Osprey 101 (848)
+ 85 -> Osprey 101/151
+ 86 -> Osprey 101/151 w/ svid
+ 87 -> Osprey 200/201/250/251
+ 88 -> Osprey 200/250                                      [0070:ff01]
+ 89 -> Osprey 210/220
+ 90 -> Osprey 500                                          [0070:ff02]
+ 91 -> Osprey 540                                          [0070:ff04]
+ 92 -> Osprey 2000                                         [0070:ff03]
+ 93 -> IDS Eagle
+ 94 -> Pinnacle PCTV Sat                                   [11bd:001c]
+ 95 -> Formac ProTV II (bt878)
+ 96 -> MachTV
+ 97 -> Euresys Picolo
+ 98 -> ProVideo PV150                                      [aa00:1460,aa01:1461,aa02:1462,aa03:1463,aa04:1464,aa05:1465,aa06:1466,aa07:1467]
+ 99 -> AD-TVK503
+100 -> Hercules Smart TV Stereo
+101 -> Pace TV & Radio Card
+102 -> IVC-200                                             [0000:a155,0001:a155,0002:a155,0003:a155,0100:a155,0101:a155,0102:a155,0103:a155]
+103 -> Grand X-Guard / Trust 814PCI                        [0304:0102]
+104 -> Nebula Electronics DigiTV                           [0071:0101]
+105 -> ProVideo PV143                                      [aa00:1430,aa00:1431,aa00:1432,aa00:1433,aa03:1433]
+106 -> PHYTEC VD-009-X1 MiniDIN (bt878)
+107 -> PHYTEC VD-009-X1 Combi (bt878)
+108 -> PHYTEC VD-009 MiniDIN (bt878)
+109 -> PHYTEC VD-009 Combi (bt878)
+110 -> IVC-100                                             [ff00:a132]
+111 -> IVC-120G                                            [ff00:a182,ff01:a182,ff02:a182,ff03:a182,ff04:a182,ff05:a182,ff06:a182,ff07:a182,ff08:a182,ff09:a182,ff0a:a182,ff0b:a182,ff0c:a182,ff0d:a182,ff0e:a182,ff0f:a182]
+112 -> pcHDTV HD-2000 TV                                   [7063:2000]
+113 -> Twinhan DST + clones                                [11bd:0026,1822:0001,270f:fc00]
+114 -> Winfast VC100                                       [107d:6607]
+115 -> Teppro TEV-560/InterVision IV-560
+116 -> SIMUS GVC1100                                       [aa6a:82b2]
+117 -> NGS NGSTV+
+118 -> LMLBT4
+119 -> Tekram M205 PRO
+120 -> Conceptronic CONTVFMi
+121 -> Euresys Picolo Tetra                                [1805:0105,1805:0106,1805:0107,1805:0108]
+122 -> Spirit TV Tuner
+123 -> AVerMedia AVerTV DVB-T 771                          [1461:0771]
+124 -> AverMedia AverTV DVB-T 761                          [1461:0761]
+125 -> MATRIX Vision Sigma-SQ
+126 -> MATRIX Vision Sigma-SLC
+127 -> APAC Viewcomp 878(AMAX)
+128 -> DViCO FusionHDTV DVB-T Lite                         [18ac:db10]
+129 -> V-Gear MyVCD
+130 -> Super TV Tuner
+131 -> Tibet Systems 'Progress DVR' CS16
+132 -> Kodicom 4400R (master)
+133 -> Kodicom 4400R (slave)
+134 -> Adlink RTV24
+135 -> DViCO FusionHDTV 5 Lite                             [18ac:d500]
+136 -> Acorp Y878F                                         [9511:1540]
+137 -> Conceptronic CTVFMi v2
+138 -> Prolink Pixelview PV-BT878P+ (Rev.2E)
+139 -> Prolink PixelView PlayTV MPEG2 PV-M4900
+140 -> Osprey 440                                          [0070:ff07]
+141 -> Asound Skyeye PCTV
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 03deb07..a1017d1 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -1,32 +1,37 @@
-card=0 - UNKNOWN/GENERIC
-card=1 - Hauppauge WinTV 34xxx models
-card=2 - GDI Black Gold
-card=3 - PixelView
-card=4 - ATI TV Wonder Pro
-card=5 - Leadtek Winfast 2000XP Expert
-card=6 - AverTV Studio 303 (M126)
-card=7 - MSI TV-@nywhere Master
-card=8 - Leadtek Winfast DV2000
-card=9 - Leadtek PVR 2000
-card=10 - IODATA GV-VCP3/PCI
-card=11 - Prolink PlayTV PVR
-card=12 - ASUS PVR-416
-card=13 - MSI TV-@nywhere
-card=14 - KWorld/VStream XPert DVB-T
-card=15 - DViCO FusionHDTV DVB-T1
-card=16 - KWorld LTV883RF
-card=17 - DViCO FusionHDTV 3 Gold-Q
-card=18 - Hauppauge Nova-T DVB-T
-card=19 - Conexant DVB-T reference design
-card=20 - Provideo PV259
-card=21 - DViCO FusionHDTV DVB-T Plus
-card=22 - digitalnow DNTV Live! DVB-T
-card=23 - pcHDTV HD3000 HDTV
-card=24 - Hauppauge WinTV 28xxx (Roslyn) models
-card=25 - Digital-Logic MICROSPACE Entertainment Center (MEC)
-card=26 - IODATA GV/BCTV7E
-card=27 - PixelView PlayTV Ultra Pro (Stereo)
-card=28 - DViCO FusionHDTV 3 Gold-T
-card=29 - ADS Tech Instant TV DVB-T PCI
-card=30 - TerraTec Cinergy 1400 DVB-T
-card=31 - DViCO FusionHDTV 5 Gold
+  0 -> UNKNOWN/GENERIC
+  1 -> Hauppauge WinTV 34xxx models                        [0070:3400,0070:3401]
+  2 -> GDI Black Gold                                      [14c7:0106,14c7:0107]
+  3 -> PixelView                                           [1554:4811]
+  4 -> ATI TV Wonder Pro                                   [1002:00f8]
+  5 -> Leadtek Winfast 2000XP Expert                       [107d:6611,107d:6613]
+  6 -> AverTV Studio 303 (M126)                            [1461:000b]
+  7 -> MSI TV-@nywhere Master                              [1462:8606]
+  8 -> Leadtek Winfast DV2000                              [107d:6620]
+  9 -> Leadtek PVR 2000                                    [107d:663b,107d:663C]
+ 10 -> IODATA GV-VCP3/PCI                                  [10fc:d003]
+ 11 -> Prolink PlayTV PVR
+ 12 -> ASUS PVR-416                                        [1043:4823]
+ 13 -> MSI TV-@nywhere
+ 14 -> KWorld/VStream XPert DVB-T                          [17de:08a6]
+ 15 -> DViCO FusionHDTV DVB-T1                             [18ac:db00]
+ 16 -> KWorld LTV883RF
+ 17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810]
+ 18 -> Hauppauge Nova-T DVB-T                              [0070:9002]
+ 19 -> Conexant DVB-T reference design                     [14f1:0187]
+ 20 -> Provideo PV259                                      [1540:2580]
+ 21 -> DViCO FusionHDTV DVB-T Plus                         [18ac:db10]
+ 22 -> pcHDTV HD3000 HDTV                                  [7063:3000]
+ 23 -> digitalnow DNTV Live! DVB-T                         [17de:a8a6]
+ 24 -> Hauppauge WinTV 28xxx (Roslyn) models               [0070:2801]
+ 25 -> Digital-Logic MICROSPACE Entertainment Center (MEC) [14f1:0342]
+ 26 -> IODATA GV/BCTV7E                                    [10fc:d035]
+ 27 -> PixelView PlayTV Ultra Pro (Stereo)
+ 28 -> DViCO FusionHDTV 3 Gold-T                           [18ac:d820]
+ 29 -> ADS Tech Instant TV DVB-T PCI                       [1421:0334]
+ 30 -> TerraTec Cinergy 1400 DVB-T                         [153b:1166]
+ 31 -> DViCO FusionHDTV 5 Gold                             [18ac:d500]
+ 32 -> AverMedia UltraTV Media Center PCI 550              [1461:8011]
+ 33 -> Kworld V-Stream Xpert DVD
+ 34 -> ATI HDTV Wonder                                     [1002:a101]
+ 35 -> WinFast DTV1000-T                                   [107d:665f]
+ 36 -> AVerTV 303 (M126)                                   [1461:000a]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
new file mode 100644
index 0000000..a0c7cad
--- /dev/null
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -0,0 +1,10 @@
+  0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
+  1 -> Unknown EM2820/2840 video grabber        (em2820/em2840)
+  2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
+  3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
+  4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200]
+  5 -> MSI VOX USB 2.0                          (em2820/em2840) [eb1a:2820]
+  6 -> Terratec Cinergy 200 USB                 (em2800)
+  7 -> Leadtek Winfast USB II                   (em2800)
+  8 -> Kworld USB2800                           (em2800)
+  9 -> Pinnacle Dazzle DVC 90                   (em2820/em2840) [2304:0207]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index dc57225..57c9d63 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -6,10 +6,10 @@
   5 -> SKNet Monster TV                         [1131:4e85]
   6 -> Tevion MD 9717
   7 -> KNC One TV-Station RDS / Typhoon TV Tuner RDS [1131:fe01,1894:fe01]
-  8 -> Terratec Cinergy 400 TV                  [153B:1142]
+  8 -> Terratec Cinergy 400 TV                  [153b:1142]
   9 -> Medion 5044
  10 -> Kworld/KuroutoShikou SAA7130-TVPCI
- 11 -> Terratec Cinergy 600 TV                  [153B:1143]
+ 11 -> Terratec Cinergy 600 TV                  [153b:1143]
  12 -> Medion 7134                              [16be:0003]
  13 -> Typhoon TV+Radio 90031
  14 -> ELSA EX-VISION 300TV                     [1048:226b]
@@ -36,8 +36,8 @@
  35 -> AverMedia AverTV Studio 305              [1461:2115]
  36 -> UPMOST PURPLE TV                         [12ab:0800]
  37 -> Items MuchTV Plus / IT-005
- 38 -> Terratec Cinergy 200 TV                  [153B:1152]
- 39 -> LifeView FlyTV Platinum Mini             [5168:0212]
+ 38 -> Terratec Cinergy 200 TV                  [153b:1152]
+ 39 -> LifeView FlyTV Platinum Mini             [5168:0212,4e42:0212]
  40 -> Compro VideoMate TV PVR/FM               [185b:c100]
  41 -> Compro VideoMate TV Gold+                [185b:c100]
  42 -> Sabrent SBT-TVFM (saa7130)
@@ -46,7 +46,7 @@
  45 -> Avermedia AVerTV Studio 307              [1461:9715]
  46 -> AVerMedia Cardbus TV/Radio (E500)        [1461:d6ee]
  47 -> Terratec Cinergy 400 mobile              [153b:1162]
- 48 -> Terratec Cinergy 600 TV MK3              [153B:1158]
+ 48 -> Terratec Cinergy 600 TV MK3              [153b:1158]
  49 -> Compro VideoMate Gold+ Pal               [185b:c200]
  50 -> Pinnacle PCTV 300i DVB-T + PAL           [11bd:002d]
  51 -> ProVideo PV952                           [1540:9524]
@@ -56,12 +56,27 @@
  55 -> LifeView FlyDVB-T DUO                    [5168:0502,5168:0306]
  56 -> Avermedia AVerTV 307                     [1461:a70a]
  57 -> Avermedia AVerTV GO 007 FM               [1461:f31f]
- 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0370]
+ 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0370,1421:1370]
  59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
  60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502]
  61 -> Philips TOUGH DVB-T reference design     [1131:2004]
  62 -> Compro VideoMate TV Gold+II
  63 -> Kworld Xpert TV PVR7134
- 64 -> FlyTV mini Asus Digimatrix               [1043:0210,1043:0210]
+ 64 -> FlyTV mini Asus Digimatrix               [1043:0210]
  65 -> V-Stream Studio TV Terminator
  66 -> Yuan TUN-900 (saa7135)
+ 67 -> Beholder BeholdTV 409 FM                 [0000:4091]
+ 68 -> GoTView 7135 PCI                         [5456:7135]
+ 69 -> Philips EUROPA V3 reference design       [1131:2004]
+ 70 -> Compro Videomate DVB-T300                [185b:c900]
+ 71 -> Compro Videomate DVB-T200                [185b:c901]
+ 72 -> RTD Embedded Technologies VFG7350        [1435:7350]
+ 73 -> RTD Embedded Technologies VFG7330        [1435:7330]
+ 74 -> LifeView FlyTV Platinum Mini2            [14c0:1212]
+ 75 -> AVerMedia AVerTVHD MCE A180              [1461:1044]
+ 76 -> SKNet MonsterTV Mobile                   [1131:4ee9]
+ 77 -> Pinnacle PCTV 110i (saa7133)             [11bd:002e]
+ 78 -> ASUSTeK P7131 Dual                       [1043:4862]
+ 79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
+ 80 -> ASUS Digimatrix TV                       [1043:0210]
+ 81 -> Philips Tiger reference design           [1131:2018]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index f5876be..ec840ca 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -53,7 +53,7 @@
 tuner=52 - Thomson DDT 7610 (ATSC/NTSC)
 tuner=53 - Philips FQ1286
 tuner=54 - tda8290+75
-tuner=55 - LG PAL (TAPE series)
+tuner=55 - TCL 2002MB
 tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
 tuner=57 - Philips FQ1236A MK4
 tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF
@@ -65,3 +65,5 @@
 tuner=64 - LG TDVS-H062F/TUA6034
 tuner=65 - Ymec TVF66T5-B/DFF
 tuner=66 - LG NTSC (TALN mini series)
+tuner=67 - Philips TD1316 Hybrid Tuner
+tuner=68 - Philips TUV1236D ATSC/NTSC dual in
diff --git a/Documentation/video4linux/README.cx88 b/Documentation/video4linux/README.cx88
index 897ab83..06a33a4 100644
--- a/Documentation/video4linux/README.cx88
+++ b/Documentation/video4linux/README.cx88
@@ -17,9 +17,9 @@
 	- The chip specs for the on-chip TV sound decoder are next
 	  to useless :-/
 	- Neverless the builtin TV sound decoder starts working now,
-          at least for PAL-BG.  Other TV norms need other code ...
-          FOR ANY REPORTS ON THIS PLEASE MENTION THE TV NORM YOU ARE
-          USING.
+	  at least for PAL-BG.  Other TV norms need other code ...
+	  FOR ANY REPORTS ON THIS PLEASE MENTION THE TV NORM YOU ARE
+	  USING.
 	- Most tuner chips do provide mono sound, which may or may not
 	  be useable depending on the board design.  With the Hauppauge
 	  cards it works, so there is mono sound available as fallback.
@@ -65,5 +65,5 @@
 
   Gerd
 
--- 
+--
 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
diff --git a/Documentation/video4linux/README.saa7134 b/Documentation/video4linux/README.saa7134
index 1f788e4..b911f08 100644
--- a/Documentation/video4linux/README.saa7134
+++ b/Documentation/video4linux/README.saa7134
@@ -78,5 +78,5 @@
 
   Gerd
 
--- 
+--
 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
diff --git a/Documentation/video4linux/bttv/Cards b/Documentation/video4linux/bttv/Cards
index 8f1941e..d338965 100644
--- a/Documentation/video4linux/bttv/Cards
+++ b/Documentation/video4linux/bttv/Cards
@@ -149,11 +149,11 @@
   2) There is a print on the PCB:
       LR25       = Flyvideo (Zoran ZR36120, SAA7110A)
       LR26 Rev.N = Flyvideo II (Bt848)
-           Rev.O = Flyvideo II (Bt878)
+	   Rev.O = Flyvideo II (Bt878)
       LR37 Rev.C = Flyvideo EZ (Capture only, ZR36120 + SAA7110)
       LR38 Rev.A1= Flyvideo II EZ (Bt848 capture only)
       LR50 Rev.Q = Flyvideo 98 (w/eeprom and PCI subsystem ID)
-           Rev.W = Flyvideo 98 (no eeprom)
+	   Rev.W = Flyvideo 98 (no eeprom)
       LR51 Rev.E = Flyvideo 98 EZ (capture only)
       LR90       = Flyvideo 2000 (Bt878)
 		   Flyvideo 2000S (Bt878) w/Stereo TV (Package incl. LR91 daughterboard)
@@ -163,7 +163,7 @@
       LR136	 = Flyvideo 2100/3100 (Low profile, SAA7130/SAA7134)
       LR137      = Flyvideo DV2000/DV3000 (SAA7130/SAA7134 + IEEE1394)
       LR138 Rev.C= Flyvideo 2000 (SAA7130)
-	        or Flyvideo 3000 (SAA7134) w/Stereo TV
+		or Flyvideo 3000 (SAA7134) w/Stereo TV
 		   These exist in variations w/FM and w/Remote sometimes denoted
 		   by suffixes "FM" and "R".
   3) You have a laptop (miniPCI card):
@@ -197,7 +197,7 @@
   50680 "TV Tuner Pal BG" (blue package)= Pixelview PV-BT878P+ (Rev 9B)
   50681 "TV Tuner PCI Pal I" (variant of 50680)
   50682 "TView TV/FM Tuner Pal BG"       = Flyvideo 98FM (LR50 Rev.Q)
-         Note: The package has a picture of CPH05x (which would be a real TView)
+	 Note: The package has a picture of CPH05x (which would be a real TView)
   50683 "TV Tuner PCI SECAM" (variant of 50680)
   50684 "TV Tuner Pal BG"                = Pixelview 878TV(Rev.3D)
   50686 "TV Tuner"                       = KNC1 TV Station
@@ -418,9 +418,9 @@
 --------------------------
    LT9306/MD9306 = CPH061
    LT9415/MD9415 = LR90 Rev.F or Rev.G
-          MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
-          MD9717 = KNC One (Rev D4, saa7134, FM1216 MK2 tuner)
-          MD5044 = KNC One (Rev D4, saa7134, FM1216ME MK3 tuner)
+	  MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
+	  MD9717 = KNC One (Rev D4, saa7134, FM1216 MK2 tuner)
+	  MD5044 = KNC One (Rev D4, saa7134, FM1216ME MK3 tuner)
 
 Modular Technologies (www.modulartech.com) UK
 ---------------------------------------------
@@ -453,10 +453,10 @@
    Discos ADR PC-Karte ISA (no TV!)
    Discos ADR PC-Karte PCI (probably no TV?)
    Techni-PC-Sat (Sat. analog)
-         Rev 1.2 (zr36120, vpx3220, stv0030, saa5246, BSJE3-494A)
+	 Rev 1.2 (zr36120, vpx3220, stv0030, saa5246, BSJE3-494A)
    Mediafocus I (zr36120/zr36125, drp3510, Sat. analog + ADR Radio)
    Mediafocus II (saa7146, Sat. analog)
-         SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
+	 SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
    SkyStar 1 DVB  (AV7110) = Technotrend Premium
    SkyStar 2 DVB  (B2C2) (=Sky2PC)
 
diff --git a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README
index a72f4c9..7ca2154 100644
--- a/Documentation/video4linux/bttv/README
+++ b/Documentation/video4linux/bttv/README
@@ -42,9 +42,9 @@
 the Subsystem ID in the second line, looks like this:
 
 00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02)
-        Subsystem: Hauppauge computer works Inc. WinTV/GO
-        Flags: bus master, medium devsel, latency 32, IRQ 5
-        Memory at e2000000 (32-bit, prefetchable) [size=4K]
+	Subsystem: Hauppauge computer works Inc. WinTV/GO
+	Flags: bus master, medium devsel, latency 32, IRQ 5
+	Memory at e2000000 (32-bit, prefetchable) [size=4K]
 
 only bt878-based cards can have a subsystem ID (which does not mean
 that every card really has one).  bt848 cards can't have a Subsystem
diff --git a/Documentation/video4linux/bttv/Sound-FAQ b/Documentation/video4linux/bttv/Sound-FAQ
index b8c9c26..1e6328f 100644
--- a/Documentation/video4linux/bttv/Sound-FAQ
+++ b/Documentation/video4linux/bttv/Sound-FAQ
@@ -61,8 +61,8 @@
 struct tvcard
 {
 	[ ... ]
-        u32 gpiomask;
-        u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
+	u32 gpiomask;
+	u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
 };
 
 gpiomask specifies which pins are used to control the audio mux chip.
@@ -126,11 +126,11 @@
 pll             - same as pll= insmod option
 tuner_type      - same as tuner= insmod option
 *_modulename    - hint whenever some card needs this or that audio
-                  module loaded to work properly.
+		  module loaded to work properly.
 has_radio	- whenever this TV card has a radio tuner.
 no_msp34xx	- "1" disables loading of msp3400.o module
-no_tda9875	- "1" disables loading of tda9875.o module 
-needs_tvaudio	- set to "1" to load tvaudio.o module 
+no_tda9875	- "1" disables loading of tda9875.o module
+needs_tvaudio	- set to "1" to load tvaudio.o module
 
 If some config item is specified both from the tvcards array and as
 insmod option, the insmod option takes precedence.
@@ -144,5 +144,5 @@
 
 PS: If you have a new working entry, mail it to me.
 
--- 
+--
 Gerd Knorr <kraxel@bytesex.org>
diff --git a/Documentation/video4linux/bttv/Tuners b/Documentation/video4linux/bttv/Tuners
index d18fbc7..0a371d3 100644
--- a/Documentation/video4linux/bttv/Tuners
+++ b/Documentation/video4linux/bttv/Tuners
@@ -21,7 +21,7 @@
    J= NTSC-Japan
    L= Secam LL
    M= BG+I+DK
-   N= NTSC 
+   N= NTSC
    Q= BG+I+DK+LL
  [89]: ?
  [125]:
@@ -96,7 +96,7 @@
   TADC-H002F: NTSC (L,175/410?; 2-B, C-W+11, W+12-69)
   TADC-M201D: PAL D/K+B/G+I (L,143/425)  (sound control at I2C address 0xc8)
   TADC-T003F: NTSC Taiwan  (L,175/410?; 2-B, C-W+11, W+12-69)
-  Suffix: 
+  Suffix:
     P= Standard phono female socket
     D= IEC female socket
     F= F-connector
diff --git a/Documentation/video4linux/lifeview.txt b/Documentation/video4linux/lifeview.txt
index b07ea79..05f9eb5 100644
--- a/Documentation/video4linux/lifeview.txt
+++ b/Documentation/video4linux/lifeview.txt
@@ -10,33 +10,33 @@
 ------------------------------------------------------------------------------
 
 saa7134:
-                /* LifeView FlyTV Platinum FM (LR214WF) */
-                /* "Peter Missel <peter.missel@onlinehome.de> */
-                .name           = "LifeView FlyTV Platinum FM",
-                /*      GP27    MDT2005 PB4 pin 10 */
-                /*      GP26    MDT2005 PB3 pin 9 */
-                /*      GP25    MDT2005 PB2 pin 8 */
-                /*      GP23    MDT2005 PB1 pin 7 */
-                /*      GP22    MDT2005 PB0 pin 6 */
-                /*      GP21    MDT2005 PB5 pin 11 */
-                /*      GP20    MDT2005 PB6 pin 12 */
-                /*      GP19    MDT2005 PB7 pin 13 */
-                /*      nc      MDT2005 PA3 pin 2 */
-                /*      Remote  MDT2005 PA2 pin 1 */
-                /*      GP18    MDT2005 PA1 pin 18 */
-                /*      nc      MDT2005 PA0 pin 17 strap low */
+		/* LifeView FlyTV Platinum FM (LR214WF) */
+		/* "Peter Missel <peter.missel@onlinehome.de> */
+		.name           = "LifeView FlyTV Platinum FM",
+		/*      GP27    MDT2005 PB4 pin 10 */
+		/*      GP26    MDT2005 PB3 pin 9 */
+		/*      GP25    MDT2005 PB2 pin 8 */
+		/*      GP23    MDT2005 PB1 pin 7 */
+		/*      GP22    MDT2005 PB0 pin 6 */
+		/*      GP21    MDT2005 PB5 pin 11 */
+		/*      GP20    MDT2005 PB6 pin 12 */
+		/*      GP19    MDT2005 PB7 pin 13 */
+		/*      nc      MDT2005 PA3 pin 2 */
+		/*      Remote  MDT2005 PA2 pin 1 */
+		/*      GP18    MDT2005 PA1 pin 18 */
+		/*      nc      MDT2005 PA0 pin 17 strap low */
 
-                /*      GP17    Strap "GP7"=High */
-                /*      GP16    Strap "GP6"=High
-                                0=Radio 1=TV
-                                Drives SA630D ENCH1 and HEF4052 A1 pins
-                                to do FM radio through SIF input */
-                /*      GP15    nc */
-                /*      GP14    nc */
-                /*      GP13    nc */
-                /*      GP12    Strap "GP5" = High */
-                /*      GP11    Strap "GP4" = High */
-                /*      GP10    Strap "GP3" = High */
-                /*      GP09    Strap "GP2" = Low */
-                /*      GP08    Strap "GP1" = Low */
-                /*      GP07.00 nc */
+		/*      GP17    Strap "GP7"=High */
+		/*      GP16    Strap "GP6"=High
+				0=Radio 1=TV
+				Drives SA630D ENCH1 and HEF4052 A1 pins
+				to do FM radio through SIF input */
+		/*      GP15    nc */
+		/*      GP14    nc */
+		/*      GP13    nc */
+		/*      GP12    Strap "GP5" = High */
+		/*      GP11    Strap "GP4" = High */
+		/*      GP10    Strap "GP3" = High */
+		/*      GP09    Strap "GP2" = Low */
+		/*      GP08    Strap "GP1" = Low */
+		/*      GP07.00 nc */
diff --git a/MAINTAINERS b/MAINTAINERS
index 3028d4b..2313de2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -707,7 +707,7 @@
 P:	Arnaldo Carvalho de Melo
 M:	acme@mandriva.com
 L:	dccp@vger.kernel.org
-W:	http://www.wlug.org.nz/DCCP
+W:	http://linux-net.osdl.org/index.php/DCCP
 S:	Maintained
 
 DECnet NETWORK LAYER
@@ -1330,6 +1330,24 @@
 W:	http://sourceforge.net/projects/e1000/
 S:	Supported
 
+INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
+P:	Yi Zhu
+M:	yi.zhu@intel.com
+P:	James Ketrenos
+M:	jketreno@linux.intel.com
+L:	http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
+W:	http://ipw2100.sourceforge.net
+S:	Supported
+
+INTEL PRO/WIRELESS 2915ABG NETWORK CONNECTION SUPPORT
+P:	Yi Zhu
+M:	yi.zhu@intel.com
+P:	James Ketrenos
+M:	jketreno@linux.intel.com
+L:	http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
+W:	http://ipw2200.sourceforge.net
+S:	Supported
+
 IOC3 DRIVER
 P:	Ralf Baechle
 M:	ralf@linux-mips.org
diff --git a/Makefile b/Makefile
index ea96da1..c041a43 100644
--- a/Makefile
+++ b/Makefile
@@ -168,7 +168,8 @@
 
 SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
 				  -e s/arm.*/arm/ -e s/sa110/arm/ \
-				  -e s/s390x/s390/ -e s/parisc64/parisc/ )
+				  -e s/s390x/s390/ -e s/parisc64/parisc/ \
+				  -e s/ppc64/powerpc/ )
 
 # Cross compiling and selecting different set of gcc/bin-utils
 # ---------------------------------------------------------------------------
@@ -347,7 +348,7 @@
 # Needed to be compatible with the O= option
 LINUXINCLUDE    := -Iinclude \
                    $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
-		   -imacros include/linux/autoconf.h
+		   -include include/linux/autoconf.h
 
 CPPFLAGS        := -D__KERNEL__ $(LINUXINCLUDE)
 
@@ -407,7 +408,7 @@
 # of make so .config is not included in this case either (for *config).
 
 no-dot-config-targets := clean mrproper distclean \
-			 cscope TAGS tags help %docs check%
+			 cscope TAGS tags help %docs check% kernelrelease
 
 config-targets := 0
 mixed-targets  := 0
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index eb20c3a..a868261 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -43,21 +43,17 @@
 #include "proto.h"
 #include "pci_impl.h"
 
-void default_idle(void)
-{
-	barrier();
-}
-
 void
 cpu_idle(void)
 {
+	set_thread_flag(TIF_POLLING_NRFLAG);
+
 	while (1) {
-		void (*idle)(void) = default_idle;
 		/* FIXME -- EV6 and LCA45 know how to power down
 		   the CPU.  */
 
 		while (!need_resched())
-			idle();
+			cpu_relax();
 		schedule();
 	}
 }
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 91d5ef3..3df7cbd 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -239,6 +239,8 @@
 
 source "arch/arm/mach-omap1/Kconfig"
 
+source "arch/arm/mach-omap2/Kconfig"
+
 source "arch/arm/mach-s3c2410/Kconfig"
 
 source "arch/arm/mach-lh7a40x/Kconfig"
@@ -356,6 +358,16 @@
 	  Say Y here to experiment with turning CPUs off and on.  CPUs
 	  can be controlled through /sys/devices/system/cpu.
 
+config LOCAL_TIMERS
+	bool "Use local timer interrupts"
+	depends on SMP && REALVIEW_MPCORE
+	default y
+	help
+	  Enable support for local timers on SMP platforms, rather then the
+	  legacy IPI broadcast method.  Local timers allows the system
+	  accounting to be spread across the timer interval, preventing a
+	  "thundering herd" at every timer tick.
+
 config PREEMPT
 	bool "Preemptible Kernel (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 114cda7f..81bd219 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -93,6 +93,7 @@
  machine-$(CONFIG_ARCH_IXP4XX)	   := ixp4xx
  machine-$(CONFIG_ARCH_IXP2000)    := ixp2000
  machine-$(CONFIG_ARCH_OMAP1)	   := omap1
+ machine-$(CONFIG_ARCH_OMAP2)	   := omap2
   incdir-$(CONFIG_ARCH_OMAP)	   := omap
  machine-$(CONFIG_ARCH_S3C2410)	   := s3c2410
  machine-$(CONFIG_ARCH_LH7A40X)	   := lh7a40x
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 50f13ee..5ab9458 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -283,8 +283,14 @@
 	putstr(".");
 }
 
+#ifndef arch_error
+#define arch_error(x)
+#endif
+
 static void error(char *x)
 {
+	arch_error(x);
+
 	putstr("\n\n");
 	putstr(x);
 	putstr("\n\n -- System halted");
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index ad55680..557e52c 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -550,9 +550,9 @@
 	u16	LCM_SPIMD;
 };
 
-static int locomo_suspend(struct device *dev, pm_message_t state)
+static int locomo_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct locomo *lchip = dev_get_drvdata(dev);
+	struct locomo *lchip = platform_get_drvdata(dev);
 	struct locomo_save_data *save;
 	unsigned long flags;
 
@@ -560,7 +560,7 @@
 	if (!save)
 		return -ENOMEM;
 
-	dev->power.saved_state = (void *) save;
+	dev->dev.power.saved_state = (void *) save;
 
 	spin_lock_irqsave(&lchip->lock, flags);
 
@@ -594,14 +594,14 @@
 	return 0;
 }
 
-static int locomo_resume(struct device *dev)
+static int locomo_resume(struct platform_device *dev)
 {
-	struct locomo *lchip = dev_get_drvdata(dev);
+	struct locomo *lchip = platform_get_drvdata(dev);
 	struct locomo_save_data *save;
 	unsigned long r;
 	unsigned long flags;
 	
-	save = (struct locomo_save_data *) dev->power.saved_state;
+	save = (struct locomo_save_data *) dev->dev.power.saved_state;
 	if (!save)
 		return 0;
 
@@ -760,27 +760,26 @@
 	kfree(lchip);
 }
 
-static int locomo_probe(struct device *dev)
+static int locomo_probe(struct platform_device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *mem;
 	int irq;
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	if (!mem)
 		return -EINVAL;
-	irq = platform_get_irq(pdev, 0);
+	irq = platform_get_irq(dev, 0);
 
-	return __locomo_probe(dev, mem, irq);
+	return __locomo_probe(&dev->dev, mem, irq);
 }
 
-static int locomo_remove(struct device *dev)
+static int locomo_remove(struct platform_device *dev)
 {
-	struct locomo *lchip = dev_get_drvdata(dev);
+	struct locomo *lchip = platform__get_drvdata(dev);
 
 	if (lchip) {
 		__locomo_remove(lchip);
-		dev_set_drvdata(dev, NULL);
+		platform_set_drvdata(dev, NULL);
 	}
 
 	return 0;
@@ -792,15 +791,16 @@
  *	the per-machine level, and then have this driver pick
  *	up the registered devices.
  */
-static struct device_driver locomo_device_driver = {
-	.name		= "locomo",
-	.bus		= &platform_bus_type,
+static struct platform_driver locomo_device_driver = {
 	.probe		= locomo_probe,
 	.remove		= locomo_remove,
 #ifdef CONFIG_PM
 	.suspend	= locomo_suspend,
 	.resume		= locomo_resume,
 #endif
+	.driver		= {
+		.name	= "locomo",
+	},
 };
 
 /*
@@ -1126,13 +1126,13 @@
 {
 	int ret = bus_register(&locomo_bus_type);
 	if (ret == 0)
-		driver_register(&locomo_device_driver);
+		platform_driver_register(&locomo_device_driver);
 	return ret;
 }
 
 static void __exit locomo_exit(void)
 {
-	driver_unregister(&locomo_device_driver);
+	platform_driver_unregister(&locomo_device_driver);
 	bus_unregister(&locomo_bus_type);
 }
 
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 174aa86..7b07acb 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -801,9 +801,9 @@
 
 #ifdef CONFIG_PM
 
-static int sa1111_suspend(struct device *dev, pm_message_t state)
+static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct sa1111 *sachip = dev_get_drvdata(dev);
+	struct sa1111 *sachip = platform_get_drvdata(dev);
 	struct sa1111_save_data *save;
 	unsigned long flags;
 	unsigned int val;
@@ -812,7 +812,7 @@
 	save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
 	if (!save)
 		return -ENOMEM;
-	dev->power.saved_state = save;
+	dev->dev.power.saved_state = save;
 
 	spin_lock_irqsave(&sachip->lock, flags);
 
@@ -859,14 +859,14 @@
  *	restored by their respective drivers, and must be called
  *	via LDM after this function.
  */
-static int sa1111_resume(struct device *dev)
+static int sa1111_resume(struct platform_device *dev)
 {
-	struct sa1111 *sachip = dev_get_drvdata(dev);
+	struct sa1111 *sachip = platform_get_drvdata(dev);
 	struct sa1111_save_data *save;
 	unsigned long flags, id;
 	void __iomem *base;
 
-	save = (struct sa1111_save_data *)dev->power.saved_state;
+	save = (struct sa1111_save_data *)dev->dev.power.saved_state;
 	if (!save)
 		return 0;
 
@@ -879,7 +879,7 @@
 	id = sa1111_readl(sachip->base + SA1111_SKID);
 	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
 		__sa1111_remove(sachip);
-		dev_set_drvdata(dev, NULL);
+		platform_set_drvdata(dev, NULL);
 		kfree(save);
 		return 0;
 	}
@@ -911,7 +911,7 @@
 
 	spin_unlock_irqrestore(&sachip->lock, flags);
 
-	dev->power.saved_state = NULL;
+	dev->dev.power.saved_state = NULL;
 	kfree(save);
 
 	return 0;
@@ -922,9 +922,8 @@
 #define sa1111_resume  NULL
 #endif
 
-static int sa1111_probe(struct device *dev)
+static int sa1111_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *mem;
 	int irq;
 
@@ -933,20 +932,20 @@
 		return -EINVAL;
 	irq = platform_get_irq(pdev, 0);
 
-	return __sa1111_probe(dev, mem, irq);
+	return __sa1111_probe(&pdev->dev, mem, irq);
 }
 
-static int sa1111_remove(struct device *dev)
+static int sa1111_remove(struct platform_device *pdev)
 {
-	struct sa1111 *sachip = dev_get_drvdata(dev);
+	struct sa1111 *sachip = platform_get_drvdata(pdev);
 
 	if (sachip) {
 		__sa1111_remove(sachip);
-		dev_set_drvdata(dev, NULL);
+		platform_set_drvdata(pdev, NULL);
 
 #ifdef CONFIG_PM
-		kfree(dev->power.saved_state);
-		dev->power.saved_state = NULL;
+		kfree(pdev->dev.power.saved_state);
+		pdev->dev.power.saved_state = NULL;
 #endif
 	}
 
@@ -962,13 +961,14 @@
  *	We also need to handle the SDRAM configuration for
  *	PXA250/SA1110 machine classes.
  */
-static struct device_driver sa1111_device_driver = {
-	.name		= "sa1111",
-	.bus		= &platform_bus_type,
+static struct platform_driver sa1111_device_driver = {
 	.probe		= sa1111_probe,
 	.remove		= sa1111_remove,
 	.suspend	= sa1111_suspend,
 	.resume		= sa1111_resume,
+	.driver		= {
+		.name	= "sa1111",
+	},
 };
 
 /*
@@ -1256,13 +1256,13 @@
 {
 	int ret = bus_register(&sa1111_bus_type);
 	if (ret == 0)
-		driver_register(&sa1111_device_driver);
+		platform_driver_register(&sa1111_device_driver);
 	return ret;
 }
 
 static void __exit sa1111_exit(void)
 {
-	driver_unregister(&sa1111_device_driver);
+	platform_driver_unregister(&sa1111_device_driver);
 	bus_unregister(&sa1111_bus_type);
 }
 
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index bb4eff6..32924c6 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -19,12 +19,6 @@
 
 #define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr)))
 
-/* PCMCIA to Scoop linkage structures for pxa2xx_sharpsl.c
-   There is no easy way to link multiple scoop devices into one
-   single entity for the pxa2xx_pcmcia device */
-int scoop_num;
-struct scoop_pcmcia_dev *scoop_devs;
-
 struct  scoop_dev {
 	void  *base;
 	spinlock_t scoop_lock;
@@ -104,9 +98,9 @@
 }
 
 #ifdef CONFIG_PM
-static int scoop_suspend(struct device *dev, pm_message_t state)
+static int scoop_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct scoop_dev *sdev = dev_get_drvdata(dev);
+	struct scoop_dev *sdev = platform_get_drvdata(dev);
 
 	check_scoop_reg(sdev);
 	sdev->scoop_gpwr = SCOOP_REG(sdev->base, SCOOP_GPWR);
@@ -115,9 +109,9 @@
 	return 0;
 }
 
-static int scoop_resume(struct device *dev)
+static int scoop_resume(struct platform_device *dev)
 {
-	struct scoop_dev *sdev = dev_get_drvdata(dev);
+	struct scoop_dev *sdev = platform_get_drvdata(dev);
 
 	check_scoop_reg(sdev);
 	SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr;
@@ -129,11 +123,10 @@
 #define scoop_resume	NULL
 #endif
 
-int __init scoop_probe(struct device *dev)
+int __init scoop_probe(struct platform_device *pdev)
 {
 	struct scoop_dev *devptr;
 	struct scoop_config *inf;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	if (!mem)
@@ -147,7 +140,7 @@
 	memset(devptr, 0, sizeof(struct scoop_dev));
 	spin_lock_init(&devptr->scoop_lock);
 
-	inf = dev->platform_data;
+	inf = pdev->dev.platform_data;
 	devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
 
 	if (!devptr->base) {
@@ -155,7 +148,7 @@
 		return -ENOMEM;
 	}
 
-	dev_set_drvdata(dev, devptr);
+	platform_set_drvdata(pdev, devptr);
 
 	printk("Sharp Scoop Device found at 0x%08x -> 0x%08x\n",(unsigned int)mem->start,(unsigned int)devptr->base);
 
@@ -170,29 +163,30 @@
 	return 0;
 }
 
-static int scoop_remove(struct device *dev)
+static int scoop_remove(struct platform_device *pdev)
 {
-	struct scoop_dev *sdev = dev_get_drvdata(dev);
+	struct scoop_dev *sdev = platform_get_drvdata(pdev);
 	if (sdev) {
 		iounmap(sdev->base);
 		kfree(sdev);
-		dev_set_drvdata(dev, NULL);
+		platform_set_drvdata(pdev, NULL);
 	}
 	return 0;
 }
 
-static struct device_driver scoop_driver = {
-	.name		= "sharp-scoop",
-	.bus		= &platform_bus_type,
+static struct platform_driver scoop_driver = {
 	.probe		= scoop_probe,
 	.remove 	= scoop_remove,
 	.suspend	= scoop_suspend,
 	.resume		= scoop_resume,
+	.driver		= {
+		.name	= "sharp-scoop",
+	},
 };
 
 int __init scoop_init(void)
 {
-	return driver_register(&scoop_driver);
+	return platform_driver_register(&scoop_driver);
 }
 
 subsys_initcall(scoop_init);
diff --git a/arch/arm/configs/omap_h2_1610_defconfig b/arch/arm/configs/omap_h2_1610_defconfig
index 4198677..529f0f7 100644
--- a/arch/arm/configs/omap_h2_1610_defconfig
+++ b/arch/arm/configs/omap_h2_1610_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.13
-# Mon Sep  5 18:07:12 2005
+# Linux kernel version: 2.6.14
+# Wed Nov  9 18:53:40 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -22,6 +22,7 @@
 # General setup
 #
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -31,6 +32,7 @@
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -60,6 +62,23 @@
 # CONFIG_KMOD is not set
 
 #
+# Block layer
+#
+
+#
+# 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"
+
+#
 # System Type
 #
 # CONFIG_ARCH_CLPS7500 is not set
@@ -81,6 +100,7 @@
 # CONFIG_ARCH_LH7A40X is not set
 CONFIG_ARCH_OMAP=y
 # CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_REALVIEW is not set
 # CONFIG_ARCH_IMX is not set
 # CONFIG_ARCH_H720X is not set
 # CONFIG_ARCH_AAEC2000 is not set
@@ -112,7 +132,7 @@
 # OMAP Core Type
 #
 # CONFIG_ARCH_OMAP730 is not set
-# CONFIG_ARCH_OMAP1510 is not set
+# CONFIG_ARCH_OMAP15XX is not set
 CONFIG_ARCH_OMAP16XX=y
 
 #
@@ -177,6 +197,8 @@
 # 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=4096
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -258,14 +280,19 @@
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_BIC=y
 # CONFIG_IPV6 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
@@ -281,6 +308,10 @@
 # CONFIG_NET_DIVERT 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
 # CONFIG_NET_CLS_ROUTE is not set
 
@@ -291,6 +322,7 @@
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
 
 #
 # Device Drivers
@@ -328,21 +360,13 @@
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 CONFIG_ATA_OVER_ETH=m
 
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
 CONFIG_SCSI_PROC_FS=y
 
@@ -369,10 +393,12 @@
 # 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
 
 #
 # SCSI low-level drivers
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_DEBUG is not set
 
@@ -404,6 +430,11 @@
 # CONFIG_TUN is not set
 
 #
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
@@ -439,6 +470,7 @@
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
 CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
@@ -541,18 +573,18 @@
 #
 # TPM devices
 #
+# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
 #
 # CONFIG_I2C is not set
-# CONFIG_I2C_SENSOR is not set
-CONFIG_ISP1301_OMAP=y
 
 #
 # Hardware Monitoring support
 #
 CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -560,6 +592,10 @@
 #
 
 #
+# Multimedia Capabilities Port drivers
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -576,7 +612,6 @@
 # CONFIG_FB_CFB_FILLRECT is not set
 # CONFIG_FB_CFB_COPYAREA is not set
 # CONFIG_FB_CFB_IMAGEBLIT is not set
-# CONFIG_FB_SOFT_CURSOR is not set
 # CONFIG_FB_MACMODES is not set
 CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_TILEBLITTING is not set
@@ -589,6 +624,7 @@
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
@@ -600,6 +636,7 @@
 # CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_SUN12x22 is not set
 # CONFIG_FONT_10x18 is not set
+# CONFIG_FONT_RL is not set
 
 #
 # Logo configuration
@@ -624,10 +661,10 @@
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=y
+# CONFIG_OBSOLETE_OSS_DRIVER is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_AD1980 is not set
 
 #
 # USB support
@@ -637,22 +674,21 @@
 # CONFIG_USB 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_SELECTED=y
+# CONFIG_USB_GADGET 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=y
-CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_OMAP is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_GADGET_DUALSPEED is not set
 # CONFIG_USB_ZERO is not set
-CONFIG_USB_ETH=y
-CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH is not set
 # CONFIG_USB_GADGETFS is not set
 # CONFIG_USB_FILE_STORAGE is not set
 # CONFIG_USB_G_SERIAL is not set
@@ -673,10 +709,6 @@
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-
-#
-# XFS support
-#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
@@ -685,6 +717,7 @@
 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
@@ -706,10 +739,10 @@
 #
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -750,6 +783,7 @@
 # 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
@@ -859,6 +893,7 @@
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 7b17a87..7a3261f 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -9,6 +9,7 @@
  */
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/cryptohash.h>
 #include <linux/delay.h>
 #include <linux/in6.h>
 #include <linux/syscalls.h>
@@ -126,6 +127,9 @@
 EXPORT_SYMBOL(__put_user_4);
 EXPORT_SYMBOL(__put_user_8);
 
+	/* crypto hash */
+EXPORT_SYMBOL(sha_transform);
+
 	/* gcc lib functions */
 EXPORT_SYMBOL(__ashldi3);
 EXPORT_SYMBOL(__ashrdi3);
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index a511ec5..d9fb819 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -47,6 +47,13 @@
 	movne	r0, sp
 	adrne	lr, 1b
 	bne	do_IPI
+
+#ifdef CONFIG_LOCAL_TIMERS
+	test_for_ltirq r0, r6, r5, lr
+	movne	r0, sp
+	adrne	lr, 1b
+	bne	do_local_timer
+#endif
 #endif
 
 	.endm
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 9def440..d7099db 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -264,6 +264,7 @@
 #endif
 #ifdef CONFIG_SMP
 		show_ipi_list(p);
+		show_local_irqs(p);
 #endif
 		seq_printf(p, "Err: %10lu\n", irq_err_count);
 	}
@@ -995,7 +996,7 @@
 	struct proc_dir_entry *dir;
 	int irq;
 
-	dir = proc_mkdir("irq", 0);
+	dir = proc_mkdir("irq", NULL);
 	if (!dir)
 		return;
 
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index ba29827..30494aa 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -86,12 +86,16 @@
  */
 void default_idle(void)
 {
-	local_irq_disable();
-	if (!need_resched() && !hlt_counter) {
-		timer_dyn_reprogram();
-		arch_idle();
+	if (hlt_counter)
+		cpu_relax();
+	else {
+		local_irq_disable();
+		if (!need_resched()) {
+			timer_dyn_reprogram();
+			arch_idle();
+		}
+		local_irq_enable();
 	}
-	local_irq_enable();
 }
 
 /*
@@ -116,13 +120,13 @@
 
 		if (!idle)
 			idle = default_idle;
-		preempt_disable();
 		leds_event(led_idle_start);
 		while (!need_resched())
 			idle();
 		leds_event(led_idle_end);
-		preempt_enable();
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
@@ -355,7 +359,7 @@
 	struct thread_info *thread = p->thread_info;
 	struct pt_regs *childregs;
 
-	childregs = ((struct pt_regs *)((unsigned long)thread + THREAD_START_SP)) - 1;
+	childregs = (void *)thread + THREAD_START_SP - sizeof(*regs);
 	*childregs = *regs;
 	childregs->ARM_r0 = 0;
 	childregs->ARM_sp = stack_start;
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index edb5a40..e55ea95 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -142,7 +142,7 @@
 			ret = -EIO;
 	}
 
-	secondary_data.stack = 0;
+	secondary_data.stack = NULL;
 	secondary_data.pgdir = 0;
 
 	*pmd_offset(pgd, PHYS_OFFSET) = __pmd(0);
@@ -185,6 +185,11 @@
 	migrate_irqs();
 
 	/*
+	 * Stop the local timer for this CPU.
+	 */
+	local_timer_stop(cpu);
+
+	/*
 	 * Flush user cache and TLB mappings, and then remove this CPU
 	 * from the vm mask set of all processes.
 	 */
@@ -251,7 +256,9 @@
 asmlinkage void __cpuinit secondary_start_kernel(void)
 {
 	struct mm_struct *mm = &init_mm;
-	unsigned int cpu = smp_processor_id();
+	unsigned int cpu;
+
+	cpu = smp_processor_id();
 
 	printk("CPU%u: Booted secondary processor\n", cpu);
 
@@ -268,6 +275,7 @@
 	local_flush_tlb_all();
 
 	cpu_init();
+	preempt_disable();
 
 	/*
 	 * Give the platform a chance to do its own initialisation.
@@ -290,6 +298,11 @@
 	cpu_set(cpu, cpu_online_map);
 
 	/*
+	 * Setup local timer for this CPU.
+	 */
+	local_timer_setup(cpu);
+
+	/*
 	 * OK, it's off to the idle thread for us
 	 */
 	cpu_idle();
@@ -359,8 +372,8 @@
  * You must not call this function with disabled interrupts, from a
  * hardware interrupt handler, nor from a bottom half handler.
  */
-int smp_call_function_on_cpu(void (*func)(void *info), void *info, int retry,
-                             int wait, cpumask_t callmap)
+static int smp_call_function_on_cpu(void (*func)(void *info), void *info,
+				    int retry, int wait, cpumask_t callmap)
 {
 	struct smp_call_struct data;
 	unsigned long timeout;
@@ -454,6 +467,18 @@
 	seq_putc(p, '\n');
 }
 
+void show_local_irqs(struct seq_file *p)
+{
+	unsigned int cpu;
+
+	seq_printf(p, "LOC: ");
+
+	for_each_present_cpu(cpu)
+		seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs);
+
+	seq_putc(p, '\n');
+}
+
 static void ipi_timer(struct pt_regs *regs)
 {
 	int user = user_mode(regs);
@@ -464,6 +489,18 @@
 	irq_exit();
 }
 
+#ifdef CONFIG_LOCAL_TIMERS
+asmlinkage void do_local_timer(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	if (local_timer_ack()) {
+		irq_stat[cpu].local_timer_irqs++;
+		ipi_timer(regs);
+	}
+}
+#endif
+
 /*
  * ipi_call_function - handle IPI from smp_call_function()
  *
@@ -515,7 +552,7 @@
  *
  *  Bit 0 - Inter-processor function call
  */
-void do_IPI(struct pt_regs *regs)
+asmlinkage void do_IPI(struct pt_regs *regs)
 {
 	unsigned int cpu = smp_processor_id();
 	struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
diff --git a/arch/arm/lib/bitops.h b/arch/arm/lib/bitops.h
index f35d91f..b8c14e9 100644
--- a/arch/arm/lib/bitops.h
+++ b/arch/arm/lib/bitops.h
@@ -34,7 +34,7 @@
 	and	r2, r0, #7
 	mov	r3, #1
 	mov	r3, r3, lsl r2
-	save_and_disable_irqs ip, r2
+	save_and_disable_irqs ip
 	ldrb	r2, [r1, r0, lsr #3]
 	\instr	r2, r2, r3
 	strb	r2, [r1, r0, lsr #3]
@@ -54,7 +54,7 @@
 	add	r1, r1, r0, lsr #3
 	and	r3, r0, #7
 	mov	r0, #1
-	save_and_disable_irqs ip, r2
+	save_and_disable_irqs ip
 	ldrb	r2, [r1]
 	tst	r2, r0, lsl r3
 	\instr	r2, r2, r0, lsl r3
diff --git a/arch/arm/lib/csumpartial.S b/arch/arm/lib/csumpartial.S
index cb5e370..fe797cf 100644
--- a/arch/arm/lib/csumpartial.S
+++ b/arch/arm/lib/csumpartial.S
@@ -39,6 +39,7 @@
 
 		/* we must have at least one byte. */
 		tst	buf, #1			@ odd address?
+		movne	sum, sum, ror #8
 		ldrneb	td0, [buf], #1
 		subne	len, len, #1
 		adcnes	sum, sum, td0, put_byte_1
@@ -103,6 +104,9 @@
 		cmp	len, #8			@ Ensure that we have at least
 		blo	.less8			@ 8 bytes to copy.
 
+		tst	buf, #1
+		movne	sum, sum, ror #8
+
 		adds	sum, sum, #0		@ C = 0
 		tst	buf, #3			@ Test destination alignment
 		blne	.not_aligned		@ aligh destination, return here
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
index 89762a2..3852858 100644
--- a/arch/arm/mach-ixp4xx/Kconfig
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -8,6 +8,16 @@
 
 comment "IXP4xx Platforms"
 
+# This entry is placed on top because otherwise it would have
+# been shown as a submenu.
+config MACH_NSLU2
+	bool
+	prompt "NSLU2" if !(MACH_IXDP465 || MACH_IXDPG425 || ARCH_IXDP425 || ARCH_ADI_COYOTE || ARCH_AVILA || ARCH_IXCDP1100 || ARCH_PRPMC1100 || MACH_GTWX5715)
+	help
+	  Say 'Y' here if you want your kernel to support Linksys's
+	  NSLU2 NAS device. For more information on this platform,
+	  see http://www.nslu2-linux.org
+
 config ARCH_AVILA
 	bool "Avila"
 	help
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
index ddecbda..7a15629 100644
--- a/arch/arm/mach-ixp4xx/Makefile
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -8,4 +8,5 @@
 obj-$(CONFIG_MACH_IXDPG425)	+= ixdpg425-pci.o coyote-setup.o
 obj-$(CONFIG_ARCH_ADI_COYOTE)	+= coyote-pci.o coyote-setup.o
 obj-$(CONFIG_MACH_GTWX5715)	+= gtwx5715-pci.o gtwx5715-setup.o
+obj-$(CONFIG_MACH_NSLU2)	+= nslu2-pci.o nslu2-setup.o nslu2-power.o
 
diff --git a/arch/arm/mach-ixp4xx/nslu2-pci.c b/arch/arm/mach-ixp4xx/nslu2-pci.c
new file mode 100644
index 0000000..a575f2e
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/nslu2-pci.c
@@ -0,0 +1,77 @@
+/*
+ * arch/arm/mach-ixp4xx/nslu2-pci.c
+ *
+ * NSLU2 board-level PCI initialization
+ *
+ * based on ixdp425-pci.c:
+ *	Copyright (C) 2002 Intel Corporation.
+ *	Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Maintainer: http://www.nslu2-linux.org/
+ *
+ * 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/config.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/mach/pci.h>
+#include <asm/mach-types.h>
+
+void __init nslu2_pci_preinit(void)
+{
+	set_irq_type(IRQ_NSLU2_PCI_INTA, IRQT_LOW);
+	set_irq_type(IRQ_NSLU2_PCI_INTB, IRQT_LOW);
+	set_irq_type(IRQ_NSLU2_PCI_INTC, IRQT_LOW);
+
+	gpio_line_isr_clear(NSLU2_PCI_INTA_PIN);
+	gpio_line_isr_clear(NSLU2_PCI_INTB_PIN);
+	gpio_line_isr_clear(NSLU2_PCI_INTC_PIN);
+
+	/* INTD is not configured as GPIO is used
+	 * for the power input button.
+	 */
+
+	ixp4xx_pci_preinit();
+}
+
+static int __init nslu2_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	static int pci_irq_table[NSLU2_PCI_IRQ_LINES] = {
+		IRQ_NSLU2_PCI_INTA,
+		IRQ_NSLU2_PCI_INTB,
+		IRQ_NSLU2_PCI_INTC,
+	};
+
+	int irq = -1;
+
+	if (slot >= 1 && slot <= NSLU2_PCI_MAX_DEV &&
+		pin >= 1 && pin <= NSLU2_PCI_IRQ_LINES) {
+			irq = pci_irq_table[(slot + pin - 2) % NSLU2_PCI_IRQ_LINES];
+	}
+
+	return irq;
+}
+
+struct hw_pci __initdata nslu2_pci = {
+	.nr_controllers = 1,
+	.preinit	= nslu2_pci_preinit,
+	.swizzle	= pci_std_swizzle,
+	.setup		= ixp4xx_setup,
+	.scan		= ixp4xx_scan_bus,
+	.map_irq	= nslu2_map_irq,
+};
+
+int __init nslu2_pci_init(void) /* monkey see, monkey do */
+{
+	if (machine_is_nslu2())
+		pci_common_init(&nslu2_pci);
+
+	return 0;
+}
+
+subsys_initcall(nslu2_pci_init);
diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c
new file mode 100644
index 0000000..18fbc8c
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/nslu2-power.c
@@ -0,0 +1,92 @@
+/*
+ * arch/arm/mach-ixp4xx/nslu2-power.c
+ *
+ * NSLU2 Power/Reset driver
+ *
+ * Copyright (C) 2005 Tower Technologies
+ *
+ * based on nslu2-io.c
+ *  Copyright (C) 2004 Karen Spearel
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Maintainers: http://www.nslu2-linux.org/
+ *
+ * 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/reboot.h>
+#include <linux/interrupt.h>
+
+#include <asm/mach-types.h>
+
+extern void ctrl_alt_del(void);
+
+static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* Signal init to do the ctrlaltdel action, this will bypass init if
+	 * it hasn't started and do a kernel_restart.
+	 */
+	ctrl_alt_del();
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t nslu2_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* This is the paper-clip reset, it shuts the machine down directly.
+	 */
+	machine_power_off();
+
+	return IRQ_HANDLED;
+}
+
+static int __init nslu2_power_init(void)
+{
+	if (!(machine_is_nslu2()))
+		return 0;
+
+	*IXP4XX_GPIO_GPISR = 0x20400000;	/* read the 2 irqs to clr */
+
+	set_irq_type(NSLU2_RB_IRQ, IRQT_LOW);
+	set_irq_type(NSLU2_PB_IRQ, IRQT_HIGH);
+
+	gpio_line_isr_clear(NSLU2_RB_GPIO);
+	gpio_line_isr_clear(NSLU2_PB_GPIO);
+
+	if (request_irq(NSLU2_RB_IRQ, &nslu2_reset_handler,
+		SA_INTERRUPT, "NSLU2 reset button", NULL) < 0) {
+
+		printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
+			NSLU2_RB_IRQ);
+
+		return -EIO;
+	}
+
+	if (request_irq(NSLU2_PB_IRQ, &nslu2_power_handler,
+		SA_INTERRUPT, "NSLU2 power button", NULL) < 0) {
+
+		printk(KERN_DEBUG "Power Button IRQ %d not available\n",
+			NSLU2_PB_IRQ);
+
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void __exit nslu2_power_exit(void)
+{
+	free_irq(NSLU2_RB_IRQ, NULL);
+	free_irq(NSLU2_PB_IRQ, NULL);
+}
+
+module_init(nslu2_power_init);
+module_exit(nslu2_power_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("NSLU2 Power/Reset driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
new file mode 100644
index 0000000..289e94c
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -0,0 +1,134 @@
+/*
+ * arch/arm/mach-ixp4xx/nslu2-setup.c
+ *
+ * NSLU2 board-setup
+ *
+ * based ixdp425-setup.c:
+ *      Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Author: Mark Rakes <mrakes at mac.com>
+ * Maintainers: http://www.nslu2-linux.org/
+ *
+ * Fixed missing init_time in MACHINE_START kas11 10/22/04
+ * Changed to conform to new style __init ixdp425 kas11 10/22/04
+ */
+
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+static struct flash_platform_data nslu2_flash_data = {
+	.map_name		= "cfi_probe",
+	.width			= 2,
+};
+
+static struct resource nslu2_flash_resource = {
+	.start			= NSLU2_FLASH_BASE,
+	.end			= NSLU2_FLASH_BASE + NSLU2_FLASH_SIZE,
+	.flags			= IORESOURCE_MEM,
+};
+
+static struct platform_device nslu2_flash = {
+	.name			= "IXP4XX-Flash",
+	.id			= 0,
+	.dev.platform_data	= &nslu2_flash_data,
+	.num_resources		= 1,
+	.resource		= &nslu2_flash_resource,
+};
+
+static struct ixp4xx_i2c_pins nslu2_i2c_gpio_pins = {
+	.sda_pin		= NSLU2_SDA_PIN,
+	.scl_pin		= NSLU2_SCL_PIN,
+};
+
+static struct platform_device nslu2_i2c_controller = {
+	.name			= "IXP4XX-I2C",
+	.id			= 0,
+	.dev.platform_data	= &nslu2_i2c_gpio_pins,
+	.num_resources		= 0,
+};
+
+static struct resource nslu2_uart_resources[] = {
+	{
+		.start		= IXP4XX_UART1_BASE_PHYS,
+		.end		= IXP4XX_UART1_BASE_PHYS + 0x0fff,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= IXP4XX_UART2_BASE_PHYS,
+		.end		= IXP4XX_UART2_BASE_PHYS + 0x0fff,
+		.flags		= IORESOURCE_MEM,
+	}
+};
+
+static struct plat_serial8250_port nslu2_uart_data[] = {
+	{
+		.mapbase	= IXP4XX_UART1_BASE_PHYS,
+		.membase	= (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
+		.irq		= IRQ_IXP4XX_UART1,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= IXP4XX_UART_XTAL,
+	},
+	{
+		.mapbase	= IXP4XX_UART2_BASE_PHYS,
+		.membase	= (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+		.irq		= IRQ_IXP4XX_UART2,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= IXP4XX_UART_XTAL,
+	},
+	{ }
+};
+
+static struct platform_device nslu2_uart = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev.platform_data	= nslu2_uart_data,
+	.num_resources		= 2,
+	.resource		= nslu2_uart_resources,
+};
+
+static struct platform_device *nslu2_devices[] __initdata = {
+	&nslu2_i2c_controller,
+	&nslu2_flash,
+	&nslu2_uart,
+};
+
+static void nslu2_power_off(void)
+{
+	/* This causes the box to drop the power and go dead. */
+
+	/* enable the pwr cntl gpio */
+	gpio_line_config(NSLU2_PO_GPIO, IXP4XX_GPIO_OUT);
+
+	/* do the deed */
+	gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH);
+}
+
+static void __init nslu2_init(void)
+{
+	ixp4xx_sys_init();
+
+	pm_power_off = nslu2_power_off;
+
+	platform_add_devices(nslu2_devices, ARRAY_SIZE(nslu2_devices));
+}
+
+MACHINE_START(NSLU2, "Linksys NSLU2")
+	/* Maintainer: www.nslu2-linux.org */
+	.phys_ram	= PHYS_OFFSET,
+	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
+	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
+	.boot_params	= 0x00000100,
+	.map_io		= ixp4xx_map_io,
+	.init_irq	= ixp4xx_init_irq,
+	.timer          = &ixp4xx_timer,
+	.init_machine	= nslu2_init,
+MACHINE_END
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index 27fc2e8..86a0f0d 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -6,10 +6,10 @@
 	bool "OMAP730 Based System"
 	select ARCH_OMAP_OTG
 
-config ARCH_OMAP1510
+config ARCH_OMAP15XX
 	depends on ARCH_OMAP1
 	default y
-	bool "OMAP1510 Based System"
+	bool "OMAP15xx Based System"
 
 config ARCH_OMAP16XX
 	depends on ARCH_OMAP1
@@ -21,7 +21,7 @@
 
 config MACH_OMAP_INNOVATOR
 	bool "TI Innovator"
-	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX)
+	depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
 	help
           TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
           have such a board.
@@ -64,20 +64,30 @@
 
 config MACH_VOICEBLUE
 	bool "Voiceblue"
-	depends on ARCH_OMAP1 && ARCH_OMAP1510
+	depends on ARCH_OMAP1 && ARCH_OMAP15XX
 	help
 	  Support for Voiceblue GSM/VoIP gateway. Say Y here if you have
 	  such a board.
 
 config MACH_NETSTAR
 	bool "NetStar"
-	depends on ARCH_OMAP1 && ARCH_OMAP1510
+	depends on ARCH_OMAP1 && ARCH_OMAP15XX
 	help
 	  Support for NetStar PBX. Say Y here if you have such a board.
 
+config MACH_OMAP_PALMTE
+	bool "Palm Tungsten E"
+	depends on ARCH_OMAP1 && ARCH_OMAP15XX
+	help
+          Support for the Palm Tungsten E PDA. Currently only the LCD panel
+          is supported. To boot the kernel, you'll need a PalmOS compatible
+          bootloader; check out http://palmtelinux.sourceforge.net for more
+          informations.
+          Say Y here if you have such a PDA, say NO otherwise.
+
 config MACH_OMAP_GENERIC
 	bool "Generic OMAP board"
-	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX)
+	depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
 	help
           Support for generic OMAP-1510, 1610 or 1710 board with
           no FPGA. Can be used as template for porting Linux to
@@ -121,32 +131,32 @@
 
 config OMAP_ARM_168MHZ
 	bool "OMAP ARM 168 MHz CPU"
-	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+	depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730)
 	help
           Enable 168MHz clock for OMAP CPU. If unsure, say N.
 
 config OMAP_ARM_150MHZ
 	bool "OMAP ARM 150 MHz CPU"
-	depends on ARCH_OMAP1 && ARCH_OMAP1510
+	depends on ARCH_OMAP1 && ARCH_OMAP15XX
 	help
 	  Enable 150MHz clock for OMAP CPU. If unsure, say N.
 
 config OMAP_ARM_120MHZ
 	bool "OMAP ARM 120 MHz CPU"
-	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+	depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730)
 	help
           Enable 120MHz clock for OMAP CPU. If unsure, say N.
 
 config OMAP_ARM_60MHZ
 	bool "OMAP ARM 60 MHz CPU"
-	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+	depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730)
         default y
 	help
           Enable 60MHz clock for OMAP CPU. If unsure, say Y.
 
 config OMAP_ARM_30MHZ
 	bool "OMAP ARM 30 MHz CPU"
-	depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+	depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730)
 	help
           Enable 30MHz clock for OMAP CPU. If unsure, say N.
 
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 181a93d..b0b0015 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := io.o id.o irq.o time.o serial.o devices.o
+obj-y := io.o id.o clock.o irq.o time.o mux.o serial.o devices.o
 led-y := leds.o
 
 # Specific board support
@@ -15,8 +15,9 @@
 obj-$(CONFIG_MACH_OMAP_H3)		+= board-h3.o
 obj-$(CONFIG_MACH_VOICEBLUE)		+= board-voiceblue.o
 obj-$(CONFIG_MACH_NETSTAR)		+= board-netstar.o
+obj-$(CONFIG_MACH_OMAP_PALMTE)		+= board-palmte.o
 
-ifeq ($(CONFIG_ARCH_OMAP1510),y)
+ifeq ($(CONFIG_ARCH_OMAP15XX),y)
 # Innovator-1510 FPGA
 obj-$(CONFIG_MACH_OMAP_INNOVATOR)	+= fpga.o
 endif
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index c209c71..4b292e9 100644
--- a/arch/arm/mach-omap1/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -15,7 +15,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -28,8 +28,6 @@
 #include <asm/arch/board.h>
 #include <asm/arch/common.h>
 
-static int __initdata generic_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
-
 static void __init omap_generic_init_irq(void)
 {
 	omap_init_irq();
@@ -37,7 +35,7 @@
 
 /* assume no Mini-AB port */
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 static struct omap_usb_config generic1510_usb_config __initdata = {
 	.register_host	= 1,
 	.register_dev	= 1,
@@ -76,21 +74,19 @@
 
 #endif
 
+static struct omap_uart_config generic_uart_config __initdata = {
+	.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
 static struct omap_board_config_kernel generic_config[] = {
 	{ OMAP_TAG_USB,           NULL },
 	{ OMAP_TAG_MMC,           &generic_mmc_config },
+	{ OMAP_TAG_UART,	&generic_uart_config },
 };
 
 static void __init omap_generic_init(void)
 {
-	const struct omap_uart_config *uart_conf;
-
-	/*
-	 * Make sure the serial ports are muxed on at this point.
-	 * You have to mux them off in device drivers later on
-	 * if not needed.
-	 */
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		generic_config[0].data = &generic1510_usb_config;
 	}
@@ -101,20 +97,9 @@
 	}
 #endif
 
-	uart_conf = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
-	if (uart_conf != NULL) {
-		unsigned int enabled_ports, i;
-
-		enabled_ports = uart_conf->enabled_uarts;
-		for (i = 0; i < 3; i++) {
-			if (!(enabled_ports & (1 << i)))
-				generic_serial_ports[i] = 0;
-		}
-	}
-
 	omap_board_config = generic_config;
 	omap_board_config_size = ARRAY_SIZE(generic_config);
-	omap_serial_init(generic_serial_ports);
+	omap_serial_init();
 }
 
 static void __init omap_generic_map_io(void)
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 4ee6bd8..a07e2c9 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -40,8 +40,6 @@
 
 extern int omap_gpio_init(void);
 
-static int __initdata h2_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
-
 static struct mtd_partition h2_partitions[] = {
 	/* bootloader (U-Boot, etc) in first sector */
 	{
@@ -160,9 +158,20 @@
 	},
 };
 
+static struct omap_uart_config h2_uart_config __initdata = {
+	.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_lcd_config h2_lcd_config __initdata = {
+	.panel_name	= "h2",
+	.ctrl_name	= "internal",
+};
+
 static struct omap_board_config_kernel h2_config[] = {
 	{ OMAP_TAG_USB,           &h2_usb_config },
 	{ OMAP_TAG_MMC,           &h2_mmc_config },
+	{ OMAP_TAG_UART,	&h2_uart_config },
+	{ OMAP_TAG_LCD,		&h2_lcd_config },
 };
 
 static void __init h2_init(void)
@@ -180,12 +189,12 @@
 	platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
 	omap_board_config = h2_config;
 	omap_board_config_size = ARRAY_SIZE(h2_config);
+	omap_serial_init();
 }
 
 static void __init h2_map_io(void)
 {
 	omap_map_common_io();
-	omap_serial_init(h2_serial_ports);
 }
 
 MACHINE_START(OMAP_H2, "TI-H2")
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index fc82436..668e278 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -41,8 +41,6 @@
 
 extern int omap_gpio_init(void);
 
-static int __initdata h3_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
-
 static struct mtd_partition h3_partitions[] = {
 	/* bootloader (U-Boot, etc) in first sector */
 	{
@@ -168,9 +166,20 @@
 	},
 };
 
+static struct omap_uart_config h3_uart_config __initdata = {
+	.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_lcd_config h3_lcd_config __initdata = {
+	.panel_name	= "h3",
+	.ctrl_name	= "internal",
+};
+
 static struct omap_board_config_kernel h3_config[] = {
-	{ OMAP_TAG_USB,	 &h3_usb_config },
-	{ OMAP_TAG_MMC,  &h3_mmc_config },
+	{ OMAP_TAG_USB,		&h3_usb_config },
+	{ OMAP_TAG_MMC,		&h3_mmc_config },
+	{ OMAP_TAG_UART,	&h3_uart_config },
+	{ OMAP_TAG_LCD,		&h3_lcd_config },
 };
 
 static void __init h3_init(void)
@@ -180,6 +189,7 @@
 	(void) platform_add_devices(devices, ARRAY_SIZE(devices));
 	omap_board_config = h3_config;
 	omap_board_config_size = ARRAY_SIZE(h3_config);
+	omap_serial_init();
 }
 
 static void __init h3_init_smc91x(void)
@@ -201,7 +211,6 @@
 static void __init h3_map_io(void)
 {
 	omap_map_common_io();
-	omap_serial_init(h3_serial_ports);
 }
 
 MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index a2eac85..95f1ff3 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -36,8 +36,6 @@
 #include <asm/arch/usb.h>
 #include <asm/arch/common.h>
 
-static int __initdata innovator_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
-
 static struct mtd_partition innovator_partitions[] = {
 	/* bootloader (U-Boot, etc) in first sector */
 	{
@@ -99,7 +97,7 @@
 	.resource	= &innovator_flash_resource,
 };
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 
 /* Only FPGA needs to be mapped here. All others are done with ioremap */
 static struct map_desc innovator1510_io_desc[] __initdata = {
@@ -136,7 +134,7 @@
 	&innovator1510_smc91x_device,
 };
 
-#endif /* CONFIG_ARCH_OMAP1510 */
+#endif /* CONFIG_ARCH_OMAP15XX */
 
 #ifdef CONFIG_ARCH_OMAP16XX
 
@@ -185,7 +183,7 @@
 {
 	omap_init_irq();
 	omap_gpio_init();
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		omap1510_fpga_init_irq();
 	}
@@ -193,7 +191,7 @@
 	innovator_init_smc91x();
 }
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 static struct omap_usb_config innovator1510_usb_config __initdata = {
 	/* for bundled non-standard host and peripheral cables */
 	.hmc_mode	= 4,
@@ -205,6 +203,11 @@
 	.register_dev	= 1,
 	.pins[0]	= 2,
 };
+
+static struct omap_lcd_config innovator1510_lcd_config __initdata = {
+	.panel_name	= "inn1510",
+	.ctrl_name	= "internal",
+};
 #endif
 
 #ifdef CONFIG_ARCH_OMAP16XX
@@ -222,6 +225,11 @@
 
 	.pins[1]	= 3,
 };
+
+static struct omap_lcd_config innovator1610_lcd_config __initdata = {
+	.panel_name	= "inn1610",
+	.ctrl_name	= "internal",
+};
 #endif
 
 static struct omap_mmc_config innovator_mmc_config __initdata = {
@@ -234,14 +242,20 @@
 	},
 };
 
+static struct omap_uart_config innovator_uart_config __initdata = {
+	.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
 static struct omap_board_config_kernel innovator_config[] = {
 	{ OMAP_TAG_USB,         NULL },
+	{ OMAP_TAG_LCD,		NULL },
 	{ OMAP_TAG_MMC,		&innovator_mmc_config },
+	{ OMAP_TAG_UART,	&innovator_uart_config },
 };
 
 static void __init innovator_init(void)
 {
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		platform_add_devices(innovator1510_devices, ARRAY_SIZE(innovator1510_devices));
 	}
@@ -252,23 +266,28 @@
 	}
 #endif
 
-#ifdef CONFIG_ARCH_OMAP1510
-	if (cpu_is_omap1510())
+#ifdef CONFIG_ARCH_OMAP15XX
+	if (cpu_is_omap1510()) {
 		innovator_config[0].data = &innovator1510_usb_config;
+		innovator_config[1].data = &innovator1510_lcd_config;
+	}
 #endif
 #ifdef CONFIG_ARCH_OMAP16XX
-	if (cpu_is_omap1610())
+	if (cpu_is_omap1610()) {
 		innovator_config[0].data = &h2_usb_config;
+		innovator_config[1].data = &innovator1610_lcd_config;
+	}
 #endif
 	omap_board_config = innovator_config;
 	omap_board_config_size = ARRAY_SIZE(innovator_config);
+	omap_serial_init();
 }
 
 static void __init innovator_map_io(void)
 {
 	omap_map_common_io();
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		iotable_init(innovator1510_io_desc, ARRAY_SIZE(innovator1510_io_desc));
 		udelay(10);	/* Delay needed for FPGA */
@@ -280,7 +299,6 @@
 		       fpga_read(OMAP1510_FPGA_BOARD_REV));
 	}
 #endif
-	omap_serial_init(innovator_serial_ports);
 }
 
 MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c
index c851c2e..0448fa7 100644
--- a/arch/arm/mach-omap1/board-netstar.c
+++ b/arch/arm/mach-omap1/board-netstar.c
@@ -55,6 +55,14 @@
 	&netstar_smc91x_device,
 };
 
+static struct omap_uart_config netstar_uart_config __initdata = {
+	.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel netstar_config[] = {
+	{ OMAP_TAG_UART,	&netstar_uart_config },
+};
+
 static void __init netstar_init_irq(void)
 {
 	omap_init_irq();
@@ -92,14 +100,15 @@
 	/* Switch off red LED */
 	omap_writeb(0x00, OMAP_LPG1_PMR);	/* Disable clock */
 	omap_writeb(0x80, OMAP_LPG1_LCR);
-}
 
-static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+	omap_board_config = netstar_config;
+	omap_board_config_size = ARRAY_SIZE(netstar_config);
+	omap_serial_init();
+}
 
 static void __init netstar_map_io(void)
 {
 	omap_map_common_io();
-	omap_serial_init(omap_serial_ports);
 }
 
 #define MACHINE_PANICED		1
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index a88524e..e990e1b 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -46,8 +46,6 @@
 #include <asm/arch/tc.h>
 #include <asm/arch/common.h>
 
-static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0};
-
 static struct mtd_partition osk_partitions[] = {
 	/* bootloader (U-Boot, etc) in first sector */
 	{
@@ -155,7 +153,7 @@
 	}
 
 	/* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */
-	EMIFS_CCS(1) |= 0x2;
+	EMIFS_CCS(1) |= 0x3;
 }
 
 static void __init osk_init_cf(void)
@@ -193,8 +191,19 @@
 	.pins[0]	= 2,
 };
 
+static struct omap_uart_config osk_uart_config __initdata = {
+	.enabled_uarts = (1 << 0),
+};
+
+static struct omap_lcd_config osk_lcd_config __initdata = {
+	.panel_name	= "osk",
+	.ctrl_name	= "internal",
+};
+
 static struct omap_board_config_kernel osk_config[] = {
 	{ OMAP_TAG_USB,           &osk_usb_config },
+	{ OMAP_TAG_UART,		&osk_uart_config },
+	{ OMAP_TAG_LCD,			&osk_lcd_config },
 };
 
 #ifdef	CONFIG_OMAP_OSK_MISTRAL
@@ -254,13 +263,13 @@
 	omap_board_config_size = ARRAY_SIZE(osk_config);
 	USB_TRANSCEIVER_CTRL_REG |= (3 << 1);
 
+	omap_serial_init();
 	osk_mistral_init();
 }
 
 static void __init osk_map_io(void)
 {
 	omap_map_common_io();
-	omap_serial_init(osk_serial_ports);
 }
 
 MACHINE_START(OMAP_OSK, "TI-OSK")
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
new file mode 100644
index 0000000..540b20d
--- /dev/null
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -0,0 +1,87 @@
+/*
+ * linux/arch/arm/mach-omap1/board-palmte.c
+ *
+ * Modified from board-generic.c
+ *
+ * Support for the Palm Tungsten E PDA.
+ *
+ * Original version : Laurent Gonzalez
+ *
+ * Maintainters : http://palmtelinux.sf.net
+ *                palmtelinux-developpers@lists.sf.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/notifier.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+#include <asm/hardware/clock.h>
+
+static void __init omap_generic_init_irq(void)
+{
+	omap_init_irq();
+}
+
+static struct omap_usb_config palmte_usb_config __initdata = {
+	.register_dev	= 1,
+	.hmc_mode	= 0,
+	.pins[0]	= 3,
+};
+
+static struct omap_mmc_config palmte_mmc_config __initdata = {
+	.mmc [0] = {
+		.enabled 	= 1,
+		.wire4		= 1,
+		.wp_pin		= OMAP_MPUIO(3),
+		.power_pin	= -1,
+		.switch_pin	= -1,
+	},
+};
+
+static struct omap_lcd_config palmte_lcd_config __initdata = {
+	.panel_name	= "palmte",
+	.ctrl_name	= "internal",
+};
+
+static struct omap_board_config_kernel palmte_config[] = {
+	{ OMAP_TAG_USB, &palmte_usb_config },
+	{ OMAP_TAG_MMC,	&palmte_mmc_config },
+	{ OMAP_TAG_LCD,	&palmte_lcd_config },
+};
+
+static void __init omap_generic_init(void)
+{
+	omap_board_config = palmte_config;
+	omap_board_config_size = ARRAY_SIZE(palmte_config);
+}
+
+static void __init omap_generic_map_io(void)
+{
+	omap_map_common_io();
+}
+
+MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
+	.phys_ram	= 0x10000000,
+	.phys_io	= 0xfff00000,
+	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
+	.boot_params	= 0x10000100,
+	.map_io		= omap_generic_map_io,
+	.init_irq	= omap_generic_init_irq,
+	.init_machine	= omap_generic_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 354b157..bd900b7 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -29,6 +29,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
 #include <asm/arch/common.h>
+#include <asm/arch/board.h>
 
 static struct resource smc91x_resources[] = {
 	[0] = {
@@ -43,8 +44,6 @@
 	},
 };
 
-static int __initdata p2_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 0};
-
 static struct mtd_partition p2_partitions[] = {
 	/* bootloader (U-Boot, etc) in first sector */
 	{
@@ -111,9 +110,27 @@
 	&smc91x_device,
 };
 
+static struct omap_uart_config perseus2_uart_config __initdata = {
+	.enabled_uarts = ((1 << 0) | (1 << 1)),
+};
+
+static struct omap_lcd_config perseus2_lcd_config __initdata = {
+	.panel_name	= "p2",
+	.ctrl_name	= "internal",
+};
+
+static struct omap_board_config_kernel perseus2_config[] = {
+	{ OMAP_TAG_UART,	&perseus2_uart_config },
+	{ OMAP_TAG_LCD,		&perseus2_lcd_config },
+};
+
 static void __init omap_perseus2_init(void)
 {
 	(void) platform_add_devices(devices, ARRAY_SIZE(devices));
+
+	omap_board_config = perseus2_config;
+	omap_board_config_size = ARRAY_SIZE(perseus2_config);
+	omap_serial_init();
 }
 
 static void __init perseus2_init_smc91x(void)
@@ -131,7 +148,6 @@
 	omap_gpio_init();
 	perseus2_init_smc91x();
 }
-
 /* Only FPGA needs to be mapped here. All others are done with ioremap */
 static struct map_desc omap_perseus2_io_desc[] __initdata = {
 	{
@@ -179,7 +195,6 @@
 	 * It is used as the Ethernet controller interrupt
 	 */
 	omap_writel(omap_readl(OMAP730_IO_CONF_9) & 0x1FFFFFFF, OMAP730_IO_CONF_9);
-	omap_serial_init(p2_serial_ports);
 }
 
 MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index 3f018b2..6f9a622 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -150,9 +150,14 @@
 	},
 };
 
+static struct omap_uart_config voiceblue_uart_config __initdata = {
+	.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
 static struct omap_board_config_kernel voiceblue_config[] = {
 	{ OMAP_TAG_USB, &voiceblue_usb_config },
 	{ OMAP_TAG_MMC, &voiceblue_mmc_config },
+	{ OMAP_TAG_UART,	&voiceblue_uart_config },
 };
 
 static void __init voiceblue_init_irq(void)
@@ -191,6 +196,7 @@
 	platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
 	omap_board_config = voiceblue_config;
 	omap_board_config_size = ARRAY_SIZE(voiceblue_config);
+	omap_serial_init();
 
 	/* There is a good chance board is going up, so enable power LED
 	 * (it is connected through invertor) */
@@ -198,12 +204,9 @@
 	omap_writeb(0x00, OMAP_LPG1_PMR);	/* Disable clock */
 }
 
-static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
-
 static void __init voiceblue_map_io(void)
 {
 	omap_map_common_io();
-	omap_serial_init(omap_serial_ports);
 }
 
 #define MACHINE_PANICED		1
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
new file mode 100644
index 0000000..4277eee
--- /dev/null
+++ b/arch/arm/mach-omap1/clock.c
@@ -0,0 +1,792 @@
+/*
+ *  linux/arch/arm/mach-omap1/clock.c
+ *
+ *  Copyright (C) 2004 - 2005 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ *  Modified to use omap shared clock framework by
+ *  Tony Lindgren <tony@atomide.com>
+ *
+ * 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/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/hardware/clock.h>
+
+#include <asm/arch/usb.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
+
+#include "clock.h"
+
+__u32 arm_idlect1_mask;
+
+/*-------------------------------------------------------------------------
+ * Omap1 specific clock functions
+ *-------------------------------------------------------------------------*/
+
+static void omap1_watchdog_recalc(struct clk * clk)
+{
+	clk->rate = clk->parent->rate / 14;
+}
+
+static void omap1_uart_recalc(struct clk * clk)
+{
+	unsigned int val = omap_readl(clk->enable_reg);
+	if (val & clk->enable_bit)
+		clk->rate = 48000000;
+	else
+		clk->rate = 12000000;
+}
+
+static int omap1_clk_enable_dsp_domain(struct clk *clk)
+{
+	int retval;
+
+	retval = omap1_clk_use(&api_ck.clk);
+	if (!retval) {
+		retval = omap1_clk_enable(clk);
+		omap1_clk_unuse(&api_ck.clk);
+	}
+
+	return retval;
+}
+
+static void omap1_clk_disable_dsp_domain(struct clk *clk)
+{
+	if (omap1_clk_use(&api_ck.clk) == 0) {
+		omap1_clk_disable(clk);
+		omap1_clk_unuse(&api_ck.clk);
+	}
+}
+
+static int omap1_clk_enable_uart_functional(struct clk *clk)
+{
+	int ret;
+	struct uart_clk *uclk;
+
+	ret = omap1_clk_enable(clk);
+	if (ret == 0) {
+		/* Set smart idle acknowledgement mode */
+		uclk = (struct uart_clk *)clk;
+		omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8,
+			    uclk->sysc_addr);
+	}
+
+	return ret;
+}
+
+static void omap1_clk_disable_uart_functional(struct clk *clk)
+{
+	struct uart_clk *uclk;
+
+	/* Set force idle acknowledgement mode */
+	uclk = (struct uart_clk *)clk;
+	omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr);
+
+	omap1_clk_disable(clk);
+}
+
+static void omap1_clk_allow_idle(struct clk *clk)
+{
+	struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
+
+	if (!(clk->flags & CLOCK_IDLE_CONTROL))
+		return;
+
+	if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count))
+		arm_idlect1_mask |= 1 << iclk->idlect_shift;
+}
+
+static void omap1_clk_deny_idle(struct clk *clk)
+{
+	struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
+
+	if (!(clk->flags & CLOCK_IDLE_CONTROL))
+		return;
+
+	if (iclk->no_idle_count++ == 0)
+		arm_idlect1_mask &= ~(1 << iclk->idlect_shift);
+}
+
+static __u16 verify_ckctl_value(__u16 newval)
+{
+	/* This function checks for following limitations set
+	 * by the hardware (all conditions must be true):
+	 * DSPMMU_CK == DSP_CK  or  DSPMMU_CK == DSP_CK/2
+	 * ARM_CK >= TC_CK
+	 * DSP_CK >= TC_CK
+	 * DSPMMU_CK >= TC_CK
+	 *
+	 * In addition following rules are enforced:
+	 * LCD_CK <= TC_CK
+	 * ARMPER_CK <= TC_CK
+	 *
+	 * However, maximum frequencies are not checked for!
+	 */
+	__u8 per_exp;
+	__u8 lcd_exp;
+	__u8 arm_exp;
+	__u8 dsp_exp;
+	__u8 tc_exp;
+	__u8 dspmmu_exp;
+
+	per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3;
+	lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3;
+	arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3;
+	dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3;
+	tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3;
+	dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3;
+
+	if (dspmmu_exp < dsp_exp)
+		dspmmu_exp = dsp_exp;
+	if (dspmmu_exp > dsp_exp+1)
+		dspmmu_exp = dsp_exp+1;
+	if (tc_exp < arm_exp)
+		tc_exp = arm_exp;
+	if (tc_exp < dspmmu_exp)
+		tc_exp = dspmmu_exp;
+	if (tc_exp > lcd_exp)
+		lcd_exp = tc_exp;
+	if (tc_exp > per_exp)
+		per_exp = tc_exp;
+
+	newval &= 0xf000;
+	newval |= per_exp << CKCTL_PERDIV_OFFSET;
+	newval |= lcd_exp << CKCTL_LCDDIV_OFFSET;
+	newval |= arm_exp << CKCTL_ARMDIV_OFFSET;
+	newval |= dsp_exp << CKCTL_DSPDIV_OFFSET;
+	newval |= tc_exp << CKCTL_TCDIV_OFFSET;
+	newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET;
+
+	return newval;
+}
+
+static int calc_dsor_exp(struct clk *clk, unsigned long rate)
+{
+	/* Note: If target frequency is too low, this function will return 4,
+	 * which is invalid value. Caller must check for this value and act
+	 * accordingly.
+	 *
+	 * Note: This function does not check for following limitations set
+	 * by the hardware (all conditions must be true):
+	 * DSPMMU_CK == DSP_CK  or  DSPMMU_CK == DSP_CK/2
+	 * ARM_CK >= TC_CK
+	 * DSP_CK >= TC_CK
+	 * DSPMMU_CK >= TC_CK
+	 */
+	unsigned long realrate;
+	struct clk * parent;
+	unsigned  dsor_exp;
+
+	if (unlikely(!(clk->flags & RATE_CKCTL)))
+		return -EINVAL;
+
+	parent = clk->parent;
+	if (unlikely(parent == 0))
+		return -EIO;
+
+	realrate = parent->rate;
+	for (dsor_exp=0; dsor_exp<4; dsor_exp++) {
+		if (realrate <= rate)
+			break;
+
+		realrate /= 2;
+	}
+
+	return dsor_exp;
+}
+
+static void omap1_ckctl_recalc(struct clk * clk)
+{
+	int dsor;
+
+	/* Calculate divisor encoded as 2-bit exponent */
+	dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
+
+	if (unlikely(clk->rate == clk->parent->rate / dsor))
+		return; /* No change, quick exit */
+	clk->rate = clk->parent->rate / dsor;
+
+	if (unlikely(clk->flags & RATE_PROPAGATES))
+		propagate_rate(clk);
+}
+
+static void omap1_ckctl_recalc_dsp_domain(struct clk * clk)
+{
+	int dsor;
+
+	/* Calculate divisor encoded as 2-bit exponent
+	 *
+	 * The clock control bits are in DSP domain,
+	 * so api_ck is needed for access.
+	 * Note that DSP_CKCTL virt addr = phys addr, so
+	 * we must use __raw_readw() instead of omap_readw().
+	 */
+	omap1_clk_use(&api_ck.clk);
+	dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
+	omap1_clk_unuse(&api_ck.clk);
+
+	if (unlikely(clk->rate == clk->parent->rate / dsor))
+		return; /* No change, quick exit */
+	clk->rate = clk->parent->rate / dsor;
+
+	if (unlikely(clk->flags & RATE_PROPAGATES))
+		propagate_rate(clk);
+}
+
+/* MPU virtual clock functions */
+static int omap1_select_table_rate(struct clk * clk, unsigned long rate)
+{
+	/* Find the highest supported frequency <= rate and switch to it */
+	struct mpu_rate * ptr;
+
+	if (clk != &virtual_ck_mpu)
+		return -EINVAL;
+
+	for (ptr = rate_table; ptr->rate; ptr++) {
+		if (ptr->xtal != ck_ref.rate)
+			continue;
+
+		/* DPLL1 cannot be reprogrammed without risking system crash */
+		if (likely(ck_dpll1.rate!=0) && ptr->pll_rate != ck_dpll1.rate)
+			continue;
+
+		/* Can check only after xtal frequency check */
+		if (ptr->rate <= rate)
+			break;
+	}
+
+	if (!ptr->rate)
+		return -EINVAL;
+
+	/*
+	 * In most cases we should not need to reprogram DPLL.
+	 * Reprogramming the DPLL is tricky, it must be done from SRAM.
+	 */
+	omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
+
+	ck_dpll1.rate = ptr->pll_rate;
+	propagate_rate(&ck_dpll1);
+	return 0;
+}
+
+static int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate)
+{
+	int  ret = -EINVAL;
+	int  dsor_exp;
+	__u16  regval;
+
+	if (clk->flags & RATE_CKCTL) {
+		dsor_exp = calc_dsor_exp(clk, rate);
+		if (dsor_exp > 3)
+			dsor_exp = -EINVAL;
+		if (dsor_exp < 0)
+			return dsor_exp;
+
+		regval = __raw_readw(DSP_CKCTL);
+		regval &= ~(3 << clk->rate_offset);
+		regval |= dsor_exp << clk->rate_offset;
+		__raw_writew(regval, DSP_CKCTL);
+		clk->rate = clk->parent->rate / (1 << dsor_exp);
+		ret = 0;
+	}
+
+	if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
+		propagate_rate(clk);
+
+	return ret;
+}
+
+static long omap1_round_to_table_rate(struct clk * clk, unsigned long rate)
+{
+	/* Find the highest supported frequency <= rate */
+	struct mpu_rate * ptr;
+	long  highest_rate;
+
+	if (clk != &virtual_ck_mpu)
+		return -EINVAL;
+
+	highest_rate = -EINVAL;
+
+	for (ptr = rate_table; ptr->rate; ptr++) {
+		if (ptr->xtal != ck_ref.rate)
+			continue;
+
+		highest_rate = ptr->rate;
+
+		/* Can check only after xtal frequency check */
+		if (ptr->rate <= rate)
+			break;
+	}
+
+	return highest_rate;
+}
+
+static unsigned calc_ext_dsor(unsigned long rate)
+{
+	unsigned dsor;
+
+	/* MCLK and BCLK divisor selection is not linear:
+	 * freq = 96MHz / dsor
+	 *
+	 * RATIO_SEL range: dsor <-> RATIO_SEL
+	 * 0..6: (RATIO_SEL+2) <-> (dsor-2)
+	 * 6..48:  (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6)
+	 * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9
+	 * can not be used.
+	 */
+	for (dsor = 2; dsor < 96; ++dsor) {
+		if ((dsor & 1) && dsor > 8)
+		  	continue;
+		if (rate >= 96000000 / dsor)
+			break;
+	}
+	return dsor;
+}
+
+/* Only needed on 1510 */
+static int omap1_set_uart_rate(struct clk * clk, unsigned long rate)
+{
+	unsigned int val;
+
+	val = omap_readl(clk->enable_reg);
+	if (rate == 12000000)
+		val &= ~(1 << clk->enable_bit);
+	else if (rate == 48000000)
+		val |= (1 << clk->enable_bit);
+	else
+		return -EINVAL;
+	omap_writel(val, clk->enable_reg);
+	clk->rate = rate;
+
+	return 0;
+}
+
+/* External clock (MCLK & BCLK) functions */
+static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate)
+{
+	unsigned dsor;
+	__u16 ratio_bits;
+
+	dsor = calc_ext_dsor(rate);
+	clk->rate = 96000000 / dsor;
+	if (dsor > 8)
+		ratio_bits = ((dsor - 8) / 2 + 6) << 2;
+	else
+		ratio_bits = (dsor - 2) << 2;
+
+	ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd;
+	omap_writew(ratio_bits, clk->enable_reg);
+
+	return 0;
+}
+
+static long omap1_round_ext_clk_rate(struct clk * clk, unsigned long rate)
+{
+	return 96000000 / calc_ext_dsor(rate);
+}
+
+static void omap1_init_ext_clk(struct clk * clk)
+{
+	unsigned dsor;
+	__u16 ratio_bits;
+
+	/* Determine current rate and ensure clock is based on 96MHz APLL */
+	ratio_bits = omap_readw(clk->enable_reg) & ~1;
+	omap_writew(ratio_bits, clk->enable_reg);
+
+	ratio_bits = (ratio_bits & 0xfc) >> 2;
+	if (ratio_bits > 6)
+		dsor = (ratio_bits - 6) * 2 + 8;
+	else
+		dsor = ratio_bits + 2;
+
+	clk-> rate = 96000000 / dsor;
+}
+
+static int omap1_clk_use(struct clk *clk)
+{
+	int ret = 0;
+	if (clk->usecount++ == 0) {
+		if (likely(clk->parent)) {
+			ret = omap1_clk_use(clk->parent);
+
+			if (unlikely(ret != 0)) {
+				clk->usecount--;
+				return ret;
+			}
+
+			if (clk->flags & CLOCK_NO_IDLE_PARENT)
+				if (!cpu_is_omap24xx())
+					omap1_clk_deny_idle(clk->parent);
+		}
+
+		ret = clk->enable(clk);
+
+		if (unlikely(ret != 0) && clk->parent) {
+			omap1_clk_unuse(clk->parent);
+			clk->usecount--;
+		}
+	}
+
+	return ret;
+}
+
+static void omap1_clk_unuse(struct clk *clk)
+{
+	if (clk->usecount > 0 && !(--clk->usecount)) {
+		clk->disable(clk);
+		if (likely(clk->parent)) {
+			omap1_clk_unuse(clk->parent);
+			if (clk->flags & CLOCK_NO_IDLE_PARENT)
+				if (!cpu_is_omap24xx())
+					omap1_clk_allow_idle(clk->parent);
+		}
+	}
+}
+
+static int omap1_clk_enable(struct clk *clk)
+{
+	__u16 regval16;
+	__u32 regval32;
+
+	if (clk->flags & ALWAYS_ENABLED)
+		return 0;
+
+	if (unlikely(clk->enable_reg == 0)) {
+		printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
+		       clk->name);
+		return 0;
+	}
+
+	if (clk->flags & ENABLE_REG_32BIT) {
+		if (clk->flags & VIRTUAL_IO_ADDRESS) {
+			regval32 = __raw_readl(clk->enable_reg);
+			regval32 |= (1 << clk->enable_bit);
+			__raw_writel(regval32, clk->enable_reg);
+		} else {
+			regval32 = omap_readl(clk->enable_reg);
+			regval32 |= (1 << clk->enable_bit);
+			omap_writel(regval32, clk->enable_reg);
+		}
+	} else {
+		if (clk->flags & VIRTUAL_IO_ADDRESS) {
+			regval16 = __raw_readw(clk->enable_reg);
+			regval16 |= (1 << clk->enable_bit);
+			__raw_writew(regval16, clk->enable_reg);
+		} else {
+			regval16 = omap_readw(clk->enable_reg);
+			regval16 |= (1 << clk->enable_bit);
+			omap_writew(regval16, clk->enable_reg);
+		}
+	}
+
+	return 0;
+}
+
+static void omap1_clk_disable(struct clk *clk)
+{
+	__u16 regval16;
+	__u32 regval32;
+
+	if (clk->enable_reg == 0)
+		return;
+
+	if (clk->flags & ENABLE_REG_32BIT) {
+		if (clk->flags & VIRTUAL_IO_ADDRESS) {
+			regval32 = __raw_readl(clk->enable_reg);
+			regval32 &= ~(1 << clk->enable_bit);
+			__raw_writel(regval32, clk->enable_reg);
+		} else {
+			regval32 = omap_readl(clk->enable_reg);
+			regval32 &= ~(1 << clk->enable_bit);
+			omap_writel(regval32, clk->enable_reg);
+		}
+	} else {
+		if (clk->flags & VIRTUAL_IO_ADDRESS) {
+			regval16 = __raw_readw(clk->enable_reg);
+			regval16 &= ~(1 << clk->enable_bit);
+			__raw_writew(regval16, clk->enable_reg);
+		} else {
+			regval16 = omap_readw(clk->enable_reg);
+			regval16 &= ~(1 << clk->enable_bit);
+			omap_writew(regval16, clk->enable_reg);
+		}
+	}
+}
+
+static long omap1_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	int dsor_exp;
+
+	if (clk->flags & RATE_FIXED)
+		return clk->rate;
+
+	if (clk->flags & RATE_CKCTL) {
+		dsor_exp = calc_dsor_exp(clk, rate);
+		if (dsor_exp < 0)
+			return dsor_exp;
+		if (dsor_exp > 3)
+			dsor_exp = 3;
+		return clk->parent->rate / (1 << dsor_exp);
+	}
+
+	if(clk->round_rate != 0)
+		return clk->round_rate(clk, rate);
+
+	return clk->rate;
+}
+
+static int omap1_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int  ret = -EINVAL;
+	int  dsor_exp;
+	__u16  regval;
+
+	if (clk->set_rate)
+		ret = clk->set_rate(clk, rate);
+	else if (clk->flags & RATE_CKCTL) {
+		dsor_exp = calc_dsor_exp(clk, rate);
+		if (dsor_exp > 3)
+			dsor_exp = -EINVAL;
+		if (dsor_exp < 0)
+			return dsor_exp;
+
+		regval = omap_readw(ARM_CKCTL);
+		regval &= ~(3 << clk->rate_offset);
+		regval |= dsor_exp << clk->rate_offset;
+		regval = verify_ckctl_value(regval);
+		omap_writew(regval, ARM_CKCTL);
+		clk->rate = clk->parent->rate / (1 << dsor_exp);
+		ret = 0;
+	}
+
+	if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
+		propagate_rate(clk);
+
+	return ret;
+}
+
+/*-------------------------------------------------------------------------
+ * Omap1 clock reset and init functions
+ *-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+/*
+ * Resets some clocks that may be left on from bootloader,
+ * but leaves serial clocks on. See also omap_late_clk_reset().
+ */
+static inline void omap1_early_clk_reset(void)
+{
+	//omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
+}
+
+static int __init omap1_late_clk_reset(void)
+{
+	/* Turn off all unused clocks */
+	struct clk *p;
+	__u32 regval32;
+
+	/* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
+	regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4);
+	omap_writew(regval32, SOFT_REQ_REG);
+	omap_writew(0, SOFT_REQ_REG2);
+
+	list_for_each_entry(p, &clocks, node) {
+		if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) ||
+			p->enable_reg == 0)
+			continue;
+
+		/* Clocks in the DSP domain need api_ck. Just assume bootloader
+		 * has not enabled any DSP clocks */
+		if ((u32)p->enable_reg == DSP_IDLECT2) {
+			printk(KERN_INFO "Skipping reset check for DSP domain "
+			       "clock \"%s\"\n", p->name);
+			continue;
+		}
+
+		/* Is the clock already disabled? */
+		if (p->flags & ENABLE_REG_32BIT) {
+			if (p->flags & VIRTUAL_IO_ADDRESS)
+				regval32 = __raw_readl(p->enable_reg);
+			else
+				regval32 = omap_readl(p->enable_reg);
+		} else {
+			if (p->flags & VIRTUAL_IO_ADDRESS)
+				regval32 = __raw_readw(p->enable_reg);
+			else
+				regval32 = omap_readw(p->enable_reg);
+		}
+
+		if ((regval32 & (1 << p->enable_bit)) == 0)
+			continue;
+
+		/* FIXME: This clock seems to be necessary but no-one
+		 * has asked for its activation. */
+		if (p == &tc2_ck         // FIX: pm.c (SRAM), CCP, Camera
+		    || p == &ck_dpll1out.clk // FIX: SoSSI, SSR
+		    || p == &arm_gpio_ck // FIX: GPIO code for 1510
+		    ) {
+			printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
+			       p->name);
+			continue;
+		}
+
+		printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name);
+		p->disable(p);
+		printk(" done\n");
+	}
+
+	return 0;
+}
+late_initcall(omap1_late_clk_reset);
+
+#else
+#define omap1_early_clk_reset()	{}
+#endif
+
+static struct clk_functions omap1_clk_functions = {
+	.clk_use		= omap1_clk_use,
+	.clk_unuse		= omap1_clk_unuse,
+	.clk_round_rate		= omap1_clk_round_rate,
+	.clk_set_rate		= omap1_clk_set_rate,
+};
+
+int __init omap1_clk_init(void)
+{
+	struct clk ** clkp;
+	const struct omap_clock_config *info;
+	int crystal_type = 0; /* Default 12 MHz */
+
+	omap1_early_clk_reset();
+	clk_init(&omap1_clk_functions);
+
+	/* By default all idlect1 clocks are allowed to idle */
+	arm_idlect1_mask = ~0;
+
+	for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
+		if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) {
+			clk_register(*clkp);
+			continue;
+		}
+
+		if (((*clkp)->flags &CLOCK_IN_OMAP16XX) && cpu_is_omap16xx()) {
+			clk_register(*clkp);
+			continue;
+		}
+
+		if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) {
+			clk_register(*clkp);
+			continue;
+		}
+	}
+
+	info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config);
+	if (info != NULL) {
+		if (!cpu_is_omap1510())
+			crystal_type = info->system_clock_type;
+	}
+
+#if defined(CONFIG_ARCH_OMAP730)
+	ck_ref.rate = 13000000;
+#elif defined(CONFIG_ARCH_OMAP16XX)
+	if (crystal_type == 2)
+		ck_ref.rate = 19200000;
+#endif
+
+	printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n",
+	       omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
+	       omap_readw(ARM_CKCTL));
+
+	/* We want to be in syncronous scalable mode */
+	omap_writew(0x1000, ARM_SYSST);
+
+#ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER
+	/* Use values set by bootloader. Determine PLL rate and recalculate
+	 * dependent clocks as if kernel had changed PLL or divisors.
+	 */
+	{
+		unsigned pll_ctl_val = omap_readw(DPLL_CTL);
+
+		ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */
+		if (pll_ctl_val & 0x10) {
+			/* PLL enabled, apply multiplier and divisor */
+			if (pll_ctl_val & 0xf80)
+				ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7;
+			ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1;
+		} else {
+			/* PLL disabled, apply bypass divisor */
+			switch (pll_ctl_val & 0xc) {
+			case 0:
+				break;
+			case 0x4:
+				ck_dpll1.rate /= 2;
+				break;
+			default:
+				ck_dpll1.rate /= 4;
+				break;
+			}
+		}
+	}
+	propagate_rate(&ck_dpll1);
+#else
+	/* Find the highest supported frequency and enable it */
+	if (omap1_select_table_rate(&virtual_ck_mpu, ~0)) {
+		printk(KERN_ERR "System frequencies not set. Check your config.\n");
+		/* Guess sane values (60MHz) */
+		omap_writew(0x2290, DPLL_CTL);
+		omap_writew(0x1005, ARM_CKCTL);
+		ck_dpll1.rate = 60000000;
+		propagate_rate(&ck_dpll1);
+	}
+#endif
+	/* Cache rates for clocks connected to ck_ref (not dpll1) */
+	propagate_rate(&ck_ref);
+	printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): "
+		"%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
+	       ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
+	       ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10,
+	       arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10);
+
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+	/* Select slicer output as OMAP input clock */
+	omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);
+#endif
+
+	/* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
+	omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL);
+
+	/* Put DSP/MPUI into reset until needed */
+	omap_writew(0, ARM_RSTCT1);
+	omap_writew(1, ARM_RSTCT2);
+	omap_writew(0x400, ARM_IDLECT1);
+
+	/*
+	 * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8)
+	 * of the ARM_IDLECT2 register must be set to zero. The power-on
+	 * default value of this bit is one.
+	 */
+	omap_writew(0x0000, ARM_IDLECT2);	/* Turn LCD clock off also */
+
+	/*
+	 * Only enable those clocks we will need, let the drivers
+	 * enable other clocks as necessary
+	 */
+	clk_use(&armper_ck.clk);
+	clk_use(&armxor_ck.clk);
+	clk_use(&armtim_ck.clk); /* This should be done by timer code */
+
+	if (cpu_is_omap1510())
+		clk_enable(&arm_gpio_ck);
+
+	return 0;
+}
+
diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h
new file mode 100644
index 0000000..f3bdfb5
--- /dev/null
+++ b/arch/arm/mach-omap1/clock.h
@@ -0,0 +1,768 @@
+/*
+ *  linux/arch/arm/mach-omap1/clock.h
+ *
+ *  Copyright (C) 2004 - 2005 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *  Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, 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 __ARCH_ARM_MACH_OMAP1_CLOCK_H
+#define __ARCH_ARM_MACH_OMAP1_CLOCK_H
+
+static int omap1_clk_enable(struct clk * clk);
+static void omap1_clk_disable(struct clk * clk);
+static void omap1_ckctl_recalc(struct clk * clk);
+static void omap1_watchdog_recalc(struct clk * clk);
+static void omap1_ckctl_recalc_dsp_domain(struct clk * clk);
+static int omap1_clk_enable_dsp_domain(struct clk * clk);
+static int omap1_clk_set_rate_dsp_domain(struct clk * clk, unsigned long rate);
+static void omap1_clk_disable_dsp_domain(struct clk * clk);
+static int omap1_set_uart_rate(struct clk * clk, unsigned long rate);
+static void omap1_uart_recalc(struct clk * clk);
+static int omap1_clk_enable_uart_functional(struct clk * clk);
+static void omap1_clk_disable_uart_functional(struct clk * clk);
+static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate);
+static long omap1_round_ext_clk_rate(struct clk * clk, unsigned long rate);
+static void omap1_init_ext_clk(struct clk * clk);
+static int omap1_select_table_rate(struct clk * clk, unsigned long rate);
+static long omap1_round_to_table_rate(struct clk * clk, unsigned long rate);
+static int omap1_clk_use(struct clk *clk);
+static void omap1_clk_unuse(struct clk *clk);
+
+struct mpu_rate {
+	unsigned long		rate;
+	unsigned long		xtal;
+	unsigned long		pll_rate;
+	__u16			ckctl_val;
+	__u16			dpllctl_val;
+};
+
+struct uart_clk {
+	struct clk	clk;
+	unsigned long	sysc_addr;
+};
+
+/* Provide a method for preventing idling some ARM IDLECT clocks */
+struct arm_idlect1_clk {
+	struct clk	clk;
+	unsigned long	no_idle_count;
+	__u8		idlect_shift;
+};
+
+/* ARM_CKCTL bit shifts */
+#define CKCTL_PERDIV_OFFSET	0
+#define CKCTL_LCDDIV_OFFSET	2
+#define CKCTL_ARMDIV_OFFSET	4
+#define CKCTL_DSPDIV_OFFSET	6
+#define CKCTL_TCDIV_OFFSET	8
+#define CKCTL_DSPMMUDIV_OFFSET	10
+/*#define ARM_TIMXO		12*/
+#define EN_DSPCK		13
+/*#define ARM_INTHCK_SEL	14*/ /* Divide-by-2 for mpu inth_ck */
+/* DSP_CKCTL bit shifts */
+#define CKCTL_DSPPERDIV_OFFSET	0
+
+/* ARM_IDLECT2 bit shifts */
+#define EN_WDTCK	0
+#define EN_XORPCK	1
+#define EN_PERCK	2
+#define EN_LCDCK	3
+#define EN_LBCK		4 /* Not on 1610/1710 */
+/*#define EN_HSABCK	5*/
+#define EN_APICK	6
+#define EN_TIMCK	7
+#define DMACK_REQ	8
+#define EN_GPIOCK	9 /* Not on 1610/1710 */
+/*#define EN_LBFREECK	10*/
+#define EN_CKOUT_ARM	11
+
+/* ARM_IDLECT3 bit shifts */
+#define EN_OCPI_CK	0
+#define EN_TC1_CK	2
+#define EN_TC2_CK	4
+
+/* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */
+#define EN_DSPTIMCK	5
+
+/* Various register defines for clock controls scattered around OMAP chip */
+#define USB_MCLK_EN_BIT		4	/* In ULPD_CLKC_CTRL */
+#define USB_HOST_HHC_UHOST_EN	9	/* In MOD_CONF_CTRL_0 */
+#define SWD_ULPD_PLL_CLK_REQ	1	/* In SWD_CLK_DIV_CTRL_SEL */
+#define COM_ULPD_PLL_CLK_REQ	1	/* In COM_CLK_DIV_CTRL_SEL */
+#define SWD_CLK_DIV_CTRL_SEL	0xfffe0874
+#define COM_CLK_DIV_CTRL_SEL	0xfffe0878
+#define SOFT_REQ_REG		0xfffe0834
+#define SOFT_REQ_REG2		0xfffe0880
+
+/*-------------------------------------------------------------------------
+ * Omap1 MPU rate table
+ *-------------------------------------------------------------------------*/
+static struct mpu_rate rate_table[] = {
+	/* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
+	 * NOTE: Comment order here is different from bits in CKCTL value:
+	 * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
+	 */
+#if defined(CONFIG_OMAP_ARM_216MHZ)
+	{ 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_195MHZ)
+	{ 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_192MHZ)
+	{ 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */
+	{ 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */
+	{  96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */
+	{  48000000, 12000000, 192000000, 0x0baf, 0x2810 }, /* 4/4/4/8/8/8 */
+	{  24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_182MHZ)
+	{ 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_168MHZ)
+	{ 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_150MHZ)
+	{ 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */
+#endif
+#if defined(CONFIG_OMAP_ARM_120MHZ)
+	{ 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
+#endif
+#if defined(CONFIG_OMAP_ARM_96MHZ)
+	{  96000000, 12000000,  96000000, 0x0005, 0x2410 }, /* 1/1/1/1/2/2 */
+#endif
+#if defined(CONFIG_OMAP_ARM_60MHZ)
+	{  60000000, 12000000,  60000000, 0x0005, 0x2290 }, /* 1/1/1/1/2/2 */
+#endif
+#if defined(CONFIG_OMAP_ARM_30MHZ)
+	{  30000000, 12000000,  60000000, 0x0555, 0x2290 }, /* 2/2/2/2/2/2 */
+#endif
+	{ 0, 0, 0, 0, 0 },
+};
+
+/*-------------------------------------------------------------------------
+ * Omap1 clocks
+ *-------------------------------------------------------------------------*/
+
+static struct clk ck_ref = {
+	.name		= "ck_ref",
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  ALWAYS_ENABLED,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk ck_dpll1 = {
+	.name		= "ck_dpll1",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_PROPAGATES | ALWAYS_ENABLED,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct arm_idlect1_clk ck_dpll1out = {
+	.clk = {
+	       	.name		= "ck_dpll1out",
+		.parent		= &ck_dpll1,
+		.flags		= CLOCK_IN_OMAP16XX | CLOCK_IDLE_CONTROL,
+		.enable_reg	= (void __iomem *)ARM_IDLECT2,
+		.enable_bit	= EN_CKOUT_ARM,
+		.recalc		= &followparent_recalc,
+		.enable		= &omap1_clk_enable,
+		.disable	= &omap1_clk_disable,
+	},
+	.idlect_shift	= 12,
+};
+
+static struct clk arm_ck = {
+	.name		= "arm_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
+	.rate_offset	= CKCTL_ARMDIV_OFFSET,
+	.recalc		= &omap1_ckctl_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct arm_idlect1_clk armper_ck = {
+	.clk = {
+		.name		= "armper_ck",
+		.parent		= &ck_dpll1,
+		.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+				  RATE_CKCTL | CLOCK_IDLE_CONTROL,
+		.enable_reg	= (void __iomem *)ARM_IDLECT2,
+		.enable_bit	= EN_PERCK,
+		.rate_offset	= CKCTL_PERDIV_OFFSET,
+		.recalc		= &omap1_ckctl_recalc,
+		.enable		= &omap1_clk_enable,
+		.disable	= &omap1_clk_disable,
+	},
+	.idlect_shift	= 2,
+};
+
+static struct clk arm_gpio_ck = {
+	.name		= "arm_gpio_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510,
+	.enable_reg	= (void __iomem *)ARM_IDLECT2,
+	.enable_bit	= EN_GPIOCK,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct arm_idlect1_clk armxor_ck = {
+	.clk = {
+		.name		= "armxor_ck",
+		.parent		= &ck_ref,
+		.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+				  CLOCK_IDLE_CONTROL,
+		.enable_reg	= (void __iomem *)ARM_IDLECT2,
+		.enable_bit	= EN_XORPCK,
+		.recalc		= &followparent_recalc,
+		.enable		= &omap1_clk_enable,
+		.disable	= &omap1_clk_disable,
+	},
+	.idlect_shift	= 1,
+};
+
+static struct arm_idlect1_clk armtim_ck = {
+	.clk = {
+		.name		= "armtim_ck",
+		.parent		= &ck_ref,
+		.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+				  CLOCK_IDLE_CONTROL,
+		.enable_reg	= (void __iomem *)ARM_IDLECT2,
+		.enable_bit	= EN_TIMCK,
+		.recalc		= &followparent_recalc,
+		.enable		= &omap1_clk_enable,
+		.disable	= &omap1_clk_disable,
+	},
+	.idlect_shift	= 9,
+};
+
+static struct arm_idlect1_clk armwdt_ck = {
+	.clk = {
+		.name		= "armwdt_ck",
+		.parent		= &ck_ref,
+		.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+				  CLOCK_IDLE_CONTROL,
+		.enable_reg	= (void __iomem *)ARM_IDLECT2,
+		.enable_bit	= EN_WDTCK,
+		.recalc		= &omap1_watchdog_recalc,
+		.enable		= &omap1_clk_enable,
+		.disable	= &omap1_clk_disable,
+	},
+	.idlect_shift	= 0,
+};
+
+static struct clk arminth_ck16xx = {
+	.name		= "arminth_ck",
+	.parent		= &arm_ck,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+	.recalc		= &followparent_recalc,
+	/* Note: On 16xx the frequency can be divided by 2 by programming
+	 * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
+	 *
+	 * 1510 version is in TC clocks.
+	 */
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk dsp_ck = {
+	.name		= "dsp_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL,
+	.enable_reg	= (void __iomem *)ARM_CKCTL,
+	.enable_bit	= EN_DSPCK,
+	.rate_offset	= CKCTL_DSPDIV_OFFSET,
+	.recalc		= &omap1_ckctl_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk dspmmu_ck = {
+	.name		= "dspmmu_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL | ALWAYS_ENABLED,
+	.rate_offset	= CKCTL_DSPMMUDIV_OFFSET,
+	.recalc		= &omap1_ckctl_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk dspper_ck = {
+	.name		= "dspper_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL | VIRTUAL_IO_ADDRESS,
+	.enable_reg	= (void __iomem *)DSP_IDLECT2,
+	.enable_bit	= EN_PERCK,
+	.rate_offset	= CKCTL_PERDIV_OFFSET,
+	.recalc		= &omap1_ckctl_recalc_dsp_domain,
+	.set_rate	= &omap1_clk_set_rate_dsp_domain,
+	.enable		= &omap1_clk_enable_dsp_domain,
+	.disable	= &omap1_clk_disable_dsp_domain,
+};
+
+static struct clk dspxor_ck = {
+	.name		= "dspxor_ck",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  VIRTUAL_IO_ADDRESS,
+	.enable_reg	= (void __iomem *)DSP_IDLECT2,
+	.enable_bit	= EN_XORPCK,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable_dsp_domain,
+	.disable	= &omap1_clk_disable_dsp_domain,
+};
+
+static struct clk dsptim_ck = {
+	.name		= "dsptim_ck",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  VIRTUAL_IO_ADDRESS,
+	.enable_reg	= (void __iomem *)DSP_IDLECT2,
+	.enable_bit	= EN_DSPTIMCK,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable_dsp_domain,
+	.disable	= &omap1_clk_disable_dsp_domain,
+};
+
+/* Tie ARM_IDLECT1:IDLIF_ARM to this logical clock structure */
+static struct arm_idlect1_clk tc_ck = {
+	.clk = {
+		.name		= "tc_ck",
+		.parent		= &ck_dpll1,
+		.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+				  CLOCK_IN_OMAP730 | RATE_CKCTL |
+				  RATE_PROPAGATES | ALWAYS_ENABLED |
+				  CLOCK_IDLE_CONTROL,
+		.rate_offset	= CKCTL_TCDIV_OFFSET,
+		.recalc		= &omap1_ckctl_recalc,
+		.enable		= &omap1_clk_enable,
+		.disable	= &omap1_clk_disable,
+	},
+	.idlect_shift	= 6,
+};
+
+static struct clk arminth_ck1510 = {
+	.name		= "arminth_ck",
+	.parent		= &tc_ck.clk,
+	.flags		= CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
+	.recalc		= &followparent_recalc,
+	/* Note: On 1510 the frequency follows TC_CK
+	 *
+	 * 16xx version is in MPU clocks.
+	 */
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk tipb_ck = {
+	/* No-idle controlled by "tc_ck" */
+	.name		= "tibp_ck",
+	.parent		= &tc_ck.clk,
+	.flags		= CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk l3_ocpi_ck = {
+	/* No-idle controlled by "tc_ck" */
+	.name		= "l3_ocpi_ck",
+	.parent		= &tc_ck.clk,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= (void __iomem *)ARM_IDLECT3,
+	.enable_bit	= EN_OCPI_CK,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk tc1_ck = {
+	.name		= "tc1_ck",
+	.parent		= &tc_ck.clk,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= (void __iomem *)ARM_IDLECT3,
+	.enable_bit	= EN_TC1_CK,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk tc2_ck = {
+	.name		= "tc2_ck",
+	.parent		= &tc_ck.clk,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= (void __iomem *)ARM_IDLECT3,
+	.enable_bit	= EN_TC2_CK,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk dma_ck = {
+	/* No-idle controlled by "tc_ck" */
+	.name		= "dma_ck",
+	.parent		= &tc_ck.clk,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  ALWAYS_ENABLED,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk dma_lcdfree_ck = {
+	.name		= "dma_lcdfree_ck",
+	.parent		= &tc_ck.clk,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct arm_idlect1_clk api_ck = {
+	.clk = {
+		.name		= "api_ck",
+		.parent		= &tc_ck.clk,
+		.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+				  CLOCK_IDLE_CONTROL,
+		.enable_reg	= (void __iomem *)ARM_IDLECT2,
+		.enable_bit	= EN_APICK,
+		.recalc		= &followparent_recalc,
+		.enable		= &omap1_clk_enable,
+		.disable	= &omap1_clk_disable,
+	},
+	.idlect_shift	= 8,
+};
+
+static struct arm_idlect1_clk lb_ck = {
+	.clk = {
+		.name		= "lb_ck",
+		.parent		= &tc_ck.clk,
+		.flags		= CLOCK_IN_OMAP1510 | CLOCK_IDLE_CONTROL,
+		.enable_reg	= (void __iomem *)ARM_IDLECT2,
+		.enable_bit	= EN_LBCK,
+		.recalc		= &followparent_recalc,
+		.enable		= &omap1_clk_enable,
+		.disable	= &omap1_clk_disable,
+	},
+	.idlect_shift	= 4,
+};
+
+static struct clk rhea1_ck = {
+	.name		= "rhea1_ck",
+	.parent		= &tc_ck.clk,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk rhea2_ck = {
+	.name		= "rhea2_ck",
+	.parent		= &tc_ck.clk,
+	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+	.recalc		= &followparent_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk lcd_ck_16xx = {
+	.name		= "lcd_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | RATE_CKCTL,
+	.enable_reg	= (void __iomem *)ARM_IDLECT2,
+	.enable_bit	= EN_LCDCK,
+	.rate_offset	= CKCTL_LCDDIV_OFFSET,
+	.recalc		= &omap1_ckctl_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct arm_idlect1_clk lcd_ck_1510 = {
+	.clk = {
+		.name		= "lcd_ck",
+		.parent		= &ck_dpll1,
+		.flags		= CLOCK_IN_OMAP1510 | RATE_CKCTL |
+				  CLOCK_IDLE_CONTROL,
+		.enable_reg	= (void __iomem *)ARM_IDLECT2,
+		.enable_bit	= EN_LCDCK,
+		.rate_offset	= CKCTL_LCDDIV_OFFSET,
+		.recalc		= &omap1_ckctl_recalc,
+		.enable		= &omap1_clk_enable,
+		.disable	= &omap1_clk_disable,
+	},
+	.idlect_shift	= 3,
+};
+
+static struct clk uart1_1510 = {
+	.name		= "uart1_ck",
+	/* Direct from ULPD, no real parent */
+	.parent		= &armper_ck.clk,
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT |
+			  ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
+	.enable_reg	= (void __iomem *)MOD_CONF_CTRL_0,
+	.enable_bit	= 29,	/* Chooses between 12MHz and 48MHz */
+	.set_rate	= &omap1_set_uart_rate,
+	.recalc		= &omap1_uart_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct uart_clk uart1_16xx = {
+	.clk	= {
+		.name		= "uart1_ck",
+		/* Direct from ULPD, no real parent */
+		.parent		= &armper_ck.clk,
+		.rate		= 48000000,
+		.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED |
+				  ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+		.enable_reg	= (void __iomem *)MOD_CONF_CTRL_0,
+		.enable_bit	= 29,
+		.enable		= &omap1_clk_enable_uart_functional,
+		.disable	= &omap1_clk_disable_uart_functional,
+	},
+	.sysc_addr	= 0xfffb0054,
+};
+
+static struct clk uart2_ck = {
+	.name		= "uart2_ck",
+	/* Direct from ULPD, no real parent */
+	.parent		= &armper_ck.clk,
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  ENABLE_REG_32BIT | ALWAYS_ENABLED |
+			  CLOCK_NO_IDLE_PARENT,
+	.enable_reg	= (void __iomem *)MOD_CONF_CTRL_0,
+	.enable_bit	= 30,	/* Chooses between 12MHz and 48MHz */
+	.set_rate	= &omap1_set_uart_rate,
+	.recalc		= &omap1_uart_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk uart3_1510 = {
+	.name		= "uart3_ck",
+	/* Direct from ULPD, no real parent */
+	.parent		= &armper_ck.clk,
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT |
+			  ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
+	.enable_reg	= (void __iomem *)MOD_CONF_CTRL_0,
+	.enable_bit	= 31,	/* Chooses between 12MHz and 48MHz */
+	.set_rate	= &omap1_set_uart_rate,
+	.recalc		= &omap1_uart_recalc,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct uart_clk uart3_16xx = {
+	.clk	= {
+		.name		= "uart3_ck",
+		/* Direct from ULPD, no real parent */
+		.parent		= &armper_ck.clk,
+		.rate		= 48000000,
+		.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED |
+				  ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+		.enable_reg	= (void __iomem *)MOD_CONF_CTRL_0,
+		.enable_bit	= 31,
+		.enable		= &omap1_clk_enable_uart_functional,
+		.disable	= &omap1_clk_disable_uart_functional,
+	},
+	.sysc_addr	= 0xfffb9854,
+};
+
+static struct clk usb_clko = {	/* 6 MHz output on W4_USB_CLKO */
+	.name		= "usb_clko",
+	/* Direct from ULPD, no parent */
+	.rate		= 6000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= (void __iomem *)ULPD_CLOCK_CTRL,
+	.enable_bit	= USB_MCLK_EN_BIT,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk usb_hhc_ck1510 = {
+	.name		= "usb_hhc_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
+	.flags		= CLOCK_IN_OMAP1510 |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= (void __iomem *)MOD_CONF_CTRL_0,
+	.enable_bit	= USB_HOST_HHC_UHOST_EN,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk usb_hhc_ck16xx = {
+	.name		= "usb_hhc_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 48000000,
+	/* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
+	.flags		= CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= (void __iomem *)OTG_BASE + 0x08 /* OTG_SYSCON_2 */,
+	.enable_bit	= 8 /* UHOST_EN */,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk usb_dc_ck = {
+	.name		= "usb_dc_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 48000000,
+	.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED,
+	.enable_reg	= (void __iomem *)SOFT_REQ_REG,
+	.enable_bit	= 4,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk mclk_1510 = {
+	.name		= "mclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk mclk_16xx = {
+	.name		= "mclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= (void __iomem *)COM_CLK_DIV_CTRL_SEL,
+	.enable_bit	= COM_ULPD_PLL_CLK_REQ,
+	.set_rate	= &omap1_set_ext_clk_rate,
+	.round_rate	= &omap1_round_ext_clk_rate,
+	.init		= &omap1_init_ext_clk,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk bclk_1510 = {
+	.name		= "bclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk bclk_16xx = {
+	.name		= "bclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= (void __iomem *)SWD_CLK_DIV_CTRL_SEL,
+	.enable_bit	= SWD_ULPD_PLL_CLK_REQ,
+	.set_rate	= &omap1_set_ext_clk_rate,
+	.round_rate	= &omap1_round_ext_clk_rate,
+	.init		= &omap1_init_ext_clk,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk mmc1_ck = {
+	.name		= "mmc1_ck",
+	/* Functional clock is direct from ULPD, interface clock is ARMPER */
+	.parent		= &armper_ck.clk,
+	.rate		= 48000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+	.enable_reg	= (void __iomem *)MOD_CONF_CTRL_0,
+	.enable_bit	= 23,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk mmc2_ck = {
+	.name		= "mmc2_ck",
+	/* Functional clock is direct from ULPD, interface clock is ARMPER */
+	.parent		= &armper_ck.clk,
+	.rate		= 48000000,
+	.flags		= CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+	.enable_reg	= (void __iomem *)MOD_CONF_CTRL_0,
+	.enable_bit	= 20,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk virtual_ck_mpu = {
+	.name		= "mpu",
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  VIRTUAL_CLOCK | ALWAYS_ENABLED,
+	.parent		= &arm_ck, /* Is smarter alias for */
+	.recalc		= &followparent_recalc,
+	.set_rate	= &omap1_select_table_rate,
+	.round_rate	= &omap1_round_to_table_rate,
+	.enable		= &omap1_clk_enable,
+	.disable	= &omap1_clk_disable,
+};
+
+static struct clk * onchip_clks[] = {
+	/* non-ULPD clocks */
+	&ck_ref,
+	&ck_dpll1,
+	/* CK_GEN1 clocks */
+	&ck_dpll1out.clk,
+	&arm_ck,
+	&armper_ck.clk,
+	&arm_gpio_ck,
+	&armxor_ck.clk,
+	&armtim_ck.clk,
+	&armwdt_ck.clk,
+	&arminth_ck1510,  &arminth_ck16xx,
+	/* CK_GEN2 clocks */
+	&dsp_ck,
+	&dspmmu_ck,
+	&dspper_ck,
+	&dspxor_ck,
+	&dsptim_ck,
+	/* CK_GEN3 clocks */
+	&tc_ck.clk,
+	&tipb_ck,
+	&l3_ocpi_ck,
+	&tc1_ck,
+	&tc2_ck,
+	&dma_ck,
+	&dma_lcdfree_ck,
+	&api_ck.clk,
+	&lb_ck.clk,
+	&rhea1_ck,
+	&rhea2_ck,
+	&lcd_ck_16xx,
+	&lcd_ck_1510.clk,
+	/* ULPD clocks */
+	&uart1_1510,
+	&uart1_16xx.clk,
+	&uart2_ck,
+	&uart3_1510,
+	&uart3_16xx.clk,
+	&usb_clko,
+	&usb_hhc_ck1510, &usb_hhc_ck16xx,
+	&usb_dc_ck,
+	&mclk_1510,  &mclk_16xx,
+	&bclk_1510,  &bclk_16xx,
+	&mmc1_ck,
+	&mmc2_ck,
+	/* Virtual clocks */
+	&virtual_ck_mpu,
+};
+
+#endif
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 3c5d901..ecbc475 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -25,56 +25,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/gpio.h>
 
-
-static void omap_nop_release(struct device *dev)
-{
-        /* Nothing */
-}
-
-/*-------------------------------------------------------------------------*/
-
-#if	defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
-
-#define	OMAP_I2C_BASE		0xfffb3800
-
-static struct resource i2c_resources[] = {
-	{
-		.start		= OMAP_I2C_BASE,
-		.end		= OMAP_I2C_BASE + 0x3f,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= INT_I2C,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-/* DMA not used; works around erratum writing to non-empty i2c fifo */
-
-static struct platform_device omap_i2c_device = {
-        .name           = "i2c_omap",
-        .id             = -1,
-        .dev = {
-                .release        = omap_nop_release,
-        },
-	.num_resources	= ARRAY_SIZE(i2c_resources),
-	.resource	= i2c_resources,
-};
-
-static void omap_init_i2c(void)
-{
-	/* FIXME define and use a boot tag, in case of boards that
-	 * either don't wire up I2C, or chips that mux it differently...
-	 * it can include clocking and address info, maybe more.
-	 */
-	omap_cfg_reg(I2C_SCL);
-	omap_cfg_reg(I2C_SDA);
-
-	(void) platform_device_register(&omap_i2c_device);
-}
-#else
-static inline void omap_init_i2c(void) {}
-#endif
+extern void omap_nop_release(struct device *dev);
 
 /*-------------------------------------------------------------------------*/
 
@@ -110,137 +61,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-#if	defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
-
-#define	OMAP_MMC1_BASE		0xfffb7800
-#define	OMAP_MMC2_BASE		0xfffb7c00	/* omap16xx only */
-
-static struct omap_mmc_conf mmc1_conf;
-
-static u64 mmc1_dmamask = 0xffffffff;
-
-static struct resource mmc1_resources[] = {
-	{
-		.start		= IO_ADDRESS(OMAP_MMC1_BASE),
-		.end		= IO_ADDRESS(OMAP_MMC1_BASE) + 0x7f,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= INT_MMC,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device mmc_omap_device1 = {
-	.name		= "mmci-omap",
-	.id		= 1,
-	.dev = {
-		.release	= omap_nop_release,
-		.dma_mask	= &mmc1_dmamask,
-		.platform_data	= &mmc1_conf,
-	},
-	.num_resources	= ARRAY_SIZE(mmc1_resources),
-	.resource	= mmc1_resources,
-};
-
-#ifdef	CONFIG_ARCH_OMAP16XX
-
-static struct omap_mmc_conf mmc2_conf;
-
-static u64 mmc2_dmamask = 0xffffffff;
-
-static struct resource mmc2_resources[] = {
-	{
-		.start		= IO_ADDRESS(OMAP_MMC2_BASE),
-		.end		= IO_ADDRESS(OMAP_MMC2_BASE) + 0x7f,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= INT_1610_MMC2,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device mmc_omap_device2 = {
-	.name		= "mmci-omap",
-	.id		= 2,
-	.dev = {
-		.release	= omap_nop_release,
-		.dma_mask	= &mmc2_dmamask,
-		.platform_data	= &mmc2_conf,
-	},
-	.num_resources	= ARRAY_SIZE(mmc2_resources),
-	.resource	= mmc2_resources,
-};
-#endif
-
-static void __init omap_init_mmc(void)
-{
-	const struct omap_mmc_config	*mmc_conf;
-	const struct omap_mmc_conf	*mmc;
-
-	/* NOTE:  assumes MMC was never (wrongly) enabled */
-	mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config);
-	if (!mmc_conf)
-		return;
-
-	/* block 1 is always available and has just one pinout option */
-	mmc = &mmc_conf->mmc[0];
-	if (mmc->enabled) {
-		omap_cfg_reg(MMC_CMD);
-		omap_cfg_reg(MMC_CLK);
-		omap_cfg_reg(MMC_DAT0);
-		if (cpu_is_omap1710()) {
-	              omap_cfg_reg(M15_1710_MMC_CLKI);
-	              omap_cfg_reg(P19_1710_MMC_CMDDIR);
-	              omap_cfg_reg(P20_1710_MMC_DATDIR0);
-	        }
-		if (mmc->wire4) {
-			omap_cfg_reg(MMC_DAT1);
-			/* NOTE:  DAT2 can be on W10 (here) or M15 */
-			if (!mmc->nomux)
-				omap_cfg_reg(MMC_DAT2);
-			omap_cfg_reg(MMC_DAT3);
-		}
-		mmc1_conf = *mmc;
-		(void) platform_device_register(&mmc_omap_device1);
-	}
-
-#ifdef	CONFIG_ARCH_OMAP16XX
-	/* block 2 is on newer chips, and has many pinout options */
-	mmc = &mmc_conf->mmc[1];
-	if (mmc->enabled) {
-		if (!mmc->nomux) {
-			omap_cfg_reg(Y8_1610_MMC2_CMD);
-			omap_cfg_reg(Y10_1610_MMC2_CLK);
-			omap_cfg_reg(R18_1610_MMC2_CLKIN);
-			omap_cfg_reg(W8_1610_MMC2_DAT0);
-			if (mmc->wire4) {
-				omap_cfg_reg(V8_1610_MMC2_DAT1);
-				omap_cfg_reg(W15_1610_MMC2_DAT2);
-				omap_cfg_reg(R10_1610_MMC2_DAT3);
-			}
-
-			/* These are needed for the level shifter */
-			omap_cfg_reg(V9_1610_MMC2_CMDDIR);
-			omap_cfg_reg(V5_1610_MMC2_DATDIR0);
-			omap_cfg_reg(W19_1610_MMC2_DATDIR1);
-		}
-
-		/* Feedback clock must be set on OMAP-1710 MMC2 */
-		if (cpu_is_omap1710())
-			omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
-				     MOD_CONF_CTRL_1);
-		mmc2_conf = *mmc;
-		(void) platform_device_register(&mmc_omap_device2);
-	}
-#endif
-	return;
-}
-#else
-static inline void omap_init_mmc(void) {}
-#endif
-
 #if	defined(CONFIG_OMAP_RTC) || defined(CONFIG_OMAP_RTC)
 
 #define	OMAP_RTC_BASE		0xfffb4800
@@ -279,38 +99,6 @@
 static inline void omap_init_rtc(void) {}
 #endif
 
-/*-------------------------------------------------------------------------*/
-
-#if	defined(CONFIG_OMAP16XX_WATCHDOG) || defined(CONFIG_OMAP16XX_WATCHDOG_MODULE)
-
-#define	OMAP_WDT_BASE		0xfffeb000
-
-static struct resource wdt_resources[] = {
-	{
-		.start		= OMAP_WDT_BASE,
-		.end		= OMAP_WDT_BASE + 0x4f,
-		.flags		= IORESOURCE_MEM,
-	},
-};
-
-static struct platform_device omap_wdt_device = {
-	.name	   = "omap1610_wdt",
-	.id	     = -1,
-	.dev = {
-		.release	= omap_nop_release,
-	},
-	.num_resources	= ARRAY_SIZE(wdt_resources),
-	.resource	= wdt_resources,
-};
-
-static void omap_init_wdt(void)
-{
-	(void) platform_device_register(&omap_wdt_device);
-}
-#else
-static inline void omap_init_wdt(void) {}
-#endif
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -334,18 +122,15 @@
  * may be handled by the boot loader, and drivers should expect it will
  * normally have been done by the time they're probed.
  */
-static int __init omap_init_devices(void)
+static int __init omap1_init_devices(void)
 {
 	/* please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 */
-	omap_init_i2c();
 	omap_init_irda();
-	omap_init_mmc();
 	omap_init_rtc();
-	omap_init_wdt();
 
 	return 0;
 }
-arch_initcall(omap_init_devices);
+arch_initcall(omap1_init_devices);
 
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c
index 986c3b7..5c637c0 100644
--- a/arch/arm/mach-omap1/id.c
+++ b/arch/arm/mach-omap1/id.c
@@ -18,6 +18,13 @@
 
 #include <asm/io.h>
 
+#define OMAP_DIE_ID_0		0xfffe1800
+#define OMAP_DIE_ID_1		0xfffe1804
+#define OMAP_PRODUCTION_ID_0	0xfffe2000
+#define OMAP_PRODUCTION_ID_1	0xfffe2004
+#define OMAP32_ID_0		0xfffed400
+#define OMAP32_ID_1		0xfffed404
+
 struct omap_id {
 	u16	jtag_id;	/* Used to determine OMAP type */
 	u8	die_rev;	/* Processor revision */
@@ -27,6 +34,7 @@
 
 /* Register values to detect the OMAP version */
 static struct omap_id omap_ids[] __initdata = {
+	{ .jtag_id = 0xb574, .die_rev = 0x2, .omap_id = 0x03310315, .type = 0x03100000},
 	{ .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
 	{ .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
 	{ .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
@@ -164,6 +172,7 @@
 	case 0x07:
 		system_rev |= 0x07;
 		break;
+	case 0x03:
 	case 0x15:
 		system_rev |= 0x15;
 		break;
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index 79fb865..a7a19f7 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -15,9 +15,10 @@
 
 #include <asm/mach/map.h>
 #include <asm/io.h>
+#include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
 
-extern int clk_init(void);
+extern int omap1_clk_init(void);
 extern void omap_check_revision(void);
 extern void omap_sram_init(void);
 
@@ -50,7 +51,7 @@
 };
 #endif
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 static struct map_desc omap1510_io_desc[] __initdata = {
 	{
 		.virtual	= OMAP1510_DSP_BASE,
@@ -98,7 +99,7 @@
 		iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
 	}
 #endif
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
 	}
@@ -119,7 +120,7 @@
 
 	/* Must init clocks early to assure that timer interrupt works
 	 */
-	clk_init();
+	omap1_clk_init();
 }
 
 /*
@@ -127,7 +128,9 @@
  */
 void __init omap_map_common_io(void)
 {
-	if (!initialized)
+	if (!initialized) {
 		_omap_map_io();
+		omap1_mux_init();
+	}
 }
 
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index 192ce60..ed65a7d 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -47,6 +47,7 @@
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/arch/gpio.h>
+#include <asm/arch/cpu.h>
 
 #include <asm/io.h>
 
@@ -147,11 +148,15 @@
 };
 #endif
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 static struct omap_irq_bank omap1510_irq_banks[] = {
 	{ .base_reg = OMAP_IH1_BASE, 		.trigger_map = 0xb3febfff },
 	{ .base_reg = OMAP_IH2_BASE, 		.trigger_map = 0xffbfffed },
 };
+static struct omap_irq_bank omap310_irq_banks[] = {
+	{ .base_reg = OMAP_IH1_BASE, 		.trigger_map = 0xb3faefc3 },
+	{ .base_reg = OMAP_IH2_BASE, 		.trigger_map = 0x65b3c061 },
+};
 #endif
 
 #if defined(CONFIG_ARCH_OMAP16XX)
@@ -181,11 +186,15 @@
 		irq_bank_count = ARRAY_SIZE(omap730_irq_banks);
 	}
 #endif
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		irq_banks = omap1510_irq_banks;
 		irq_bank_count = ARRAY_SIZE(omap1510_irq_banks);
 	}
+	if (cpu_is_omap310()) {
+		irq_banks = omap310_irq_banks;
+		irq_bank_count = ARRAY_SIZE(omap310_irq_banks);
+	}
 #endif
 #if defined(CONFIG_ARCH_OMAP16XX)
 	if (cpu_is_omap16xx()) {
@@ -226,9 +235,11 @@
 	}
 
 	/* Unmask level 2 handler */
-	if (cpu_is_omap730()) {
+
+	if (cpu_is_omap730())
 		omap_unmask_irq(INT_730_IH2_IRQ);
-	} else {
-		omap_unmask_irq(INT_IH2_IRQ);
-	}
+	else if (cpu_is_omap1510())
+		omap_unmask_irq(INT_1510_IH2_IRQ);
+	else if (cpu_is_omap16xx())
+		omap_unmask_irq(INT_1610_IH2_IRQ);
 }
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
index be283cd..6506508 100644
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap1/leds-h2p2-debug.c
@@ -13,12 +13,12 @@
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/leds.h>
 #include <asm/system.h>
+#include <asm/mach-types.h>
 
 #include <asm/arch/fpga.h>
 #include <asm/arch/gpio.h>
@@ -64,14 +64,19 @@
 	case led_stop:
 	case led_halted:
 		/* all leds off during suspend or shutdown */
-		omap_set_gpio_dataout(GPIO_TIMER, 0);
-		omap_set_gpio_dataout(GPIO_IDLE, 0);
+
+		if (! machine_is_omap_perseus2()) {
+			omap_set_gpio_dataout(GPIO_TIMER, 0);
+			omap_set_gpio_dataout(GPIO_IDLE, 0);
+		}
+
 		__raw_writew(~0, &fpga->leds);
 		led_state &= ~LED_STATE_ENABLED;
 		if (evt == led_halted) {
 			iounmap(fpga);
 			fpga = NULL;
 		}
+
 		goto done;
 
 	case led_claim:
@@ -86,18 +91,37 @@
 #ifdef CONFIG_LEDS_TIMER
 	case led_timer:
 		led_state ^= LED_TIMER_ON;
-		omap_set_gpio_dataout(GPIO_TIMER, led_state & LED_TIMER_ON);
-		goto done;
+
+		if (machine_is_omap_perseus2())
+			hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
+		else {
+			omap_set_gpio_dataout(GPIO_TIMER, led_state & LED_TIMER_ON);
+			goto done;
+		}
+
+		break;
 #endif
 
 #ifdef CONFIG_LEDS_CPU
 	case led_idle_start:
-		omap_set_gpio_dataout(GPIO_IDLE, 1);
-		goto done;
+		if (machine_is_omap_perseus2())
+			hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
+		else {
+			omap_set_gpio_dataout(GPIO_IDLE, 1);
+			goto done;
+		}
+
+		break;
 
 	case led_idle_end:
-		omap_set_gpio_dataout(GPIO_IDLE, 0);
-		goto done;
+		if (machine_is_omap_perseus2())
+			hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
+		else {
+			omap_set_gpio_dataout(GPIO_IDLE, 0);
+			goto done;
+		}
+
+		break;
 #endif
 
 	case led_green_on:
@@ -136,7 +160,7 @@
 	/*
 	 *  Actually burn the LEDs
 	 */
-	if (led_state & LED_STATE_CLAIMED)
+	if (led_state & LED_STATE_ENABLED)
 		__raw_writew(~hw_led_state, &fpga->leds);
 
 done:
diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c
index 5c6b1bb..3f9dcac 100644
--- a/arch/arm/mach-omap1/leds.c
+++ b/arch/arm/mach-omap1/leds.c
@@ -33,7 +33,6 @@
 
 	if (machine_is_omap_h2()
 			|| machine_is_omap_h3()
-			|| machine_is_omap_perseus2()
 #ifdef	CONFIG_OMAP_OSK_MISTRAL
 			|| machine_is_omap_osk()
 #endif
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
new file mode 100644
index 0000000..d4b8d62
--- /dev/null
+++ b/arch/arm/mach-omap1/mux.c
@@ -0,0 +1,289 @@
+/*
+ * linux/arch/arm/mach-omap1/mux.c
+ *
+ * OMAP1 pin multiplexing configurations
+ *
+ * Copyright (C) 2003 - 2005 Nokia Corporation
+ *
+ * Written by Tony Lindgren <tony.lindgren@nokia.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/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/spinlock.h>
+
+#include <asm/arch/mux.h>
+
+#ifdef CONFIG_OMAP_MUX
+
+#ifdef CONFIG_ARCH_OMAP730
+struct pin_config __initdata_or_module omap730_pins[] = {
+MUX_CFG_730("E2_730_KBR0",	12,   21,    0,	  0,   20,   1,	  NA,	 0,  0)
+MUX_CFG_730("J7_730_KBR1",	12,   25,    0,	  0,   24,   1,	  NA,	 0,  0)
+MUX_CFG_730("E1_730_KBR2",	12,   29,    0,	  0,   28,   1,	  NA,	 0,  0)
+MUX_CFG_730("F3_730_KBR3",	13,    1,    0,	  0,   0,    1,	  NA,	 0,  0)
+MUX_CFG_730("D2_730_KBR4",	13,    5,    0,	  0,   4,    1,	  NA,	 0,  0)
+MUX_CFG_730("C2_730_KBC0",	13,    9,    0,	  0,	8,   1,	  NA,	 0,  0)
+MUX_CFG_730("D3_730_KBC1",	13,   13,    0,	  0,   12,   1,	  NA,	 0,  0)
+MUX_CFG_730("E4_730_KBC2",	13,   17,    0,	  0,   16,   1,	  NA,	 0,  0)
+MUX_CFG_730("F4_730_KBC3",	13,   21,    0,	  0,   20,   1,	  NA,	 0,  0)
+MUX_CFG_730("E3_730_KBC4",	13,   25,    0,	  0,   24,   1,	  NA,	 0,  0)
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
+struct pin_config __initdata_or_module omap1xxx_pins[] = {
+/*
+ *	 description		mux  mode   mux	 pull pull  pull  pu_pd	 pu  dbg
+ *				reg  offset mode reg  bit   ena	  reg
+ */
+MUX_CFG("UART1_TX",		 9,   21,    1,	  2,   3,   0,	 NA,	 0,  0)
+MUX_CFG("UART1_RTS",		 9,   12,    1,	  2,   0,   0,	 NA,	 0,  0)
+
+/* UART2 (COM_UART_GATING), conflicts with USB2 */
+MUX_CFG("UART2_TX",		 C,   27,    1,	  3,   3,   0,	 NA,	 0,  0)
+MUX_CFG("UART2_RX",		 C,   18,    0,	  3,   1,   1,	 NA,	 0,  0)
+MUX_CFG("UART2_CTS",		 C,   21,    0,	  3,   1,   1,	 NA,	 0,  0)
+MUX_CFG("UART2_RTS",		 C,   24,    1,	  3,   2,   0,	 NA,	 0,  0)
+
+/* UART3 (GIGA_UART_GATING) */
+MUX_CFG("UART3_TX",		 6,    0,    1,	  0,  30,   0,	 NA,	 0,  0)
+MUX_CFG("UART3_RX",		 6,    3,    0,	  0,  31,   1,	 NA,	 0,  0)
+MUX_CFG("UART3_CTS",		 5,   12,    2,	  0,  24,   0,	 NA,	 0,  0)
+MUX_CFG("UART3_RTS",		 5,   15,    2,	  0,  25,   0,	 NA,	 0,  0)
+MUX_CFG("UART3_CLKREQ",		 9,   27,    0,	  2,   5,   0,	 NA,	 0,  0)
+MUX_CFG("UART3_BCLK",		 A,    0,    0,	  2,   6,   0,	 NA,	 0,  0)
+MUX_CFG("Y15_1610_UART3_RTS",	 A,    0,    1,	  2,   6,   0,	 NA,	 0,  0)
+
+/* PWT & PWL, conflicts with UART3 */
+MUX_CFG("PWT",		 	 6,    0,    2,	  0,  30,   0,	 NA,	 0,  0)
+MUX_CFG("PWL",		 	 6,    3,    1,	  0,  31,   1,	 NA,	 0,  0)
+
+/* USB internal master generic */
+MUX_CFG("R18_USB_VBUS",		 7,    9,    2,	  1,  11,   0,	 NA,	 0,  1)
+MUX_CFG("R18_1510_USB_GPIO0",	 7,    9,    0,	  1,  11,   1,	 NA,	 0,  1)
+/* works around erratum:  W4_USB_PUEN and W4_USB_PUDIS are switched! */
+MUX_CFG("W4_USB_PUEN",		 D,    3,    3,	  3,   5,   1,	 NA,	 0,  1)
+MUX_CFG("W4_USB_CLKO",		 D,    3,    1,	  3,   5,   0,	 NA,	 0,  1)
+MUX_CFG("W4_USB_HIGHZ",		 D,    3,    4,	  3,   5,   0,	  3,	 0,  1)
+MUX_CFG("W4_GPIO58",		 D,    3,    7,	  3,   5,   0,	  3,	 0,  1)
+
+/* USB1 master */
+MUX_CFG("USB1_SUSP",		 8,   27,    2,	  1,  27,   0,	 NA,	 0,  1)
+MUX_CFG("USB1_SE0",		 9,    0,    2,	  1,  28,   0,	 NA,	 0,  1)
+MUX_CFG("W13_1610_USB1_SE0",	 9,    0,    4,	  1,  28,   0,	 NA,	 0,  1)
+MUX_CFG("USB1_TXEN",		 9,    3,    2,	  1,  29,   0,	 NA,	 0,  1)
+MUX_CFG("USB1_TXD",		 9,   24,    1,	  2,   4,   0,	 NA,	 0,  1)
+MUX_CFG("USB1_VP",		 A,    3,    1,	  2,   7,   0,	 NA,	 0,  1)
+MUX_CFG("USB1_VM",		 A,    6,    1,	  2,   8,   0,	 NA,	 0,  1)
+MUX_CFG("USB1_RCV",		 A,    9,    1,	  2,   9,   0,	 NA,	 0,  1)
+MUX_CFG("USB1_SPEED",		 A,   12,    2,	  2,  10,   0,	 NA,	 0,  1)
+MUX_CFG("R13_1610_USB1_SPEED",	 A,   12,    5,	  2,  10,   0,	 NA,	 0,  1)
+MUX_CFG("R13_1710_USB1_SEO",	 A,   12,    5,   2,  10,   0,   NA,     0,  1)
+
+/* USB2 master */
+MUX_CFG("USB2_SUSP",		 B,    3,    1,	  2,  17,   0,	 NA,	 0,  1)
+MUX_CFG("USB2_VP",		 B,    6,    1,	  2,  18,   0,	 NA,	 0,  1)
+MUX_CFG("USB2_TXEN",		 B,    9,    1,	  2,  19,   0,	 NA,	 0,  1)
+MUX_CFG("USB2_VM",		 C,   18,    1,	  3,   0,   0,	 NA,	 0,  1)
+MUX_CFG("USB2_RCV",		 C,   21,    1,	  3,   1,   0,	 NA,	 0,  1)
+MUX_CFG("USB2_SE0",		 C,   24,    2,	  3,   2,   0,	 NA,	 0,  1)
+MUX_CFG("USB2_TXD",		 C,   27,    2,	  3,   3,   0,	 NA,	 0,  1)
+
+/* OMAP-1510 GPIO */
+MUX_CFG("R18_1510_GPIO0",	 7,    9,    0,   1,  11,   1,    0,     0,  1)
+MUX_CFG("R19_1510_GPIO1",	 7,    6,    0,   1,  10,   1,    0,     0,  1)
+MUX_CFG("M14_1510_GPIO2",	 7,    3,    0,   1,   9,   1,    0,     0,  1)
+
+/* OMAP1610 GPIO */
+MUX_CFG("P18_1610_GPIO3",	 7,    0,    0,   1,   8,   0,   NA,     0,  1)
+MUX_CFG("Y15_1610_GPIO17",	 A,    0,    7,   2,   6,   0,   NA,     0,  1)
+
+/* OMAP-1710 GPIO */
+MUX_CFG("R18_1710_GPIO0",        7,    9,    0,   1,  11,   1,    1,     1,  1)
+MUX_CFG("V2_1710_GPIO10",        F,   27,    1,   4,   3,   1,    4,     1,  1)
+MUX_CFG("N21_1710_GPIO14",       6,    9,    0,   1,   1,   1,    1,     1,  1)
+MUX_CFG("W15_1710_GPIO40",       9,   27,    7,   2,   5,   1,    2,     1,  1)
+
+/* MPUIO */
+MUX_CFG("MPUIO2",		 7,   18,    0,	  1,  14,   1,	 NA,	 0,  1)
+MUX_CFG("N15_1610_MPUIO2",	 7,   18,    0,	  1,  14,   1,	  1,	 0,  1)
+MUX_CFG("MPUIO4",		 7,   15,    0,	  1,  13,   1,	 NA,	 0,  1)
+MUX_CFG("MPUIO5",		 7,   12,    0,	  1,  12,   1,	 NA,	 0,  1)
+
+MUX_CFG("T20_1610_MPUIO5",	 7,   12,    0,	  1,  12,   0,	  3,	 0,  1)
+MUX_CFG("W11_1610_MPUIO6",	10,   15,    2,	  3,   8,   0,	  3,	 0,  1)
+MUX_CFG("V10_1610_MPUIO7",	 A,   24,    2,	  2,  14,   0,	  2,	 0,  1)
+MUX_CFG("W11_1610_MPUIO9",	10,   15,    1,	  3,   8,   0,	  3,	 0,  1)
+MUX_CFG("V10_1610_MPUIO10",	 A,   24,    1,	  2,  14,   0,	  2,	 0,  1)
+MUX_CFG("W10_1610_MPUIO11",	 A,   18,    2,	  2,  11,   0,	  2,	 0,  1)
+MUX_CFG("E20_1610_MPUIO13",	 3,   21,    1,	  0,   7,   0,	  0,	 0,  1)
+MUX_CFG("U20_1610_MPUIO14",	 9,    6,    6,	  0,  30,   0,	  0,	 0,  1)
+MUX_CFG("E19_1610_MPUIO15",	 3,   18,    1,	  0,   6,   0,	  0,	 0,  1)
+
+/* MCBSP2 */
+MUX_CFG("MCBSP2_CLKR",		 C,    6,    0,	  2,  27,   1,	 NA,	 0,  1)
+MUX_CFG("MCBSP2_CLKX",		 C,    9,    0,	  2,  29,   1,	 NA,	 0,  1)
+MUX_CFG("MCBSP2_DR",		 C,    0,    0,	  2,  26,   1,	 NA,	 0,  1)
+MUX_CFG("MCBSP2_DX",		 C,   15,    0,	  2,  31,   1,	 NA,	 0,  1)
+MUX_CFG("MCBSP2_FSR",		 C,   12,    0,	  2,  30,   1,	 NA,	 0,  1)
+MUX_CFG("MCBSP2_FSX",		 C,    3,    0,	  2,  27,   1,	 NA,	 0,  1)
+
+/* MCBSP3 NOTE: Mode must 1 for clock */
+MUX_CFG("MCBSP3_CLKX",		 9,    3,    1,	  1,  29,   0,	 NA,	 0,  1)
+
+/* Misc ballouts */
+MUX_CFG("BALLOUT_V8_ARMIO3",	 B,   18,    0,	  2,  25,   1,	 NA,	 0,  1)
+MUX_CFG("N20_HDQ",	       6,   18,    1,   1,   4,   0,    1,     4,  0)
+
+/* OMAP-1610 MMC2 */
+MUX_CFG("W8_1610_MMC2_DAT0",	 B,   21,    6,	  2,  23,   1,	  2,	 1,  1)
+MUX_CFG("V8_1610_MMC2_DAT1",	 B,   27,    6,	  2,  25,   1,	  2,	 1,  1)
+MUX_CFG("W15_1610_MMC2_DAT2",	 9,   12,    6,	  2,   5,   1,	  2,	 1,  1)
+MUX_CFG("R10_1610_MMC2_DAT3",	 B,   18,    6,	  2,  22,   1,	  2,	 1,  1)
+MUX_CFG("Y10_1610_MMC2_CLK",	 B,    3,    6,	  2,  17,   0,	  2,	 0,  1)
+MUX_CFG("Y8_1610_MMC2_CMD",	 B,   24,    6,	  2,  24,   1,	  2,	 1,  1)
+MUX_CFG("V9_1610_MMC2_CMDDIR",	 B,   12,    6,	  2,  20,   0,	  2,	 1,  1)
+MUX_CFG("V5_1610_MMC2_DATDIR0",	 B,   15,    6,	  2,  21,   0,	  2,	 1,  1)
+MUX_CFG("W19_1610_MMC2_DATDIR1", 8,   15,    6,	  1,  23,   0,	  1,	 1,  1)
+MUX_CFG("R18_1610_MMC2_CLKIN",	 7,    9,    6,	  1,  11,   0,	  1,	11,  1)
+
+/* OMAP-1610 External Trace Interface */
+MUX_CFG("M19_1610_ETM_PSTAT0",	 5,   27,    1,	  0,  29,   0,	  0,	 0,  1)
+MUX_CFG("L15_1610_ETM_PSTAT1",	 5,   24,    1,	  0,  28,   0,	  0,	 0,  1)
+MUX_CFG("L18_1610_ETM_PSTAT2",	 5,   21,    1,	  0,  27,   0,	  0,	 0,  1)
+MUX_CFG("L19_1610_ETM_D0",	 5,   18,    1,	  0,  26,   0,	  0,	 0,  1)
+MUX_CFG("J19_1610_ETM_D6",	 5,    0,    1,	  0,  20,   0,	  0,	 0,  1)
+MUX_CFG("J18_1610_ETM_D7",	 5,   27,    1,	  0,  19,   0,	  0,	 0,  1)
+
+/* OMAP16XX GPIO */
+MUX_CFG("P20_1610_GPIO4",	 6,   27,    0,	  1,   7,   0,	  1,	 1,  1)
+MUX_CFG("V9_1610_GPIO7",	 B,   12,    1,	  2,  20,   0,	  2,	 1,  1)
+MUX_CFG("W8_1610_GPIO9",	 B,   21,    0,	  2,  23,   0,	  2,	 1,  1)
+MUX_CFG("N20_1610_GPIO11",       6,   18,    0,   1,   4,   0,    1,     1,  1)
+MUX_CFG("N19_1610_GPIO13",	 6,   12,    0,	  1,   2,   0,	  1,	 1,  1)
+MUX_CFG("P10_1610_GPIO22",	 C,    0,    7,	  2,  26,   0,	  2,	 1,  1)
+MUX_CFG("V5_1610_GPIO24",	 B,   15,    7,	  2,  21,   0,	  2,	 1,  1)
+MUX_CFG("AA20_1610_GPIO_41",	 9,    9,    7,	  1,  31,   0,	  1,	 1,  1)
+MUX_CFG("W19_1610_GPIO48",	 8,   15,    7,   1,  23,   1,    1,     0,  1)
+MUX_CFG("M7_1610_GPIO62",	10,    0,    0,   4,  24,   0,    4,     0,  1)
+MUX_CFG("V14_16XX_GPIO37",	 9,   18,    7,	  2,   2,   0,	  2,	 2,  0)
+MUX_CFG("R9_16XX_GPIO18",	 C,   18,    7,   3,   0,   0,    3,     0,  0)
+MUX_CFG("L14_16XX_GPIO49",	 6,    3,    7,   0,  31,   0,    0,    31,  0)
+
+/* OMAP-1610 uWire */
+MUX_CFG("V19_1610_UWIRE_SCLK",	 8,    6,    0,	  1,  20,   0,	  1,	 1,  1)
+MUX_CFG("U18_1610_UWIRE_SDI",	 8,    0,    0,	  1,  18,   0,	  1,	 1,  1)
+MUX_CFG("W21_1610_UWIRE_SDO",	 8,    3,    0,	  1,  19,   0,	  1,	 1,  1)
+MUX_CFG("N14_1610_UWIRE_CS0",	 8,    9,    1,	  1,  21,   0,	  1,	 1,  1)
+MUX_CFG("P15_1610_UWIRE_CS3",	 8,   12,    1,	  1,  22,   0,	  1,	 1,  1)
+MUX_CFG("N15_1610_UWIRE_CS1",	 7,   18,    2,	  1,  14,   0,	 NA,	 0,  1)
+
+/* OMAP-1610 Flash */
+MUX_CFG("L3_1610_FLASH_CS2B_OE",10,    6,    1,	 NA,   0,   0,	 NA,	 0,  1)
+MUX_CFG("M8_1610_FLASH_CS2B_WE",10,    3,    1,	 NA,   0,   0,	 NA,	 0,  1)
+
+/* First MMC interface, same on 1510, 1610 and 1710 */
+MUX_CFG("MMC_CMD",		 A,   27,    0,	  2,  15,   1,	  2,	 1,  1)
+MUX_CFG("MMC_DAT1",		 A,   24,    0,	  2,  14,   1,	  2,	 1,  1)
+MUX_CFG("MMC_DAT2",		 A,   18,    0,	  2,  12,   1,	  2,	 1,  1)
+MUX_CFG("MMC_DAT0",		 B,    0,    0,	  2,  16,   1,	  2,	 1,  1)
+MUX_CFG("MMC_CLK",		 A,   21,    0,	 NA,   0,   0,	 NA,	 0,  1)
+MUX_CFG("MMC_DAT3",		10,   15,    0,	  3,   8,   1,	  3,	 1,  1)
+MUX_CFG("M15_1710_MMC_CLKI",	 6,   21,    2,   0,   0,   0,   NA,     0,  1)
+MUX_CFG("P19_1710_MMC_CMDDIR",	 6,   24,    6,   0,   0,   0,   NA,     0,  1)
+MUX_CFG("P20_1710_MMC_DATDIR0",	 6,   27,    5,   0,   0,   0,   NA,     0,  1)
+
+/* OMAP-1610 USB0 alternate configuration */
+MUX_CFG("W9_USB0_TXEN",		 B,   9,     5,	  2,  19,   0,	  2,	 0,  1)
+MUX_CFG("AA9_USB0_VP",		 B,   6,     5,	  2,  18,   0,	  2,	 0,  1)
+MUX_CFG("Y5_USB0_RCV",		 C,  21,     5,	  3,   1,   0,	  1,	 0,  1)
+MUX_CFG("R9_USB0_VM",		 C,  18,     5,	  3,   0,   0,	  3,	 0,  1)
+MUX_CFG("V6_USB0_TXD",		 C,  27,     5,	  3,   3,   0,	  3,	 0,  1)
+MUX_CFG("W5_USB0_SE0",		 C,  24,     5,	  3,   2,   0,	  3,	 0,  1)
+MUX_CFG("V9_USB0_SPEED",	 B,  12,     5,	  2,  20,   0,	  2,	 0,  1)
+MUX_CFG("Y10_USB0_SUSP",	 B,   3,     5,	  2,  17,   0,	  2,	 0,  1)
+
+/* USB2 interface */
+MUX_CFG("W9_USB2_TXEN",		 B,   9,     1,	 NA,   0,   0,	 NA,	 0,  1)
+MUX_CFG("AA9_USB2_VP",		 B,   6,     1,	 NA,   0,   0,	 NA,	 0,  1)
+MUX_CFG("Y5_USB2_RCV",		 C,  21,     1,	 NA,   0,   0,	 NA,	 0,  1)
+MUX_CFG("R9_USB2_VM",		 C,  18,     1,	 NA,   0,   0,	 NA,	 0,  1)
+MUX_CFG("V6_USB2_TXD",		 C,  27,     2,	 NA,   0,   0,	 NA,	 0,  1)
+MUX_CFG("W5_USB2_SE0",		 C,  24,     2,	 NA,   0,   0,	 NA,	 0,  1)
+
+/* 16XX UART */
+MUX_CFG("R13_1610_UART1_TX",	 A,  12,     6,	  2,  10,   0,	  2,	10,  1)
+MUX_CFG("V14_16XX_UART1_RX",	 9,  18,     0,	  2,   2,   0,	  2,	 2,  1)
+MUX_CFG("R14_1610_UART1_CTS",	 9,  15,     0,	  2,   1,   0,	  2,	 1,  1)
+MUX_CFG("AA15_1610_UART1_RTS",	 9,  12,     1,	  2,   0,   0,	  2,	 0,  1)
+MUX_CFG("R9_16XX_UART2_RX",	 C,  18,     0,   3,   0,   0,    3,     0,  1)
+MUX_CFG("L14_16XX_UART3_RX",	 6,   3,     0,   0,  31,   0,    0,    31,  1)
+
+/* I2C interface */
+MUX_CFG("I2C_SCL",		 7,  24,     0,	 NA,   0,   0,	 NA,	 0,  0)
+MUX_CFG("I2C_SDA",		 7,  27,     0,	 NA,   0,   0,	 NA,	 0,  0)
+
+/* Keypad */
+MUX_CFG("F18_1610_KBC0",	 3,  15,     0,	  0,   5,   1,	  0,	 0,  0)
+MUX_CFG("D20_1610_KBC1",	 3,  12,     0,	  0,   4,   1,	  0,	 0,  0)
+MUX_CFG("D19_1610_KBC2",	 3,   9,     0,	  0,   3,   1,	  0,	 0,  0)
+MUX_CFG("E18_1610_KBC3",	 3,   6,     0,	  0,   2,   1,	  0,	 0,  0)
+MUX_CFG("C21_1610_KBC4",	 3,   3,     0,	  0,   1,   1,	  0,	 0,  0)
+MUX_CFG("G18_1610_KBR0",	 4,   0,     0,	  0,   10,  1,	  0,	 1,  0)
+MUX_CFG("F19_1610_KBR1",	 3,   27,    0,	  0,   9,   1,	  0,	 1,  0)
+MUX_CFG("H14_1610_KBR2",	 3,   24,    0,	  0,   8,   1,	  0,	 1,  0)
+MUX_CFG("E20_1610_KBR3",	 3,   21,    0,	  0,   7,   1,	  0,	 1,  0)
+MUX_CFG("E19_1610_KBR4",	 3,   18,    0,	  0,   6,   1,	  0,	 1,  0)
+MUX_CFG("N19_1610_KBR5",	 6,  12,     1,	  1,   2,   1,	  1,	 1,  0)
+
+/* Power management */
+MUX_CFG("T20_1610_LOW_PWR",	 7,   12,    1,	  NA,   0,   0,   NA,	 0,  0)
+
+/* MCLK Settings */
+MUX_CFG("V5_1710_MCLK_ON",	 B,   15,    0,	  NA,   0,   0,   NA,	 0,  0)
+MUX_CFG("V5_1710_MCLK_OFF",	 B,   15,    6,	  NA,   0,   0,   NA,	 0,  0)
+MUX_CFG("R10_1610_MCLK_ON",	 B,   18,    0,	  NA,  22,   0,	  NA,	 1,  0)
+MUX_CFG("R10_1610_MCLK_OFF",	 B,   18,    6,	  2,   22,   1,	  2,	 1,  1)
+
+/* CompactFlash controller, conflicts with MMC1 */
+MUX_CFG("P11_1610_CF_CD2",	 A,   27,    3,	  2,   15,   1,	  2,	 1,  1)
+MUX_CFG("R11_1610_CF_IOIS16",	 B,    0,    3,	  2,   16,   1,	  2,	 1,  1)
+MUX_CFG("V10_1610_CF_IREQ",	 A,   24,    3,	  2,   14,   0,	  2,	 0,  1)
+MUX_CFG("W10_1610_CF_RESET",	 A,   18,    3,	  2,   12,   1,	  2,	 1,  1)
+MUX_CFG("W11_1610_CF_CD1",	10,   15,    3,	  3,    8,   1,	  3,	 1,  1)
+};
+#endif	/* CONFIG_ARCH_OMAP15XX || CONFIG_ARCH_OMAP16XX */
+
+int __init omap1_mux_init(void)
+{
+
+#ifdef CONFIG_ARCH_OMAP730
+	omap_mux_register(omap730_pins, ARRAY_SIZE(omap730_pins));
+#endif
+
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
+	omap_mux_register(omap1xxx_pins, ARRAY_SIZE(omap1xxx_pins));
+#endif
+
+	return 0;
+}
+
+#endif
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index 40c4f7c4..6810cfb 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -109,9 +109,10 @@
  * By default UART2 does not work on Innovator-1510 if you have
  * USB OHCI enabled. To use UART2, you must disable USB2 first.
  */
-void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
+void __init omap_serial_init(void)
 {
 	int i;
+	const struct omap_uart_config *info;
 
 	if (cpu_is_omap730()) {
 		serial_platform_data[0].regshift = 0;
@@ -126,10 +127,14 @@
 		serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
 	}
 
+	info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
+	if (info == NULL)
+		return;
+
 	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
 		unsigned char reg;
 
-		if (ports[i] == 0) {
+		if (!((1 << i) & info->enabled_uarts)) {
 			serial_platform_data[i].membase = NULL;
 			serial_platform_data[i].mapbase = 0;
 			continue;
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 191a9b1..cdbf4d7 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -226,8 +226,8 @@
 
 #ifdef CONFIG_OMAP_32K_TIMER
 
-#ifdef CONFIG_ARCH_OMAP1510
-#error OMAP 32KHz timer does not currently work on 1510!
+#ifdef CONFIG_ARCH_OMAP15XX
+#error OMAP 32KHz timer does not currently work on 15XX!
 #endif
 
 /*
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
new file mode 100644
index 0000000..5788809
--- /dev/null
+++ b/arch/arm/mach-omap2/Kconfig
@@ -0,0 +1,22 @@
+comment "OMAP Core Type"
+	depends on ARCH_OMAP2
+
+config ARCH_OMAP24XX
+	bool "OMAP24xx Based System"
+	depends on ARCH_OMAP2
+
+config ARCH_OMAP2420
+	bool "OMAP2420 support"
+	depends on ARCH_OMAP24XX
+
+comment "OMAP Board Type"
+	depends on ARCH_OMAP2
+
+config MACH_OMAP_GENERIC
+	bool "Generic OMAP board"
+	depends on ARCH_OMAP2 && ARCH_OMAP24XX
+
+config MACH_OMAP_H4
+	bool "OMAP 2420 H4 board"
+	depends on ARCH_OMAP2 && ARCH_OMAP24XX
+
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
new file mode 100644
index 0000000..4204116
--- /dev/null
+++ b/arch/arm/mach-omap2/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := irq.o id.o io.o sram-fn.o clock.o mux.o devices.o serial.o
+
+obj-$(CONFIG_OMAP_MPU_TIMER)		+= timer-gp.o
+
+# Specific board support
+obj-$(CONFIG_MACH_OMAP_GENERIC)		+= board-generic.o
+obj-$(CONFIG_MACH_OMAP_H4)		+= board-h4.o
+
diff --git a/arch/arm/mach-omap2/Makefile.boot b/arch/arm/mach-omap2/Makefile.boot
new file mode 100644
index 0000000..565aff7
--- /dev/null
+++ b/arch/arm/mach-omap2/Makefile.boot
@@ -0,0 +1,3 @@
+  zreladdr-y		:= 0x80008000
+params_phys-y		:= 0x80000100
+initrd_phys-y		:= 0x80800000
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
new file mode 100644
index 0000000..c602e7a
--- /dev/null
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -0,0 +1,80 @@
+/*
+ * linux/arch/arm/mach-omap/omap2/board-generic.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * Modified from mach-omap/omap1/board-generic.c
+ *
+ * Code for generic OMAP2 board. Should work on many OMAP2 systems where
+ * the bootloader passes the board-specific data to the kernel.
+ * Do not put any board specific code to this file; create a new machine
+ * type if you need custom low-level initializations.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+
+static void __init omap_generic_init_irq(void)
+{
+	omap_init_irq();
+}
+
+static struct omap_uart_config generic_uart_config __initdata = {
+	.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_mmc_config generic_mmc_config __initdata = {
+	.mmc [0] = {
+		.enabled 	= 0,
+		.wire4		= 0,
+		.wp_pin		= -1,
+		.power_pin	= -1,
+		.switch_pin	= -1,
+	},
+};
+
+static struct omap_board_config_kernel generic_config[] = {
+	{ OMAP_TAG_UART,	&generic_uart_config },
+	{ OMAP_TAG_MMC,		&generic_mmc_config },
+};
+
+static void __init omap_generic_init(void)
+{
+	omap_board_config = generic_config;
+	omap_board_config_size = ARRAY_SIZE(generic_config);
+	omap_serial_init();
+}
+
+static void __init omap_generic_map_io(void)
+{
+	omap_map_common_io();
+}
+
+MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
+	/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
+	.phys_ram	= 0x80000000,
+	.phys_io	= 0x48000000,
+	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
+	.boot_params	= 0x80000100,
+	.map_io		= omap_generic_map_io,
+	.init_irq	= omap_generic_init_irq,
+	.init_machine	= omap_generic_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
new file mode 100644
index 0000000..f255446
--- /dev/null
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -0,0 +1,197 @@
+/*
+ * linux/arch/arm/mach-omap/omap2/board-h4.c
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * Modified from mach-omap/omap1/board-generic.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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+#include <asm/arch/common.h>
+#include <asm/arch/prcm.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+
+static struct mtd_partition h4_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	},
+	/* kernel */
+	{
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	},
+	/* file system */
+	{
+	      .name		= "filesystem",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	}
+};
+
+static struct flash_platform_data h4_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= h4_partitions,
+	.nr_parts	= ARRAY_SIZE(h4_partitions),
+};
+
+static struct resource h4_flash_resource = {
+	.start		= H4_CS0_BASE,
+	.end		= H4_CS0_BASE + SZ_64M - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device h4_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &h4_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &h4_flash_resource,
+};
+
+static struct resource h4_smc91x_resources[] = {
+	[0] = {
+		.start  = OMAP24XX_ETHR_START,          /* Physical */
+		.end    = OMAP24XX_ETHR_START + 0xf,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
+		.end    = OMAP_GPIO_IRQ(OMAP24XX_ETHR_GPIO_IRQ),
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device h4_smc91x_device = {
+	.name		= "smc91x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(h4_smc91x_resources),
+	.resource	= h4_smc91x_resources,
+};
+
+static struct platform_device *h4_devices[] __initdata = {
+	&h4_smc91x_device,
+	&h4_flash_device,
+};
+
+static inline void __init h4_init_smc91x(void)
+{
+	/* Make sure CS1 timings are correct */
+	GPMC_CONFIG1_1 = 0x00011200;
+	GPMC_CONFIG2_1 = 0x001f1f01;
+	GPMC_CONFIG3_1 = 0x00080803;
+	GPMC_CONFIG4_1 = 0x1c091c09;
+	GPMC_CONFIG5_1 = 0x041f1f1f;
+	GPMC_CONFIG6_1 = 0x000004c4;
+	GPMC_CONFIG7_1 = 0x00000f40 | (0x08000000 >> 24);
+	udelay(100);
+
+	omap_cfg_reg(M15_24XX_GPIO92);
+	if (omap_request_gpio(OMAP24XX_ETHR_GPIO_IRQ) < 0) {
+		printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
+			OMAP24XX_ETHR_GPIO_IRQ);
+		return;
+	}
+	omap_set_gpio_direction(OMAP24XX_ETHR_GPIO_IRQ, 1);
+}
+
+static void __init omap_h4_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+	h4_init_smc91x();
+}
+
+static struct omap_uart_config h4_uart_config __initdata = {
+	.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_mmc_config h4_mmc_config __initdata = {
+	.mmc [0] = {
+		.enabled	= 1,
+		.wire4		= 1,
+		.wp_pin		= -1,
+		.power_pin	= -1,
+		.switch_pin	= -1,
+	},
+};
+
+static struct omap_lcd_config h4_lcd_config __initdata = {
+	.panel_name	= "h4",
+	.ctrl_name	= "internal",
+};
+
+static struct omap_board_config_kernel h4_config[] = {
+	{ OMAP_TAG_UART,	&h4_uart_config },
+	{ OMAP_TAG_MMC,		&h4_mmc_config },
+	{ OMAP_TAG_LCD,		&h4_lcd_config },
+};
+
+static void __init omap_h4_init(void)
+{
+	/*
+	 * Make sure the serial ports are muxed on at this point.
+	 * You have to mux them off in device drivers later on
+	 * if not needed.
+	 */
+	platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
+	omap_board_config = h4_config;
+	omap_board_config_size = ARRAY_SIZE(h4_config);
+	omap_serial_init();
+}
+
+static void __init omap_h4_map_io(void)
+{
+	omap_map_common_io();
+}
+
+MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
+	/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
+	.phys_ram	= 0x80000000,
+	.phys_io	= 0x48000000,
+	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
+	.boot_params	= 0x80000100,
+	.map_io		= omap_h4_map_io,
+	.init_irq	= omap_h4_init_irq,
+	.init_machine	= omap_h4_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
new file mode 100644
index 0000000..85818d9
--- /dev/null
+++ b/arch/arm/mach-omap2/clock.c
@@ -0,0 +1,1129 @@
+/*
+ *  linux/arch/arm/mach-omap2/clock.c
+ *
+ *  Copyright (C) 2005 Texas Instruments Inc.
+ *  Richard Woodruff <r-woodruff2@ti.com>
+ *  Created for OMAP2.
+ *
+ *  Cleaned up and modified to use omap shared clock framework by
+ *  Tony Lindgren <tony@atomide.com>
+ *
+ *  Based on omap1 clock.c, Copyright (C) 2004 - 2005 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#include <asm/hardware/clock.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/prcm.h>
+
+#include "clock.h"
+
+//#define DOWN_VARIABLE_DPLL 1			/* Experimental */
+
+static struct prcm_config *curr_prcm_set;
+static struct memory_timings mem_timings;
+static u32 curr_perf_level = PRCM_FULL_SPEED;
+
+/*-------------------------------------------------------------------------
+ * Omap2 specific clock functions
+ *-------------------------------------------------------------------------*/
+
+/* Recalculate SYST_CLK */
+static void omap2_sys_clk_recalc(struct clk * clk)
+{
+	u32 div = PRCM_CLKSRC_CTRL;
+	div &= (1 << 7) | (1 << 6);	/* Test if ext clk divided by 1 or 2 */
+	div >>= clk->rate_offset;
+	clk->rate = (clk->parent->rate / div);
+	propagate_rate(clk);
+}
+
+static u32 omap2_get_dpll_rate(struct clk * tclk)
+{
+	int dpll_clk, dpll_mult, dpll_div, amult;
+
+	dpll_mult = (CM_CLKSEL1_PLL >> 12) & 0x03ff;	/* 10 bits */
+	dpll_div = (CM_CLKSEL1_PLL >> 8) & 0x0f;	/* 4 bits */
+	dpll_clk = (tclk->parent->rate * dpll_mult) / (dpll_div + 1);
+	amult = CM_CLKSEL2_PLL & 0x3;
+	dpll_clk *= amult;
+
+	return dpll_clk;
+}
+
+static void omap2_followparent_recalc(struct clk *clk)
+{
+	followparent_recalc(clk);
+}
+
+static void omap2_propagate_rate(struct clk * clk)
+{
+	if (!(clk->flags & RATE_FIXED))
+		clk->rate = clk->parent->rate;
+
+	propagate_rate(clk);
+}
+
+/* Enable an APLL if off */
+static void omap2_clk_fixed_enable(struct clk *clk)
+{
+	u32 cval, i=0;
+
+	if (clk->enable_bit == 0xff)			/* Parent will do it */
+		return;
+
+	cval = CM_CLKEN_PLL;
+
+	if ((cval & (0x3 << clk->enable_bit)) == (0x3 << clk->enable_bit))
+		return;
+
+	cval &= ~(0x3 << clk->enable_bit);
+	cval |= (0x3 << clk->enable_bit);
+	CM_CLKEN_PLL = cval;
+
+	if (clk == &apll96_ck)
+		cval = (1 << 8);
+	else if (clk == &apll54_ck)
+		cval = (1 << 6);
+
+	while (!CM_IDLEST_CKGEN & cval) {		/* Wait for lock */
+		++i;
+		udelay(1);
+		if (i == 100000)
+			break;
+	}
+}
+
+/* Enables clock without considering parent dependencies or use count
+ * REVISIT: Maybe change this to use clk->enable like on omap1?
+ */
+static int omap2_clk_enable(struct clk * clk)
+{
+	u32 regval32;
+
+	if (clk->flags & ALWAYS_ENABLED)
+		return 0;
+
+	if (unlikely(clk->enable_reg == 0)) {
+		printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
+		       clk->name);
+		return 0;
+	}
+
+	if (clk->enable_reg == (void __iomem *)&CM_CLKEN_PLL) {
+		omap2_clk_fixed_enable(clk);
+		return 0;
+	}
+
+	regval32 = __raw_readl(clk->enable_reg);
+	regval32 |= (1 << clk->enable_bit);
+	__raw_writel(regval32, clk->enable_reg);
+
+	return 0;
+}
+
+/* Stop APLL */
+static void omap2_clk_fixed_disable(struct clk *clk)
+{
+	u32 cval;
+
+	if(clk->enable_bit == 0xff)		/* let parent off do it */
+		return;
+
+	cval = CM_CLKEN_PLL;
+	cval &= ~(0x3 << clk->enable_bit);
+	CM_CLKEN_PLL = cval;
+}
+
+/* Disables clock without considering parent dependencies or use count */
+static void omap2_clk_disable(struct clk *clk)
+{
+	u32 regval32;
+
+	if (clk->enable_reg == 0)
+		return;
+
+	if (clk->enable_reg == (void __iomem *)&CM_CLKEN_PLL) {
+		omap2_clk_fixed_disable(clk);
+		return;
+	}
+
+	regval32 = __raw_readl(clk->enable_reg);
+	regval32 &= ~(1 << clk->enable_bit);
+	__raw_writel(regval32, clk->enable_reg);
+}
+
+static int omap2_clk_use(struct clk *clk)
+{
+	int ret = 0;
+
+	if (clk->usecount++ == 0) {
+		if (likely((u32)clk->parent))
+			ret = omap2_clk_use(clk->parent);
+
+		if (unlikely(ret != 0)) {
+			clk->usecount--;
+			return ret;
+		}
+
+		ret = omap2_clk_enable(clk);
+
+		if (unlikely(ret != 0) && clk->parent) {
+			omap2_clk_unuse(clk->parent);
+			clk->usecount--;
+		}
+	}
+
+	return ret;
+}
+
+static void omap2_clk_unuse(struct clk *clk)
+{
+	if (clk->usecount > 0 && !(--clk->usecount)) {
+		omap2_clk_disable(clk);
+		if (likely((u32)clk->parent))
+			omap2_clk_unuse(clk->parent);
+	}
+}
+
+/*
+ * Uses the current prcm set to tell if a rate is valid.
+ * You can go slower, but not faster within a given rate set.
+ */
+static u32 omap2_dpll_round_rate(unsigned long target_rate)
+{
+	u32 high, low;
+
+	if ((CM_CLKSEL2_PLL & 0x3) == 1) {	/* DPLL clockout */
+		high = curr_prcm_set->dpll_speed * 2;
+		low = curr_prcm_set->dpll_speed;
+	} else {				/* DPLL clockout x 2 */
+		high = curr_prcm_set->dpll_speed;
+		low = curr_prcm_set->dpll_speed / 2;
+	}
+
+#ifdef DOWN_VARIABLE_DPLL
+	if (target_rate > high)
+		return high;
+	else
+		return target_rate;
+#else
+	if (target_rate > low)
+		return high;
+	else
+		return low;
+#endif
+
+}
+
+/*
+ * Used for clocks that are part of CLKSEL_xyz governed clocks.
+ * REVISIT: Maybe change to use clk->enable() functions like on omap1?
+ */
+static void omap2_clksel_recalc(struct clk * clk)
+{
+	u32 fixed = 0, div = 0;
+
+	if (clk == &dpll_ck) {
+		clk->rate = omap2_get_dpll_rate(clk);
+		fixed = 1;
+		div = 0;
+	}
+
+	if (clk == &iva1_mpu_int_ifck) {
+		div = 2;
+		fixed = 1;
+	}
+
+	if ((clk == &dss1_fck) && ((CM_CLKSEL1_CORE & (0x1f << 8)) == 0)) {
+		clk->rate = sys_ck.rate;
+		return;
+	}
+
+	if (!fixed) {
+		div = omap2_clksel_get_divisor(clk);
+		if (div == 0)
+			return;
+	}
+
+	if (div != 0) {
+		if (unlikely(clk->rate == clk->parent->rate / div))
+			return;
+		clk->rate = clk->parent->rate / div;
+	}
+
+	if (unlikely(clk->flags & RATE_PROPAGATES))
+		propagate_rate(clk);
+}
+
+/*
+ * Finds best divider value in an array based on the source and target
+ * rates. The divider array must be sorted with smallest divider first.
+ */
+static inline u32 omap2_divider_from_table(u32 size, u32 *div_array,
+					   u32 src_rate, u32 tgt_rate)
+{
+	int i, test_rate;
+
+	if (div_array == NULL)
+		return ~1;
+
+	for (i=0; i < size; i++) {
+		test_rate = src_rate / *div_array;
+		if (test_rate <= tgt_rate)
+			return *div_array;
+		++div_array;
+	}
+
+	return ~0;	/* No acceptable divider */
+}
+
+/*
+ * Find divisor for the given clock and target rate.
+ *
+ * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
+ * they are only settable as part of virtual_prcm set.
+ */
+static u32 omap2_clksel_round_rate(struct clk *tclk, u32 target_rate,
+	u32 *new_div)
+{
+	u32 gfx_div[] = {2, 3, 4};
+	u32 sysclkout_div[] = {1, 2, 4, 8, 16};
+	u32 dss1_div[] = {1, 2, 3, 4, 5, 6, 8, 9, 12, 16};
+	u32 vylnq_div[] = {1, 2, 3, 4, 6, 8, 9, 12, 16, 18};
+	u32 best_div = ~0, asize = 0;
+	u32 *div_array = NULL;
+
+	switch (tclk->flags & SRC_RATE_SEL_MASK) {
+	case CM_GFX_SEL1:
+		asize = 3;
+		div_array = gfx_div;
+		break;
+	case CM_PLL_SEL1:
+		return omap2_dpll_round_rate(target_rate);
+	case CM_SYSCLKOUT_SEL1:
+		asize = 5;
+		div_array = sysclkout_div;
+		break;
+	case CM_CORE_SEL1:
+		if(tclk == &dss1_fck){
+			if(tclk->parent == &core_ck){
+				asize = 10;
+				div_array = dss1_div;
+			} else {
+				*new_div = 0; /* fixed clk */
+				return(tclk->parent->rate);
+			}
+		} else if((tclk == &vlynq_fck) && cpu_is_omap2420()){
+			if(tclk->parent == &core_ck){
+				asize = 10;
+				div_array = vylnq_div;
+			} else {
+				*new_div = 0; /* fixed clk */
+				return(tclk->parent->rate);
+			}
+		}
+		break;
+	}
+
+	best_div = omap2_divider_from_table(asize, div_array,
+	 tclk->parent->rate, target_rate);
+	if (best_div == ~0){
+		*new_div = 1;
+		return best_div; /* signal error */
+	}
+
+	*new_div = best_div;
+	return (tclk->parent->rate / best_div);
+}
+
+/* Given a clock and a rate apply a clock specific rounding function */
+static long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	u32 new_div = 0;
+	int valid_rate;
+
+	if (clk->flags & RATE_FIXED)
+		return clk->rate;
+
+	if (clk->flags & RATE_CKCTL) {
+		valid_rate = omap2_clksel_round_rate(clk, rate, &new_div);
+		return valid_rate;
+	}
+
+	if (clk->round_rate != 0)
+		return clk->round_rate(clk, rate);
+
+	return clk->rate;
+}
+
+/*
+ * Check the DLL lock state, and return tue if running in unlock mode.
+ * This is needed to compenste for the shifted DLL value in unlock mode.
+ */
+static u32 omap2_dll_force_needed(void)
+{
+	u32 dll_state = SDRC_DLLA_CTRL;		/* dlla and dllb are a set */
+
+	if ((dll_state & (1 << 2)) == (1 << 2))
+		return 1;
+	else
+		return 0;
+}
+
+static void omap2_init_memory_params(u32 force_lock_to_unlock_mode)
+{
+	unsigned long dll_cnt;
+	u32 fast_dll = 0;
+
+	mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */
+
+	/* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others.
+	 * In the case of 2422, its ok to use CS1 instead of CS0.
+	 */
+
+#if 0	/* FIXME: Enable after 24xx cpu detection works */
+	ctype = get_cpu_type();
+	if (cpu_is_omap2422())
+		mem_timings.base_cs = 1;
+	else
+#endif
+		mem_timings.base_cs = 0;
+
+	if (mem_timings.m_type != M_DDR)
+		return;
+
+	/* With DDR we need to determine the low frequency DLL value */
+	if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL))
+		mem_timings.dll_mode = M_UNLOCK;
+	else
+		mem_timings.dll_mode = M_LOCK;
+
+	if (mem_timings.base_cs == 0) {
+		fast_dll = SDRC_DLLA_CTRL;
+		dll_cnt = SDRC_DLLA_STATUS & 0xff00;
+	} else {
+		fast_dll = SDRC_DLLB_CTRL;
+		dll_cnt = SDRC_DLLB_STATUS & 0xff00;
+	}
+	if (force_lock_to_unlock_mode) {
+		fast_dll &= ~0xff00;
+		fast_dll |= dll_cnt;		/* Current lock mode */
+	}
+	mem_timings.fast_dll_ctrl = fast_dll;
+
+	/* No disruptions, DDR will be offline & C-ABI not followed */
+	omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl,
+			    mem_timings.fast_dll_ctrl,
+			    mem_timings.base_cs,
+			    force_lock_to_unlock_mode);
+	mem_timings.slow_dll_ctrl &= 0xff00;	/* Keep lock value */
+
+	/* Turn status into unlock ctrl */
+	mem_timings.slow_dll_ctrl |=
+		((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2));
+
+	/* 90 degree phase for anything below 133Mhz */
+	mem_timings.slow_dll_ctrl |= (1 << 1);
+}
+
+static u32 omap2_reprogram_sdrc(u32 level, u32 force)
+{
+	u32 prev = curr_perf_level, flags;
+
+	if ((curr_perf_level == level) && !force)
+		return prev;
+
+	if (level == PRCM_HALF_SPEED) {
+		local_irq_save(flags);
+		PRCM_VOLTSETUP = 0xffff;
+		omap2_sram_reprogram_sdrc(PRCM_HALF_SPEED,
+					  mem_timings.slow_dll_ctrl,
+					  mem_timings.m_type);
+		curr_perf_level = PRCM_HALF_SPEED;
+		local_irq_restore(flags);
+	}
+	if (level == PRCM_FULL_SPEED) {
+		local_irq_save(flags);
+		PRCM_VOLTSETUP = 0xffff;
+		omap2_sram_reprogram_sdrc(PRCM_FULL_SPEED,
+					  mem_timings.fast_dll_ctrl,
+					  mem_timings.m_type);
+		curr_perf_level = PRCM_FULL_SPEED;
+		local_irq_restore(flags);
+	}
+
+	return prev;
+}
+
+static int omap2_reprogram_dpll(struct clk * clk, unsigned long rate)
+{
+	u32 flags, cur_rate, low, mult, div, valid_rate, done_rate;
+	u32 bypass = 0;
+	struct prcm_config tmpset;
+	int ret = -EINVAL;
+
+	local_irq_save(flags);
+	cur_rate = omap2_get_dpll_rate(&dpll_ck);
+	mult = CM_CLKSEL2_PLL & 0x3;
+
+	if ((rate == (cur_rate / 2)) && (mult == 2)) {
+		omap2_reprogram_sdrc(PRCM_HALF_SPEED, 1);
+	} else if ((rate == (cur_rate * 2)) && (mult == 1)) {
+		omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1);
+	} else if (rate != cur_rate) {
+		valid_rate = omap2_dpll_round_rate(rate);
+		if (valid_rate != rate)
+			goto dpll_exit;
+
+		if ((CM_CLKSEL2_PLL & 0x3) == 1)
+			low = curr_prcm_set->dpll_speed;
+		else
+			low = curr_prcm_set->dpll_speed / 2;
+
+		tmpset.cm_clksel1_pll = CM_CLKSEL1_PLL;
+		tmpset.cm_clksel1_pll &= ~(0x3FFF << 8);
+		div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
+		tmpset.cm_clksel2_pll = CM_CLKSEL2_PLL;
+		tmpset.cm_clksel2_pll &= ~0x3;
+		if (rate > low) {
+			tmpset.cm_clksel2_pll |= 0x2;
+			mult = ((rate / 2) / 1000000);
+			done_rate = PRCM_FULL_SPEED;
+		} else {
+			tmpset.cm_clksel2_pll |= 0x1;
+			mult = (rate / 1000000);
+			done_rate = PRCM_HALF_SPEED;
+		}
+		tmpset.cm_clksel1_pll |= ((div << 8) | (mult << 12));
+
+		/* Worst case */
+		tmpset.base_sdrc_rfr = V24XX_SDRC_RFR_CTRL_BYPASS;
+
+		if (rate == curr_prcm_set->xtal_speed)	/* If asking for 1-1 */
+			bypass = 1;
+
+		omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1); /* For init_mem */
+
+		/* Force dll lock mode */
+		omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
+			       bypass);
+
+		/* Errata: ret dll entry state */
+		omap2_init_memory_params(omap2_dll_force_needed());
+		omap2_reprogram_sdrc(done_rate, 0);
+	}
+	omap2_clksel_recalc(&dpll_ck);
+	ret = 0;
+
+dpll_exit:
+	local_irq_restore(flags);
+	return(ret);
+}
+
+/* Just return the MPU speed */
+static void omap2_mpu_recalc(struct clk * clk)
+{
+	clk->rate = curr_prcm_set->mpu_speed;
+}
+
+/*
+ * Look for a rate equal or less than the target rate given a configuration set.
+ *
+ * What's not entirely clear is "which" field represents the key field.
+ * Some might argue L3-DDR, others ARM, others IVA. This code is simple and
+ * just uses the ARM rates.
+ */
+static long omap2_round_to_table_rate(struct clk * clk, unsigned long rate)
+{
+	struct prcm_config * ptr;
+	long highest_rate;
+
+	if (clk != &virt_prcm_set)
+		return -EINVAL;
+
+	highest_rate = -EINVAL;
+
+	for (ptr = rate_table; ptr->mpu_speed; ptr++) {
+		if (ptr->xtal_speed != sys_ck.rate)
+			continue;
+
+		highest_rate = ptr->mpu_speed;
+
+		/* Can check only after xtal frequency check */
+		if (ptr->mpu_speed <= rate)
+			break;
+	}
+	return highest_rate;
+}
+
+/*
+ * omap2_convert_field_to_div() - turn field value into integer divider
+ */
+static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val)
+{
+	u32 i;
+	u32 clkout_array[] = {1, 2, 4, 8, 16};
+
+	if ((div_sel & SRC_RATE_SEL_MASK) == CM_SYSCLKOUT_SEL1) {
+		for (i = 0; i < 5; i++) {
+			if (field_val == i)
+				return clkout_array[i];
+		}
+		return ~0;
+	} else
+		return field_val;
+}
+
+/*
+ * Returns the CLKSEL divider register value
+ * REVISIT: This should be cleaned up to work nicely with void __iomem *
+ */
+static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask,
+			    struct clk *clk)
+{
+	int ret = ~0;
+	u32 reg_val, div_off;
+	u32 div_addr = 0;
+	u32 mask = ~0;
+
+	div_off = clk->rate_offset;
+
+	switch ((*div_sel & SRC_RATE_SEL_MASK)) {
+	case CM_MPU_SEL1:
+		div_addr = (u32)&CM_CLKSEL_MPU;
+		mask = 0x1f;
+		break;
+	case CM_DSP_SEL1:
+		div_addr = (u32)&CM_CLKSEL_DSP;
+		if (cpu_is_omap2420()) {
+			if ((div_off == 0) || (div_off == 8))
+				mask = 0x1f;
+			else if (div_off == 5)
+				mask = 0x3;
+		} else if (cpu_is_omap2430()) {
+			if (div_off == 0)
+				mask = 0x1f;
+			else if (div_off == 5)
+				mask = 0x3;
+		}
+		break;
+	case CM_GFX_SEL1:
+		div_addr = (u32)&CM_CLKSEL_GFX;
+		if (div_off == 0)
+			mask = 0x7;
+		break;
+	case CM_MODEM_SEL1:
+		div_addr = (u32)&CM_CLKSEL_MDM;
+		if (div_off == 0)
+			mask = 0xf;
+		break;
+	case CM_SYSCLKOUT_SEL1:
+		div_addr = (u32)&PRCM_CLKOUT_CTRL;
+		if ((div_off == 3) || (div_off = 11))
+			mask= 0x3;
+		break;
+	case CM_CORE_SEL1:
+		div_addr = (u32)&CM_CLKSEL1_CORE;
+		switch (div_off) {
+		case 0:					/* l3 */
+		case 8:					/* dss1 */
+		case 15:				/* vylnc-2420 */
+		case 20:				/* ssi */
+			mask = 0x1f; break;
+		case 5:					/* l4 */
+			mask = 0x3; break;
+		case 13:				/* dss2 */
+			mask = 0x1; break;
+		case 25:				/* usb */
+			mask = 0xf; break;
+		}
+	}
+
+	*field_mask = mask;
+
+	if (unlikely(mask == ~0))
+		div_addr = 0;
+
+	*div_sel = div_addr;
+
+	if (unlikely(div_addr == 0))
+		return ret;
+
+	/* Isolate field */
+	reg_val = __raw_readl((void __iomem *)div_addr) & (mask << div_off);
+
+	/* Normalize back to divider value */
+	reg_val >>= div_off;
+
+	return reg_val;
+}
+
+/*
+ * Return divider to be applied to parent clock.
+ * Return 0 on error.
+ */
+static u32 omap2_clksel_get_divisor(struct clk *clk)
+{
+	int ret = 0;
+	u32 div, div_sel, div_off, field_mask, field_val;
+
+	/* isolate control register */
+	div_sel = (SRC_RATE_SEL_MASK & clk->flags);
+
+	div_off = clk->rate_offset;
+	field_val = omap2_get_clksel(&div_sel, &field_mask, clk);
+	if (div_sel == 0)
+		return ret;
+
+	div_sel = (SRC_RATE_SEL_MASK & clk->flags);
+	div = omap2_clksel_to_divisor(div_sel, field_val);
+
+	return div;
+}
+
+/* Set the clock rate for a clock source */
+static int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
+
+{
+	int ret = -EINVAL;
+	void __iomem * reg;
+	u32 div_sel, div_off, field_mask, field_val, reg_val, validrate;
+	u32 new_div = 0;
+
+	if (!(clk->flags & CONFIG_PARTICIPANT) && (clk->flags & RATE_CKCTL)) {
+		if (clk == &dpll_ck)
+			return omap2_reprogram_dpll(clk, rate);
+
+		/* Isolate control register */
+		div_sel = (SRC_RATE_SEL_MASK & clk->flags);
+		div_off = clk->src_offset;
+
+		validrate = omap2_clksel_round_rate(clk, rate, &new_div);
+		if(validrate != rate)
+			return(ret);
+
+		field_val = omap2_get_clksel(&div_sel, &field_mask, clk);
+		if (div_sel == 0)
+			return ret;
+
+		if(clk->flags & CM_SYSCLKOUT_SEL1){
+			switch(new_div){
+			case 16: field_val = 4; break;
+			case 8:  field_val = 3; break;
+			case 4:  field_val = 2; break;
+			case 2:  field_val = 1; break;
+			case 1:  field_val = 0; break;
+			}
+		}
+		else
+			field_val = new_div;
+
+		reg = (void __iomem *)div_sel;
+
+		reg_val = __raw_readl(reg);
+		reg_val &= ~(field_mask << div_off);
+		reg_val |= (field_val << div_off);
+
+		__raw_writel(reg_val, reg);
+		clk->rate = clk->parent->rate / field_val;
+
+		if (clk->flags & DELAYED_APP)
+			__raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
+		ret = 0;
+	} else if (clk->set_rate != 0)
+		ret = clk->set_rate(clk, rate);
+
+	if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
+		propagate_rate(clk);
+
+	return ret;
+}
+
+/* Converts encoded control register address into a full address */
+static u32 omap2_get_src_field(u32 *type_to_addr, u32 reg_offset,
+			       struct clk *src_clk, u32 *field_mask)
+{
+	u32 val = ~0, src_reg_addr = 0, mask = 0;
+
+	/* Find target control register.*/
+	switch ((*type_to_addr & SRC_RATE_SEL_MASK)) {
+	case CM_CORE_SEL1:
+		src_reg_addr = (u32)&CM_CLKSEL1_CORE;
+		if (reg_offset == 13) {			/* DSS2_fclk */
+			mask = 0x1;
+			if (src_clk == &sys_ck)
+				val = 0;
+			if (src_clk == &func_48m_ck)
+				val = 1;
+		} else if (reg_offset == 8) {		/* DSS1_fclk */
+			mask = 0x1f;
+			if (src_clk == &sys_ck)
+				val = 0;
+			else if (src_clk == &core_ck)	/* divided clock */
+				val = 0x10;		/* rate needs fixing */
+		} else if ((reg_offset == 15) && cpu_is_omap2420()){ /*vlnyq*/
+			mask = 0x1F;
+			if(src_clk == &func_96m_ck)
+				val = 0;
+			else if (src_clk == &core_ck)
+				val = 0x10;
+		}
+		break;
+	case CM_CORE_SEL2:
+		src_reg_addr = (u32)&CM_CLKSEL2_CORE;
+		mask = 0x3;
+		if (src_clk == &func_32k_ck)
+			val = 0x0;
+		if (src_clk == &sys_ck)
+			val = 0x1;
+		if (src_clk == &alt_ck)
+			val = 0x2;
+		break;
+	case CM_WKUP_SEL1:
+		src_reg_addr = (u32)&CM_CLKSEL2_CORE;
+		mask = 0x3;
+		if (src_clk == &func_32k_ck)
+			val = 0x0;
+		if (src_clk == &sys_ck)
+			val = 0x1;
+		if (src_clk == &alt_ck)
+			val = 0x2;
+		break;
+	case CM_PLL_SEL1:
+		src_reg_addr = (u32)&CM_CLKSEL1_PLL;
+		mask = 0x1;
+		if (reg_offset == 0x3) {
+			if (src_clk == &apll96_ck)
+				val = 0;
+			if (src_clk == &alt_ck)
+				val = 1;
+		}
+		else if (reg_offset == 0x5) {
+			if (src_clk == &apll54_ck)
+				val = 0;
+			if (src_clk == &alt_ck)
+				val = 1;
+		}
+		break;
+	case CM_PLL_SEL2:
+		src_reg_addr = (u32)&CM_CLKSEL2_PLL;
+		mask = 0x3;
+		if (src_clk == &func_32k_ck)
+			val = 0x0;
+		if (src_clk == &dpll_ck)
+			val = 0x2;
+		break;
+	case CM_SYSCLKOUT_SEL1:
+		src_reg_addr = (u32)&PRCM_CLKOUT_CTRL;
+		mask = 0x3;
+		if (src_clk == &dpll_ck)
+			val = 0;
+		if (src_clk == &sys_ck)
+			val = 1;
+		if (src_clk == &func_54m_ck)
+			val = 2;
+		if (src_clk == &func_96m_ck)
+			val = 3;
+		break;
+	}
+
+	if (val == ~0)			/* Catch errors in offset */
+		*type_to_addr = 0;
+	else
+		*type_to_addr = src_reg_addr;
+	*field_mask = mask;
+
+	return val;
+}
+
+static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
+{
+	void __iomem * reg;
+	u32 src_sel, src_off, field_val, field_mask, reg_val, rate;
+	int ret = -EINVAL;
+
+	if (unlikely(clk->flags & CONFIG_PARTICIPANT))
+		return ret;
+
+	if (clk->flags & SRC_SEL_MASK) {	/* On-chip SEL collection */
+		src_sel = (SRC_RATE_SEL_MASK & clk->flags);
+		src_off = clk->src_offset;
+
+		if (src_sel == 0)
+			goto set_parent_error;
+
+		field_val = omap2_get_src_field(&src_sel, src_off, new_parent,
+						&field_mask);
+
+		reg = (void __iomem *)src_sel;
+
+		if (clk->usecount > 0)
+			omap2_clk_disable(clk);
+
+		/* Set new source value (previous dividers if any in effect) */
+		reg_val = __raw_readl(reg) & ~(field_mask << src_off);
+		reg_val |= (field_val << src_off);
+		__raw_writel(reg_val, reg);
+
+		if (clk->flags & DELAYED_APP)
+			__raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
+
+		if (clk->usecount > 0)
+			omap2_clk_enable(clk);
+
+		clk->parent = new_parent;
+
+		/* SRC_RATE_SEL_MASK clocks follow their parents rates.*/
+		if ((new_parent == &core_ck) && (clk == &dss1_fck))
+			clk->rate = new_parent->rate / 0x10;
+		else
+			clk->rate = new_parent->rate;
+
+		if (unlikely(clk->flags & RATE_PROPAGATES))
+			propagate_rate(clk);
+
+		return 0;
+	} else {
+		clk->parent = new_parent;
+		rate = new_parent->rate;
+		omap2_clk_set_rate(clk, rate);
+		ret = 0;
+	}
+
+ set_parent_error:
+	return ret;
+}
+
+/* Sets basic clocks based on the specified rate */
+static int omap2_select_table_rate(struct clk * clk, unsigned long rate)
+{
+	u32 flags, cur_rate, done_rate, bypass = 0;
+	u8 cpu_mask = 0;
+	struct prcm_config *prcm;
+	unsigned long found_speed = 0;
+
+	if (clk != &virt_prcm_set)
+		return -EINVAL;
+
+	/* FIXME: Change cpu_is_omap2420() to cpu_is_omap242x() */
+	if (cpu_is_omap2420())
+		cpu_mask = RATE_IN_242X;
+	else if (cpu_is_omap2430())
+		cpu_mask = RATE_IN_243X;
+
+	for (prcm = rate_table; prcm->mpu_speed; prcm++) {
+		if (!(prcm->flags & cpu_mask))
+			continue;
+
+		if (prcm->xtal_speed != sys_ck.rate)
+			continue;
+
+		if (prcm->mpu_speed <= rate) {
+			found_speed = prcm->mpu_speed;
+			break;
+		}
+	}
+
+	if (!found_speed) {
+		printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
+	 rate / 1000000);
+		return -EINVAL;
+	}
+
+	curr_prcm_set = prcm;
+	cur_rate = omap2_get_dpll_rate(&dpll_ck);
+
+	if (prcm->dpll_speed == cur_rate / 2) {
+		omap2_reprogram_sdrc(PRCM_HALF_SPEED, 1);
+	} else if (prcm->dpll_speed == cur_rate * 2) {
+		omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1);
+	} else if (prcm->dpll_speed != cur_rate) {
+		local_irq_save(flags);
+
+		if (prcm->dpll_speed == prcm->xtal_speed)
+			bypass = 1;
+
+		if ((prcm->cm_clksel2_pll & 0x3) == 2)
+			done_rate = PRCM_FULL_SPEED;
+		else
+			done_rate = PRCM_HALF_SPEED;
+
+		/* MPU divider */
+		CM_CLKSEL_MPU = prcm->cm_clksel_mpu;
+
+		/* dsp + iva1 div(2420), iva2.1(2430) */
+		CM_CLKSEL_DSP = prcm->cm_clksel_dsp;
+
+		CM_CLKSEL_GFX = prcm->cm_clksel_gfx;
+
+		/* Major subsystem dividers */
+		CM_CLKSEL1_CORE = prcm->cm_clksel1_core;
+		if (cpu_is_omap2430())
+			CM_CLKSEL_MDM = prcm->cm_clksel_mdm;
+
+		/* x2 to enter init_mem */
+		omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1);
+
+		omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
+			       bypass);
+
+		omap2_init_memory_params(omap2_dll_force_needed());
+		omap2_reprogram_sdrc(done_rate, 0);
+
+		local_irq_restore(flags);
+	}
+	omap2_clksel_recalc(&dpll_ck);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------
+ * Omap2 clock reset and init functions
+ *-------------------------------------------------------------------------*/
+
+static struct clk_functions omap2_clk_functions = {
+	.clk_enable		= omap2_clk_enable,
+	.clk_disable		= omap2_clk_disable,
+	.clk_use		= omap2_clk_use,
+	.clk_unuse		= omap2_clk_unuse,
+	.clk_round_rate		= omap2_clk_round_rate,
+	.clk_set_rate		= omap2_clk_set_rate,
+	.clk_set_parent		= omap2_clk_set_parent,
+};
+
+static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys)
+{
+	u32 div, aplls, sclk = 13000000;
+
+	aplls = CM_CLKSEL1_PLL;
+	aplls &= ((1 << 23) | (1 << 24) | (1 << 25));
+	aplls >>= 23;			/* Isolate field, 0,2,3 */
+
+	if (aplls == 0)
+		sclk = 19200000;
+	else if (aplls == 2)
+		sclk = 13000000;
+	else if (aplls == 3)
+		sclk = 12000000;
+
+	div = PRCM_CLKSRC_CTRL;
+	div &= ((1 << 7) | (1 << 6));
+	div >>= sys->rate_offset;
+
+	osc->rate = sclk * div;
+	sys->rate = sclk;
+}
+
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+static void __init omap2_disable_unused_clocks(void)
+{
+	struct clk *ck;
+	u32 regval32;
+
+	list_for_each_entry(ck, &clocks, node) {
+		if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
+			ck->enable_reg == 0)
+			continue;
+
+		regval32 = __raw_readl(ck->enable_reg);
+		if ((regval32 & (1 << ck->enable_bit)) == 0)
+			continue;
+
+		printk(KERN_INFO "Disabling unused clock \"%s\"\n", ck->name);
+		omap2_clk_disable(ck);
+	}
+}
+late_initcall(omap2_disable_unused_clocks);
+#endif
+
+/*
+ * Switch the MPU rate if specified on cmdline.
+ * We cannot do this early until cmdline is parsed.
+ */
+static int __init omap2_clk_arch_init(void)
+{
+	if (!mpurate)
+		return -EINVAL;
+
+	if (omap2_select_table_rate(&virt_prcm_set, mpurate))
+		printk(KERN_ERR "Could not find matching MPU rate\n");
+
+	propagate_rate(&osc_ck);		/* update main root fast */
+	propagate_rate(&func_32k_ck);		/* update main root slow */
+
+	printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL/MPU): "
+	       "%ld.%01ld/%ld/%ld MHz\n",
+	       (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
+	       (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;
+
+	return 0;
+}
+arch_initcall(omap2_clk_arch_init);
+
+int __init omap2_clk_init(void)
+{
+	struct prcm_config *prcm;
+	struct clk ** clkp;
+	u32 clkrate;
+
+	clk_init(&omap2_clk_functions);
+	omap2_get_crystal_rate(&osc_ck, &sys_ck);
+
+	for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
+	     clkp++) {
+
+		if ((*clkp)->flags & CLOCK_IN_OMAP242X && cpu_is_omap2420()) {
+			clk_register(*clkp);
+			continue;
+		}
+
+		if ((*clkp)->flags & CLOCK_IN_OMAP243X && cpu_is_omap2430()) {
+			clk_register(*clkp);
+			continue;
+		}
+	}
+
+	/* Check the MPU rate set by bootloader */
+	clkrate = omap2_get_dpll_rate(&dpll_ck);
+	for (prcm = rate_table; prcm->mpu_speed; prcm++) {
+		if (prcm->xtal_speed != sys_ck.rate)
+			continue;
+		if (prcm->dpll_speed <= clkrate)
+			 break;
+	}
+	curr_prcm_set = prcm;
+
+	propagate_rate(&osc_ck);		/* update main root fast */
+	propagate_rate(&func_32k_ck);		/* update main root slow */
+
+	printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): "
+	       "%ld.%01ld/%ld/%ld MHz\n",
+	       (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
+	       (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;
+
+	/*
+	 * Only enable those clocks we will need, let the drivers
+	 * enable other clocks as necessary
+	 */
+	clk_use(&sync_32k_ick);
+	clk_use(&omapctrl_ick);
+	if (cpu_is_omap2430())
+		clk_use(&sdrc_ick);
+
+	return 0;
+}
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
new file mode 100644
index 0000000..4aeab55
--- /dev/null
+++ b/arch/arm/mach-omap2/clock.h
@@ -0,0 +1,2103 @@
+/*
+ *  linux/arch/arm/mach-omap24xx/clock.h
+ *
+ *  Copyright (C) 2005 Texas Instruments Inc.
+ *  Richard Woodruff <r-woodruff2@ti.com>
+ *  Created for OMAP2.
+ *
+ *  Copyright (C) 2004 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *  Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, 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 __ARCH_ARM_MACH_OMAP2_CLOCK_H
+#define __ARCH_ARM_MACH_OMAP2_CLOCK_H
+
+static void omap2_sys_clk_recalc(struct clk * clk);
+static void omap2_clksel_recalc(struct clk * clk);
+static void omap2_followparent_recalc(struct clk * clk);
+static void omap2_propagate_rate(struct clk * clk);
+static void omap2_mpu_recalc(struct clk * clk);
+static int omap2_select_table_rate(struct clk * clk, unsigned long rate);
+static long omap2_round_to_table_rate(struct clk * clk, unsigned long rate);
+static void omap2_clk_unuse(struct clk *clk);
+static void omap2_sys_clk_recalc(struct clk * clk);
+static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val);
+static u32 omap2_clksel_get_divisor(struct clk *clk);
+
+
+#define RATE_IN_242X	(1 << 0)
+#define RATE_IN_243X	(1 << 1)
+
+/* Memory timings */
+#define M_DDR		1
+#define M_LOCK_CTRL	(1 << 2)
+#define M_UNLOCK	0
+#define M_LOCK		1
+
+struct memory_timings {
+	u32 m_type;		/* ddr = 1, sdr = 0 */
+	u32 dll_mode;		/* use lock mode = 1, unlock mode = 0 */
+	u32 slow_dll_ctrl;	/* unlock mode, dll value for slow speed */
+	u32 fast_dll_ctrl;	/* unlock mode, dll value for fast speed */
+	u32 base_cs;		/* base chip select to use for calculations */
+};
+
+/* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated.
+ * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP
+ * CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL CM_CLKSEL2_PLL, CM_CLKSEL_MDM
+ */
+struct prcm_config {
+	unsigned long xtal_speed;	/* crystal rate */
+	unsigned long dpll_speed;	/* dpll: out*xtal*M/(N-1)table_recalc */
+	unsigned long mpu_speed;	/* speed of MPU */
+	unsigned long cm_clksel_mpu;	/* mpu divider */
+	unsigned long cm_clksel_dsp;	/* dsp+iva1 div(2420), iva2.1(2430) */
+	unsigned long cm_clksel_gfx;	/* gfx dividers */
+	unsigned long cm_clksel1_core;	/* major subsystem dividers */
+	unsigned long cm_clksel1_pll;	/* m,n */
+	unsigned long cm_clksel2_pll;	/* dpllx1 or x2 out */
+	unsigned long cm_clksel_mdm;	/* modem dividers 2430 only */
+	unsigned long base_sdrc_rfr;	/* base refresh timing for a set */
+	unsigned char flags;
+};
+
+/* Mask for clksel which support parent settign in set_rate */
+#define SRC_SEL_MASK (CM_CORE_SEL1 | CM_CORE_SEL2 | CM_WKUP_SEL1 | \
+			CM_PLL_SEL1 | CM_PLL_SEL2 | CM_SYSCLKOUT_SEL1)
+
+/* Mask for clksel regs which support rate operations */
+#define SRC_RATE_SEL_MASK (CM_MPU_SEL1 | CM_DSP_SEL1 | CM_GFX_SEL1 | \
+			CM_MODEM_SEL1 | CM_CORE_SEL1 | CM_CORE_SEL2 | \
+			CM_WKUP_SEL1 | CM_PLL_SEL1 | CM_PLL_SEL2 | \
+			CM_SYSCLKOUT_SEL1)
+
+/*
+ * The OMAP2 processor can be run at several discrete 'PRCM configurations'.
+ * These configurations are characterized by voltage and speed for clocks.
+ * The device is only validated for certain combinations. One way to express
+ * these combinations is via the 'ratio's' which the clocks operate with
+ * respect to each other. These ratio sets are for a given voltage/DPLL
+ * setting. All configurations can be described by a DPLL setting and a ratio
+ * There are 3 ratio sets for the 2430 and X ratio sets for 2420.
+ *
+ * 2430 differs from 2420 in that there are no more phase synchronizers used.
+ * They both have a slightly different clock domain setup. 2420(iva1,dsp) vs
+ * 2430 (iva2.1, NOdsp, mdm)
+ */
+
+/* Core fields for cm_clksel, not ratio governed */
+#define RX_CLKSEL_DSS1			(0x10 << 8)
+#define RX_CLKSEL_DSS2			(0x0 << 13)
+#define RX_CLKSEL_SSI			(0x5 << 20)
+
+/*-------------------------------------------------------------------------
+ * Voltage/DPLL ratios
+ *-------------------------------------------------------------------------*/
+
+/* 2430 Ratio's, 2430-Ratio Config 1 */
+#define R1_CLKSEL_L3			(4 << 0)
+#define R1_CLKSEL_L4			(2 << 5)
+#define R1_CLKSEL_USB			(4 << 25)
+#define R1_CM_CLKSEL1_CORE_VAL		R1_CLKSEL_USB | RX_CLKSEL_SSI | \
+					RX_CLKSEL_DSS2 | RX_CLKSEL_DSS1 | \
+					R1_CLKSEL_L4 | R1_CLKSEL_L3
+#define R1_CLKSEL_MPU			(2 << 0)
+#define R1_CM_CLKSEL_MPU_VAL		R1_CLKSEL_MPU
+#define R1_CLKSEL_DSP			(2 << 0)
+#define R1_CLKSEL_DSP_IF		(2 << 5)
+#define R1_CM_CLKSEL_DSP_VAL		R1_CLKSEL_DSP | R1_CLKSEL_DSP_IF
+#define R1_CLKSEL_GFX			(2 << 0)
+#define R1_CM_CLKSEL_GFX_VAL		R1_CLKSEL_GFX
+#define R1_CLKSEL_MDM			(4 << 0)
+#define R1_CM_CLKSEL_MDM_VAL		R1_CLKSEL_MDM
+
+/* 2430-Ratio Config 2 */
+#define R2_CLKSEL_L3			(6 << 0)
+#define R2_CLKSEL_L4			(2 << 5)
+#define R2_CLKSEL_USB			(2 << 25)
+#define R2_CM_CLKSEL1_CORE_VAL		R2_CLKSEL_USB | RX_CLKSEL_SSI | \
+					RX_CLKSEL_DSS2 | RX_CLKSEL_DSS1 | \
+					R2_CLKSEL_L4 | R2_CLKSEL_L3
+#define R2_CLKSEL_MPU			(2 << 0)
+#define R2_CM_CLKSEL_MPU_VAL		R2_CLKSEL_MPU
+#define R2_CLKSEL_DSP			(2 << 0)
+#define R2_CLKSEL_DSP_IF		(3 << 5)
+#define R2_CM_CLKSEL_DSP_VAL		R2_CLKSEL_DSP | R2_CLKSEL_DSP_IF
+#define R2_CLKSEL_GFX			(2 << 0)
+#define R2_CM_CLKSEL_GFX_VAL		R2_CLKSEL_GFX
+#define R2_CLKSEL_MDM			(6 << 0)
+#define R2_CM_CLKSEL_MDM_VAL		R2_CLKSEL_MDM
+
+/* 2430-Ratio Bootm (BYPASS) */
+#define RB_CLKSEL_L3			(1 << 0)
+#define RB_CLKSEL_L4			(1 << 5)
+#define RB_CLKSEL_USB			(1 << 25)
+#define RB_CM_CLKSEL1_CORE_VAL		RB_CLKSEL_USB | RX_CLKSEL_SSI | \
+					RX_CLKSEL_DSS2 | RX_CLKSEL_DSS1 | \
+					RB_CLKSEL_L4 | RB_CLKSEL_L3
+#define RB_CLKSEL_MPU			(1 << 0)
+#define RB_CM_CLKSEL_MPU_VAL		RB_CLKSEL_MPU
+#define RB_CLKSEL_DSP			(1 << 0)
+#define RB_CLKSEL_DSP_IF		(1 << 5)
+#define RB_CM_CLKSEL_DSP_VAL		RB_CLKSEL_DSP | RB_CLKSEL_DSP_IF
+#define RB_CLKSEL_GFX			(1 << 0)
+#define RB_CM_CLKSEL_GFX_VAL		RB_CLKSEL_GFX
+#define RB_CLKSEL_MDM			(1 << 0)
+#define RB_CM_CLKSEL_MDM_VAL		RB_CLKSEL_MDM
+
+/* 2420 Ratio Equivalents */
+#define RXX_CLKSEL_VLYNQ		(0x12 << 15)
+#define RXX_CLKSEL_SSI			(0x8 << 20)
+
+/* 2420-PRCM III 532MHz core */
+#define RIII_CLKSEL_L3			(4 << 0)	/* 133MHz */
+#define RIII_CLKSEL_L4			(2 << 5)	/* 66.5MHz */
+#define RIII_CLKSEL_USB			(4 << 25)	/* 33.25MHz */
+#define RIII_CM_CLKSEL1_CORE_VAL	RIII_CLKSEL_USB | RXX_CLKSEL_SSI | \
+					RXX_CLKSEL_VLYNQ | RX_CLKSEL_DSS2 | \
+					RX_CLKSEL_DSS1 | RIII_CLKSEL_L4 | \
+					RIII_CLKSEL_L3
+#define RIII_CLKSEL_MPU			(2 << 0)	/* 266MHz */
+#define RIII_CM_CLKSEL_MPU_VAL		RIII_CLKSEL_MPU
+#define RIII_CLKSEL_DSP			(3 << 0)	/* c5x - 177.3MHz */
+#define RIII_CLKSEL_DSP_IF		(2 << 5)	/* c5x - 88.67MHz */
+#define RIII_SYNC_DSP			(1 << 7)	/* Enable sync */
+#define RIII_CLKSEL_IVA			(6 << 8)	/* iva1 - 88.67MHz */
+#define RIII_SYNC_IVA			(1 << 13)	/* Enable sync */
+#define RIII_CM_CLKSEL_DSP_VAL		RIII_SYNC_IVA | RIII_CLKSEL_IVA | \
+					RIII_SYNC_DSP | RIII_CLKSEL_DSP_IF | \
+					RIII_CLKSEL_DSP
+#define RIII_CLKSEL_GFX			(2 << 0)	/* 66.5MHz */
+#define RIII_CM_CLKSEL_GFX_VAL		RIII_CLKSEL_GFX
+
+/* 2420-PRCM II 600MHz core */
+#define RII_CLKSEL_L3			(6 << 0)	/* 100MHz */
+#define RII_CLKSEL_L4			(2 << 5)	/* 50MHz */
+#define RII_CLKSEL_USB			(2 << 25)	/* 50MHz */
+#define RII_CM_CLKSEL1_CORE_VAL		RII_CLKSEL_USB | \
+					RXX_CLKSEL_SSI | RXX_CLKSEL_VLYNQ | \
+					RX_CLKSEL_DSS2 | RX_CLKSEL_DSS1 | \
+					RII_CLKSEL_L4 | RII_CLKSEL_L3
+#define RII_CLKSEL_MPU			(2 << 0)	/* 300MHz */
+#define RII_CM_CLKSEL_MPU_VAL		RII_CLKSEL_MPU
+#define RII_CLKSEL_DSP			(3 << 0)	/* c5x - 200MHz */
+#define RII_CLKSEL_DSP_IF		(2 << 5)	/* c5x - 100MHz */
+#define RII_SYNC_DSP			(0 << 7)	/* Bypass sync */
+#define RII_CLKSEL_IVA			(6 << 8)	/* iva1 - 200MHz */
+#define RII_SYNC_IVA			(0 << 13)	/* Bypass sync */
+#define RII_CM_CLKSEL_DSP_VAL		RII_SYNC_IVA | RII_CLKSEL_IVA | \
+					RII_SYNC_DSP | RII_CLKSEL_DSP_IF | \
+					RII_CLKSEL_DSP
+#define RII_CLKSEL_GFX			(2 << 0)	/* 50MHz */
+#define RII_CM_CLKSEL_GFX_VAL		RII_CLKSEL_GFX
+
+/* 2420-PRCM VII (boot) */
+#define RVII_CLKSEL_L3			(1 << 0)
+#define RVII_CLKSEL_L4			(1 << 5)
+#define RVII_CLKSEL_DSS1		(1 << 8)
+#define RVII_CLKSEL_DSS2		(0 << 13)
+#define RVII_CLKSEL_VLYNQ		(1 << 15)
+#define RVII_CLKSEL_SSI			(1 << 20)
+#define RVII_CLKSEL_USB			(1 << 25)
+
+#define RVII_CM_CLKSEL1_CORE_VAL	RVII_CLKSEL_USB | RVII_CLKSEL_SSI | \
+					RVII_CLKSEL_VLYNQ | RVII_CLKSEL_DSS2 | \
+					RVII_CLKSEL_DSS1 | RVII_CLKSEL_L4 | RVII_CLKSEL_L3
+
+#define RVII_CLKSEL_MPU			(1 << 0) /* all divide by 1 */
+#define RVII_CM_CLKSEL_MPU_VAL		RVII_CLKSEL_MPU
+
+#define RVII_CLKSEL_DSP			(1 << 0)
+#define RVII_CLKSEL_DSP_IF		(1 << 5)
+#define RVII_SYNC_DSP			(0 << 7)
+#define RVII_CLKSEL_IVA			(1 << 8)
+#define RVII_SYNC_IVA			(0 << 13)
+#define RVII_CM_CLKSEL_DSP_VAL		RVII_SYNC_IVA | RVII_CLKSEL_IVA | RVII_SYNC_DSP | \
+					RVII_CLKSEL_DSP_IF | RVII_CLKSEL_DSP
+
+#define RVII_CLKSEL_GFX			(1 << 0)
+#define RVII_CM_CLKSEL_GFX_VAL		RVII_CLKSEL_GFX
+
+/*-------------------------------------------------------------------------
+ * 2430 Target modes: Along with each configuration the CPU has several
+ * modes which goes along with them. Modes mainly are the addition of
+ * describe DPLL combinations to go along with a ratio.
+ *-------------------------------------------------------------------------*/
+
+/* Hardware governed */
+#define MX_48M_SRC			(0 << 3)
+#define MX_54M_SRC			(0 << 5)
+#define MX_APLLS_CLIKIN_12		(3 << 23)
+#define MX_APLLS_CLIKIN_13		(2 << 23)
+#define MX_APLLS_CLIKIN_19_2		(0 << 23)
+
+/*
+ * 2430 - standalone, 2*ref*M/(n+1), M/N is for exactness not relock speed
+ * #2	(ratio1) baseport-target
+ * #5a	(ratio1) baseport-target, target DPLL = 266*2 = 532MHz
+ */
+#define M5A_DPLL_MULT_12		(133 << 12)
+#define M5A_DPLL_DIV_12			(5 << 8)
+#define M5A_CM_CLKSEL1_PLL_12_VAL	MX_48M_SRC | MX_54M_SRC | \
+					M5A_DPLL_DIV_12 | M5A_DPLL_MULT_12 | \
+					MX_APLLS_CLIKIN_12
+#define M5A_DPLL_MULT_13		(266 << 12)
+#define M5A_DPLL_DIV_13			(12 << 8)
+#define M5A_CM_CLKSEL1_PLL_13_VAL	MX_48M_SRC | MX_54M_SRC | \
+					M5A_DPLL_DIV_13 | M5A_DPLL_MULT_13 | \
+					MX_APLLS_CLIKIN_13
+#define M5A_DPLL_MULT_19		(180 << 12)
+#define M5A_DPLL_DIV_19			(12 << 8)
+#define M5A_CM_CLKSEL1_PLL_19_VAL	MX_48M_SRC | MX_54M_SRC | \
+					M5A_DPLL_DIV_19 | M5A_DPLL_MULT_19 | \
+					MX_APLLS_CLIKIN_19_2
+/* #5b	(ratio1) target DPLL = 200*2 = 400MHz */
+#define M5B_DPLL_MULT_12		(50 << 12)
+#define M5B_DPLL_DIV_12			(2 << 8)
+#define M5B_CM_CLKSEL1_PLL_12_VAL	MX_48M_SRC | MX_54M_SRC | \
+					M5B_DPLL_DIV_12 | M5B_DPLL_MULT_12 | \
+					MX_APLLS_CLIKIN_12
+#define M5B_DPLL_MULT_13		(200 << 12)
+#define M5B_DPLL_DIV_13			(12 << 8)
+
+#define M5B_CM_CLKSEL1_PLL_13_VAL	MX_48M_SRC | MX_54M_SRC | \
+					M5B_DPLL_DIV_13 | M5B_DPLL_MULT_13 | \
+					MX_APLLS_CLIKIN_13
+#define M5B_DPLL_MULT_19		(125 << 12)
+#define M5B_DPLL_DIV_19			(31 << 8)
+#define M5B_CM_CLKSEL1_PLL_19_VAL	MX_48M_SRC | MX_54M_SRC | \
+					M5B_DPLL_DIV_19 | M5B_DPLL_MULT_19 | \
+					MX_APLLS_CLIKIN_19_2
+/*
+ * #4	(ratio2)
+ * #3	(ratio2) baseport-target, target DPLL = 330*2 = 660MHz
+ */
+#define M3_DPLL_MULT_12			(55 << 12)
+#define M3_DPLL_DIV_12			(1 << 8)
+#define M3_CM_CLKSEL1_PLL_12_VAL	MX_48M_SRC | MX_54M_SRC | \
+					M3_DPLL_DIV_12 | M3_DPLL_MULT_12 | \
+					MX_APLLS_CLIKIN_12
+#define M3_DPLL_MULT_13			(330 << 12)
+#define M3_DPLL_DIV_13			(12 << 8)
+#define M3_CM_CLKSEL1_PLL_13_VAL	MX_48M_SRC | MX_54M_SRC | \
+					M3_DPLL_DIV_13 | M3_DPLL_MULT_13 | \
+					MX_APLLS_CLIKIN_13
+#define M3_DPLL_MULT_19			(275 << 12)
+#define M3_DPLL_DIV_19			(15 << 8)
+#define M3_CM_CLKSEL1_PLL_19_VAL	MX_48M_SRC | MX_54M_SRC | \
+					M3_DPLL_DIV_19 | M3_DPLL_MULT_19 | \
+					MX_APLLS_CLIKIN_19_2
+/* boot (boot) */
+#define MB_DPLL_MULT			(1 << 12)
+#define MB_DPLL_DIV			(0 << 8)
+#define MB_CM_CLKSEL1_PLL_12_VAL	MX_48M_SRC | MX_54M_SRC | MB_DPLL_DIV |\
+					MB_DPLL_MULT | MX_APLLS_CLIKIN_12
+
+#define MB_CM_CLKSEL1_PLL_13_VAL	MX_48M_SRC | MX_54M_SRC | MB_DPLL_DIV |\
+					MB_DPLL_MULT | MX_APLLS_CLIKIN_13
+
+#define MB_CM_CLKSEL1_PLL_19_VAL	MX_48M_SRC | MX_54M_SRC | MB_DPLL_DIV |\
+					MB_DPLL_MULT | MX_APLLS_CLIKIN_19
+
+/*
+ * 2430 - chassis (sedna)
+ * 165 (ratio1) same as above #2
+ * 150 (ratio1)
+ * 133 (ratio2) same as above #4
+ * 110 (ratio2) same as above #3
+ * 104 (ratio2)
+ * boot (boot)
+ */
+
+/*
+ * 2420 Equivalent - mode registers
+ * PRCM II , target DPLL = 2*300MHz = 600MHz
+ */
+#define MII_DPLL_MULT_12		(50 << 12)
+#define MII_DPLL_DIV_12			(1 << 8)
+#define MII_CM_CLKSEL1_PLL_12_VAL	MX_48M_SRC | MX_54M_SRC | \
+					MII_DPLL_DIV_12 | MII_DPLL_MULT_12 | \
+					MX_APLLS_CLIKIN_12
+#define MII_DPLL_MULT_13		(300 << 12)
+#define MII_DPLL_DIV_13			(12 << 8)
+#define MII_CM_CLKSEL1_PLL_13_VAL	MX_48M_SRC | MX_54M_SRC | \
+					MII_DPLL_DIV_13 | MII_DPLL_MULT_13 | \
+					MX_APLLS_CLIKIN_13
+
+/* PRCM III target DPLL = 2*266 = 532MHz*/
+#define MIII_DPLL_MULT_12		(133 << 12)
+#define MIII_DPLL_DIV_12		(5 << 8)
+#define MIII_CM_CLKSEL1_PLL_12_VAL	MX_48M_SRC | MX_54M_SRC | \
+					MIII_DPLL_DIV_12 | MIII_DPLL_MULT_12 | \
+					MX_APLLS_CLIKIN_12
+#define MIII_DPLL_MULT_13		(266 << 12)
+#define MIII_DPLL_DIV_13		(12 << 8)
+#define MIII_CM_CLKSEL1_PLL_13_VAL	MX_48M_SRC | MX_54M_SRC | \
+					MIII_DPLL_DIV_13 | MIII_DPLL_MULT_13 | \
+					MX_APLLS_CLIKIN_13
+
+/* PRCM VII (boot bypass) */
+#define MVII_CM_CLKSEL1_PLL_12_VAL	MB_CM_CLKSEL1_PLL_12_VAL
+#define MVII_CM_CLKSEL1_PLL_13_VAL	MB_CM_CLKSEL1_PLL_13_VAL
+
+/* High and low operation value */
+#define MX_CLKSEL2_PLL_2x_VAL		(2 << 0)
+#define MX_CLKSEL2_PLL_1x_VAL		(1 << 0)
+
+/*
+ * These represent optimal values for common parts, it won't work for all.
+ * As long as you scale down, most parameters are still work, they just
+ * become sub-optimal. The RFR value goes in the oppisite direction. If you
+ * don't adjust it down as your clock period increases the refresh interval
+ * will not be met. Setting all parameters for complete worst case may work,
+ * but may cut memory performance by 2x. Due to errata the DLLs need to be
+ * unlocked and their value needs run time calibration.	A dynamic call is
+ * need for that as no single right value exists acorss production samples.
+ *
+ * Only the FULL speed values are given. Current code is such that rate
+ * changes must be made at DPLLoutx2. The actual value adjustment for low
+ * frequency operation will be handled by omap_set_performance()
+ *
+ * By having the boot loader boot up in the fastest L4 speed available likely
+ * will result in something which you can switch between.
+ */
+#define V24XX_SDRC_RFR_CTRL_133MHz	(0x0003de00 | 1)
+#define V24XX_SDRC_RFR_CTRL_100MHz	(0x0002da01 | 1)
+#define V24XX_SDRC_RFR_CTRL_110MHz	(0x0002da01 | 1) /* Need to calc */
+#define V24XX_SDRC_RFR_CTRL_BYPASS	(0x00005000 | 1) /* Need to calc */
+
+/* MPU speed defines */
+#define S12M	12000000
+#define S13M	13000000
+#define S19M	19200000
+#define S26M	26000000
+#define S100M	100000000
+#define S133M	133000000
+#define S150M	150000000
+#define S165M	165000000
+#define S200M	200000000
+#define S266M	266000000
+#define S300M	300000000
+#define S330M	330000000
+#define S400M	400000000
+#define S532M	532000000
+#define S600M	600000000
+#define S660M	660000000
+
+/*-------------------------------------------------------------------------
+ * Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated.
+ * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,
+ * CM_CLKSEL_DSP, CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL,
+ * CM_CLKSEL2_PLL, CM_CLKSEL_MDM
+ *
+ * Filling in table based on H4 boards and 2430-SDPs variants available.
+ * There are quite a few more rates combinations which could be defined.
+ *
+ * When multiple values are defiend the start up will try and choose the
+ * fastest one. If a 'fast' value is defined, then automatically, the /2
+ * one should be included as it can be used.	Generally having more that
+ * one fast set does not make sense, as static timings need to be changed
+ * to change the set.	 The exception is the bypass setting which is
+ * availble for low power bypass.
+ *
+ * Note: This table needs to be sorted, fastest to slowest.
+ *-------------------------------------------------------------------------*/
+static struct prcm_config rate_table[] = {
+	/* PRCM II - FAST */
+	{S12M, S600M, S300M, RII_CM_CLKSEL_MPU_VAL,		/* 300MHz ARM */
+		RII_CM_CLKSEL_DSP_VAL, RII_CM_CLKSEL_GFX_VAL,
+		RII_CM_CLKSEL1_CORE_VAL, MII_CM_CLKSEL1_PLL_12_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_100MHz,
+		RATE_IN_242X},
+
+	{S13M, S600M, S300M, RII_CM_CLKSEL_MPU_VAL,		/* 300MHz ARM */
+		RII_CM_CLKSEL_DSP_VAL, RII_CM_CLKSEL_GFX_VAL,
+		RII_CM_CLKSEL1_CORE_VAL, MII_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_100MHz,
+		RATE_IN_242X},
+
+	/* PRCM III - FAST */
+	{S12M, S532M, S266M, RIII_CM_CLKSEL_MPU_VAL,		/* 266MHz ARM */
+		RIII_CM_CLKSEL_DSP_VAL, RIII_CM_CLKSEL_GFX_VAL,
+		RIII_CM_CLKSEL1_CORE_VAL, MIII_CM_CLKSEL1_PLL_12_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_133MHz,
+		RATE_IN_242X},
+
+	{S13M, S532M, S266M, RIII_CM_CLKSEL_MPU_VAL,		/* 266MHz ARM */
+		RIII_CM_CLKSEL_DSP_VAL, RIII_CM_CLKSEL_GFX_VAL,
+		RIII_CM_CLKSEL1_CORE_VAL, MIII_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_133MHz,
+		RATE_IN_242X},
+
+	/* PRCM II - SLOW */
+	{S12M, S300M, S150M, RII_CM_CLKSEL_MPU_VAL,		/* 150MHz ARM */
+		RII_CM_CLKSEL_DSP_VAL, RII_CM_CLKSEL_GFX_VAL,
+		RII_CM_CLKSEL1_CORE_VAL, MII_CM_CLKSEL1_PLL_12_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_100MHz,
+		RATE_IN_242X},
+
+	{S13M, S300M, S150M, RII_CM_CLKSEL_MPU_VAL,		/* 150MHz ARM */
+		RII_CM_CLKSEL_DSP_VAL, RII_CM_CLKSEL_GFX_VAL,
+		RII_CM_CLKSEL1_CORE_VAL, MII_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_100MHz,
+		RATE_IN_242X},
+
+	/* PRCM III - SLOW */
+	{S12M, S266M, S133M, RIII_CM_CLKSEL_MPU_VAL,		/* 133MHz ARM */
+		RIII_CM_CLKSEL_DSP_VAL, RIII_CM_CLKSEL_GFX_VAL,
+		RIII_CM_CLKSEL1_CORE_VAL, MIII_CM_CLKSEL1_PLL_12_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_133MHz,
+		RATE_IN_242X},
+
+	{S13M, S266M, S133M, RIII_CM_CLKSEL_MPU_VAL,		/* 133MHz ARM */
+		RIII_CM_CLKSEL_DSP_VAL, RIII_CM_CLKSEL_GFX_VAL,
+		RIII_CM_CLKSEL1_CORE_VAL, MIII_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_133MHz,
+		RATE_IN_242X},
+
+	/* PRCM-VII (boot-bypass) */
+	{S12M, S12M, S12M, RVII_CM_CLKSEL_MPU_VAL,		/* 12MHz ARM*/
+		RVII_CM_CLKSEL_DSP_VAL, RVII_CM_CLKSEL_GFX_VAL,
+		RVII_CM_CLKSEL1_CORE_VAL, MVII_CM_CLKSEL1_PLL_12_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_BYPASS,
+		RATE_IN_242X},
+
+	/* PRCM-VII (boot-bypass) */
+	{S13M, S13M, S13M, RVII_CM_CLKSEL_MPU_VAL,		/* 13MHz ARM */
+		RVII_CM_CLKSEL_DSP_VAL, RVII_CM_CLKSEL_GFX_VAL,
+		RVII_CM_CLKSEL1_CORE_VAL, MVII_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, 0, V24XX_SDRC_RFR_CTRL_BYPASS,
+		RATE_IN_242X},
+
+	/* PRCM #3 - ratio2 (ES2) - FAST */
+	{S13M, S660M, S330M, R2_CM_CLKSEL_MPU_VAL,		/* 330MHz ARM */
+		R2_CM_CLKSEL_DSP_VAL, R2_CM_CLKSEL_GFX_VAL,
+		R2_CM_CLKSEL1_CORE_VAL, M3_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, R2_CM_CLKSEL_MDM_VAL,
+		V24XX_SDRC_RFR_CTRL_110MHz,
+		RATE_IN_243X},
+
+	/* PRCM #5a - ratio1 - FAST */
+	{S13M, S532M, S266M, R1_CM_CLKSEL_MPU_VAL,		/* 266MHz ARM */
+		R1_CM_CLKSEL_DSP_VAL, R1_CM_CLKSEL_GFX_VAL,
+		R1_CM_CLKSEL1_CORE_VAL, M5A_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, R1_CM_CLKSEL_MDM_VAL,
+		V24XX_SDRC_RFR_CTRL_133MHz,
+		RATE_IN_243X},
+
+	/* PRCM #5b - ratio1 - FAST */
+	{S13M, S400M, S200M, R1_CM_CLKSEL_MPU_VAL,		/* 200MHz ARM */
+		R1_CM_CLKSEL_DSP_VAL, R1_CM_CLKSEL_GFX_VAL,
+		R1_CM_CLKSEL1_CORE_VAL, M5B_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, R1_CM_CLKSEL_MDM_VAL,
+		V24XX_SDRC_RFR_CTRL_100MHz,
+		RATE_IN_243X},
+
+	/* PRCM #3 - ratio2 (ES2) - SLOW */
+	{S13M, S330M, S165M, R2_CM_CLKSEL_MPU_VAL,		/* 165MHz ARM */
+		R2_CM_CLKSEL_DSP_VAL, R2_CM_CLKSEL_GFX_VAL,
+		R2_CM_CLKSEL1_CORE_VAL, M3_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_1x_VAL, R2_CM_CLKSEL_MDM_VAL,
+		V24XX_SDRC_RFR_CTRL_110MHz,
+		RATE_IN_243X},
+
+	/* PRCM #5a - ratio1 - SLOW */
+	{S13M, S266M, S133M, R1_CM_CLKSEL_MPU_VAL,		/* 133MHz ARM */
+		R1_CM_CLKSEL_DSP_VAL, R1_CM_CLKSEL_GFX_VAL,
+		R1_CM_CLKSEL1_CORE_VAL, M5A_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_1x_VAL, R1_CM_CLKSEL_MDM_VAL,
+		V24XX_SDRC_RFR_CTRL_133MHz,
+		RATE_IN_243X},
+
+	/* PRCM #5b - ratio1 - SLOW*/
+	{S13M, S200M, S100M, R1_CM_CLKSEL_MPU_VAL,		/* 100MHz ARM */
+		R1_CM_CLKSEL_DSP_VAL, R1_CM_CLKSEL_GFX_VAL,
+		R1_CM_CLKSEL1_CORE_VAL, M5B_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_1x_VAL, R1_CM_CLKSEL_MDM_VAL,
+		V24XX_SDRC_RFR_CTRL_100MHz,
+		RATE_IN_243X},
+
+	/* PRCM-boot/bypass */
+	{S13M, S13M, S13M, RB_CM_CLKSEL_MPU_VAL,		/* 13Mhz */
+		RB_CM_CLKSEL_DSP_VAL, RB_CM_CLKSEL_GFX_VAL,
+		RB_CM_CLKSEL1_CORE_VAL, MB_CM_CLKSEL1_PLL_13_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, RB_CM_CLKSEL_MDM_VAL,
+		V24XX_SDRC_RFR_CTRL_BYPASS,
+		RATE_IN_243X},
+
+	/* PRCM-boot/bypass */
+	{S12M, S12M, S12M, RB_CM_CLKSEL_MPU_VAL,		/* 12Mhz */
+		RB_CM_CLKSEL_DSP_VAL, RB_CM_CLKSEL_GFX_VAL,
+		RB_CM_CLKSEL1_CORE_VAL, MB_CM_CLKSEL1_PLL_12_VAL,
+		MX_CLKSEL2_PLL_2x_VAL, RB_CM_CLKSEL_MDM_VAL,
+		V24XX_SDRC_RFR_CTRL_BYPASS,
+		RATE_IN_243X},
+
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+/*-------------------------------------------------------------------------
+ * 24xx clock tree.
+ *
+ * NOTE:In many cases here we are assigning a 'default' parent.	In many
+ *	cases the parent is selectable.	The get/set parent calls will also
+ *	switch sources.
+ *
+ *	Many some clocks say always_enabled, but they can be auto idled for
+ *	power savings. They will always be available upon clock request.
+ *
+ *	Several sources are given initial rates which may be wrong, this will
+ *	be fixed up in the init func.
+ *
+ *	Things are broadly separated below by clock domains. It is
+ *	noteworthy that most periferals have dependencies on multiple clock
+ *	domains. Many get their interface clocks from the L4 domain, but get
+ *	functional clocks from fixed sources or other core domain derived
+ *	clocks.
+ *-------------------------------------------------------------------------*/
+
+/* Base external input clocks */
+static struct clk func_32k_ck = {
+	.name		= "func_32k_ck",
+	.rate		= 32000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | ALWAYS_ENABLED,
+};
+
+/* Typical 12/13MHz in standalone mode, will be 26Mhz in chassis mode */
+static struct clk osc_ck = {		/* (*12, *13, 19.2, *26, 38.4)MHz */
+	.name		= "osc_ck",
+	.rate		= 26000000,		/* fixed up in clock init */
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+/* With out modem likely 12MHz, with modem likely 13MHz */
+static struct clk sys_ck = {		/* (*12, *13, 19.2, 26, 38.4)MHz */
+	.name		= "sys_ck",		/* ~ ref_clk also */
+	.parent		= &osc_ck,
+	.rate		= 13000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+	.rate_offset	= 6, /* sysclkdiv 1 or 2, already handled or no boot */
+	.recalc		= &omap2_sys_clk_recalc,
+};
+
+static struct clk alt_ck = {		/* Typical 54M or 48M, may not exist */
+	.name		= "alt_ck",
+	.rate		= 54000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+	.recalc		= &omap2_propagate_rate,
+};
+
+/*
+ * Analog domain root source clocks
+ */
+
+/* dpll_ck, is broken out in to special cases through clksel */
+static struct clk dpll_ck = {
+	.name		= "dpll_ck",
+	.parent		= &sys_ck,		/* Can be func_32k also */
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_PROPAGATES | RATE_CKCTL | CM_PLL_SEL1,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk apll96_ck = {
+	.name		= "apll96_ck",
+	.parent		= &sys_ck,
+	.rate		= 96000000,
+	.flags		= CLOCK_IN_OMAP242X |CLOCK_IN_OMAP243X |
+				RATE_FIXED | RATE_PROPAGATES,
+	.enable_reg	= (void __iomem *)&CM_CLKEN_PLL,
+	.enable_bit	= 0x2,
+	.recalc		= &omap2_propagate_rate,
+};
+
+static struct clk apll54_ck = {
+	.name		= "apll54_ck",
+	.parent		= &sys_ck,
+	.rate		= 54000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | RATE_PROPAGATES,
+	.enable_reg	= (void __iomem *)&CM_CLKEN_PLL,
+	.enable_bit	= 0x6,
+	.recalc		= &omap2_propagate_rate,
+};
+
+/*
+ * PRCM digital base sources
+ */
+static struct clk func_54m_ck = {
+	.name		= "func_54m_ck",
+	.parent		= &apll54_ck,	/* can also be alt_clk */
+	.rate		= 54000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES,
+	.src_offset	= 5,
+	.enable_reg	= (void __iomem *)&CM_CLKEN_PLL,
+	.enable_bit	= 0xff,
+	.recalc		= &omap2_propagate_rate,
+};
+
+static struct clk core_ck = {
+	.name		= "core_ck",
+	.parent		= &dpll_ck,		/* can also be 32k */
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				ALWAYS_ENABLED | RATE_PROPAGATES,
+	.recalc		= &omap2_propagate_rate,
+};
+
+static struct clk sleep_ck = {		/* sys_clk or 32k */
+	.name		= "sleep_ck",
+	.parent		= &func_32k_ck,
+	.rate		= 32000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.recalc		= &omap2_propagate_rate,
+};
+
+static struct clk func_96m_ck = {
+	.name		= "func_96m_ck",
+	.parent		= &apll96_ck,
+	.rate		= 96000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | RATE_PROPAGATES,
+	.enable_reg	= (void __iomem *)&CM_CLKEN_PLL,
+	.enable_bit	= 0xff,
+	.recalc		= &omap2_propagate_rate,
+};
+
+static struct clk func_48m_ck = {
+	.name		= "func_48m_ck",
+	.parent		= &apll96_ck,	 /* 96M or Alt */
+	.rate		= 48000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES,
+	.src_offset	= 3,
+	.enable_reg	= (void __iomem *)&CM_CLKEN_PLL,
+	.enable_bit	= 0xff,
+	.recalc		= &omap2_propagate_rate,
+};
+
+static struct clk func_12m_ck = {
+	.name		= "func_12m_ck",
+	.parent		= &func_48m_ck,
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | RATE_PROPAGATES,
+	.recalc		= &omap2_propagate_rate,
+	.enable_reg	= (void __iomem *)&CM_CLKEN_PLL,
+	.enable_bit	= 0xff,
+};
+
+/* Secure timer, only available in secure mode */
+static struct clk wdt1_osc_ck = {
+	.name		= "ck_wdt1_osc",
+	.parent		= &osc_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk sys_clkout = {
+	.name		= "sys_clkout",
+	.parent		= &func_54m_ck,
+	.rate		= 54000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_SYSCLKOUT_SEL1 | RATE_CKCTL,
+	.src_offset	= 0,
+	.enable_reg	= (void __iomem *)&PRCM_CLKOUT_CTRL,
+	.enable_bit	= 7,
+	.rate_offset	= 3,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+/* In 2430, new in 2420 ES2 */
+static struct clk sys_clkout2 = {
+	.name		= "sys_clkout2",
+	.parent		= &func_54m_ck,
+	.rate		= 54000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_SYSCLKOUT_SEL1 | RATE_CKCTL,
+	.src_offset	= 8,
+	.enable_reg	= (void __iomem *)&PRCM_CLKOUT_CTRL,
+	.enable_bit	= 15,
+	.rate_offset	= 11,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+/*
+ * MPU clock domain
+ *	Clocks:
+ *		MPU_FCLK, MPU_ICLK
+ *		INT_M_FCLK, INT_M_I_CLK
+ *
+ * - Individual clocks are hardware managed.
+ * - Base divider comes from: CM_CLKSEL_MPU
+ *
+ */
+static struct clk mpu_ck = {	/* Control cpu */
+	.name		= "mpu_ck",
+	.parent		= &core_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_CKCTL |
+				ALWAYS_ENABLED | CM_MPU_SEL1 | DELAYED_APP |
+				CONFIG_PARTICIPANT | RATE_PROPAGATES,
+	.rate_offset	= 0,	/* bits 0-4 */
+	.recalc		= &omap2_clksel_recalc,
+};
+
+/*
+ * DSP (2430-IVA2.1) (2420-UMA+IVA1) clock domain
+ * Clocks:
+ *	2430: IVA2.1_FCLK, IVA2.1_ICLK
+ *	2420: UMA_FCLK, UMA_ICLK, IVA_MPU, IVA_COP
+ */
+static struct clk iva2_1_fck = {
+	.name		= "iva2_1_fck",
+	.parent		= &core_ck,
+	.flags		= CLOCK_IN_OMAP243X | RATE_CKCTL | CM_DSP_SEL1 |
+				DELAYED_APP | RATE_PROPAGATES |
+				CONFIG_PARTICIPANT,
+	.rate_offset	= 0,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_DSP,
+	.enable_bit	= 0,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk iva2_1_ick = {
+	.name		= "iva2_1_ick",
+	.parent		= &iva2_1_fck,
+	.flags		= CLOCK_IN_OMAP243X | RATE_CKCTL | CM_DSP_SEL1 |
+				DELAYED_APP | CONFIG_PARTICIPANT,
+	.rate_offset	= 5,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+/*
+ * Won't be too specific here. The core clock comes into this block
+ * it is divided then tee'ed. One branch goes directly to xyz enable
+ * controls. The other branch gets further divided by 2 then possibly
+ * routed into a synchronizer and out of clocks abc.
+ */
+static struct clk dsp_fck = {
+	.name		= "dsp_fck",
+	.parent		= &core_ck,
+	.flags		= CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 |
+			DELAYED_APP | CONFIG_PARTICIPANT | RATE_PROPAGATES,
+	.rate_offset	= 0,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_DSP,
+	.enable_bit	= 0,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk dsp_ick = {
+	.name		= "dsp_ick",	 /* apparently ipi and isp */
+	.parent		= &dsp_fck,
+	.flags		= CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 |
+				DELAYED_APP | CONFIG_PARTICIPANT,
+	.rate_offset = 5,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_DSP,
+	.enable_bit	= 1,		/* for ipi */
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk iva1_ifck = {
+	.name		= "iva1_ifck",
+	.parent		= &core_ck,
+	.flags		= CLOCK_IN_OMAP242X | CM_DSP_SEL1 | RATE_CKCTL |
+			CONFIG_PARTICIPANT | RATE_PROPAGATES | DELAYED_APP,
+	.rate_offset= 8,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_DSP,
+	.enable_bit	= 10,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+/* IVA1 mpu/int/i/f clocks are /2 of parent */
+static struct clk iva1_mpu_int_ifck = {
+	.name		= "iva1_mpu_int_ifck",
+	.parent		= &iva1_ifck,
+	.flags		= CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_DSP,
+	.enable_bit	= 8,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+/*
+ * L3 clock domain
+ * L3 clocks are used for both interface and functional clocks to
+ * multiple entities. Some of these clocks are completely managed
+ * by hardware, and some others allow software control. Hardware
+ * managed ones general are based on directly CLK_REQ signals and
+ * various auto idle settings. The functional spec sets many of these
+ * as 'tie-high' for their enables.
+ *
+ * I-CLOCKS:
+ *	L3-Interconnect, SMS, GPMC, SDRC, OCM_RAM, OCM_ROM, SDMA
+ *	CAM, HS-USB.
+ * F-CLOCK
+ *	SSI.
+ *
+ * GPMC memories and SDRC have timing and clock sensitive registers which
+ * may very well need notification when the clock changes. Currently for low
+ * operating points, these are taken care of in sleep.S.
+ */
+static struct clk core_l3_ck = {	/* Used for ick and fck, interconnect */
+	.name		= "core_l3_ck",
+	.parent		= &core_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_CKCTL | ALWAYS_ENABLED | CM_CORE_SEL1 |
+				DELAYED_APP | CONFIG_PARTICIPANT |
+				RATE_PROPAGATES,
+	.rate_offset	= 0,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk usb_l4_ick = {	/* FS-USB interface clock */
+	.name		= "usb_l4_ick",
+	.parent		= &core_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP |
+				CONFIG_PARTICIPANT,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 0,
+	.rate_offset = 25,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+/*
+ * SSI is in L3 management domain, its direct parent is core not l3,
+ * many core power domain entities are grouped into the L3 clock
+ * domain.
+ * SSI_SSR_FCLK, SSI_SST_FCLK, SSI_L4_CLIK
+ *
+ * ssr = core/1/2/3/4/5, sst = 1/2 ssr.
+ */
+static struct clk ssi_ssr_sst_fck = {
+	.name		= "ssi_fck",
+	.parent		= &core_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,	/* bit 1 */
+	.enable_bit	= 1,
+	.rate_offset = 20,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+/*
+ * GFX clock domain
+ *	Clocks:
+ * GFX_FCLK, GFX_ICLK
+ * GFX_CG1(2d), GFX_CG2(3d)
+ *
+ * GFX_FCLK runs from L3, and is divided by (1,2,3,4)
+ * The 2d and 3d clocks run at a hardware determined
+ * divided value of fclk.
+ *
+ */
+static struct clk gfx_3d_fck = {
+	.name		= "gfx_3d_fck",
+	.parent		= &core_l3_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_CKCTL | CM_GFX_SEL1,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_GFX,
+	.enable_bit	= 2,
+	.rate_offset= 0,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk gfx_2d_fck = {
+	.name		= "gfx_2d_fck",
+	.parent		= &core_l3_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_CKCTL | CM_GFX_SEL1,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_GFX,
+	.enable_bit	= 1,
+	.rate_offset= 0,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk gfx_ick = {
+	.name		= "gfx_ick",		/* From l3 */
+	.parent		= &core_l3_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_CKCTL,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_GFX,	/* bit 0 */
+	.enable_bit	= 0,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+/*
+ * Modem clock domain (2430)
+ *	CLOCKS:
+ *		MDM_OSC_CLK
+ *		MDM_ICLK
+ */
+static struct clk mdm_ick = {		/* used both as a ick and fck */
+	.name		= "mdm_ick",
+	.parent		= &core_ck,
+	.flags		= CLOCK_IN_OMAP243X | RATE_CKCTL | CM_MODEM_SEL1 |
+				DELAYED_APP | CONFIG_PARTICIPANT,
+	.rate_offset	= 0,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_MDM,
+	.enable_bit	= 0,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk mdm_osc_ck = {
+	.name		= "mdm_osc_ck",
+	.rate		= 26000000,
+	.parent		= &osc_ck,
+	.flags		= CLOCK_IN_OMAP243X | RATE_FIXED,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_MDM,
+	.enable_bit	= 1,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+/*
+ * L4 clock management domain
+ *
+ * This domain contains lots of interface clocks from the L4 interface, some
+ * functional clocks.	Fixed APLL functional source clocks are managed in
+ * this domain.
+ */
+static struct clk l4_ck = {		/* used both as an ick and fck */
+	.name		= "l4_ck",
+	.parent		= &core_l3_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_CKCTL | ALWAYS_ENABLED | CM_CORE_SEL1 |
+				DELAYED_APP | RATE_PROPAGATES,
+	.rate_offset	= 5,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk ssi_l4_ick = {
+	.name		= "ssi_l4_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_CKCTL,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,	/* bit 1 */
+	.enable_bit	= 1,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+/*
+ * DSS clock domain
+ * CLOCKs:
+ * DSS_L4_ICLK, DSS_L3_ICLK,
+ * DSS_CLK1, DSS_CLK2, DSS_54MHz_CLK
+ *
+ * DSS is both initiator and target.
+ */
+static struct clk dss_ick = {		/* Enables both L3,L4 ICLK's */
+	.name		= "dss_ick",
+	.parent		= &l4_ck,	/* really both l3 and l4 */
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_CKCTL,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 0,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk dss1_fck = {
+	.name		= "dss1_fck",
+	.parent		= &core_ck,		/* Core or sys */
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 0,
+	.rate_offset	= 8,
+	.src_offset	= 8,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk dss2_fck = {		/* Alt clk used in power management */
+	.name		= "dss2_fck",
+	.parent		= &sys_ck,		/* fixed at sys_ck or 48MHz */
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_CKCTL | CM_CORE_SEL1 | RATE_FIXED,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 1,
+	.src_offset	= 13,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk dss_54m_fck = {	/* Alt clk used in power management */
+	.name		= "dss_54m_fck",	/* 54m tv clk */
+	.parent		= &func_54m_ck,
+	.rate		= 54000000,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				RATE_FIXED | RATE_PROPAGATES,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 2,
+	.recalc		= &omap2_propagate_rate,
+};
+
+/*
+ * CORE power domain ICLK & FCLK defines.
+ * Many of the these can have more than one possible parent. Entries
+ * here will likely have an L4 interface parent, and may have multiple
+ * functional clock parents.
+ */
+static struct clk gpt1_ick = {
+	.name		= "gpt1_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_WKUP,	/* Bit4 */
+	.enable_bit	= 0,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt1_fck = {
+	.name		= "gpt1_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_WKUP_SEL1,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_WKUP,
+	.enable_bit	= 0,
+	.src_offset	= 0,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt2_ick = {
+	.name		= "gpt2_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,	/* bit4 */
+	.enable_bit	= 0,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt2_fck = {
+	.name		= "gpt2_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 4,
+	.src_offset	= 2,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt3_ick = {
+	.name		= "gpt3_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,	/* Bit5 */
+	.enable_bit	= 5,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt3_fck = {
+	.name		= "gpt3_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 5,
+	.src_offset	= 4,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt4_ick = {
+	.name		= "gpt4_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,	/* Bit6 */
+	.enable_bit	= 6,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt4_fck = {
+	.name		= "gpt4_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 6,
+	.src_offset	= 6,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt5_ick = {
+	.name		= "gpt5_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,	 /* Bit7 */
+	.enable_bit	= 7,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt5_fck = {
+	.name		= "gpt5_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 7,
+	.src_offset	= 8,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt6_ick = {
+	.name		= "gpt6_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_bit	= 8,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,	 /* bit8 */
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt6_fck = {
+	.name		= "gpt6_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 8,
+	.src_offset	= 10,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt7_ick = {
+	.name		= "gpt7_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,	 /* bit9 */
+	.enable_bit	= 9,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt7_fck = {
+	.name		= "gpt7_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 9,
+	.src_offset	= 12,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt8_ick = {
+	.name		= "gpt8_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,	 /* bit10 */
+	.enable_bit	= 10,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt8_fck = {
+	.name		= "gpt8_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 10,
+	.src_offset	= 14,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt9_ick = {
+	.name		= "gpt9_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 11,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt9_fck = {
+	.name		= "gpt9_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+					CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 11,
+	.src_offset	= 16,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt10_ick = {
+	.name		= "gpt10_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 12,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt10_fck = {
+	.name		= "gpt10_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+					CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 12,
+	.src_offset	= 18,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt11_ick = {
+	.name		= "gpt11_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 13,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt11_fck = {
+	.name		= "gpt11_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+					CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 13,
+	.src_offset	= 20,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt12_ick = {
+	.name		= "gpt12_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,	 /* bit14 */
+	.enable_bit	= 14,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpt12_fck = {
+	.name		= "gpt12_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+					CM_CORE_SEL2,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 14,
+	.src_offset	= 22,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp1_ick = {
+	.name		= "mcbsp1_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_bit	= 15,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,	 /* bit16 */
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp1_fck = {
+	.name		= "mcbsp1_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_bit	= 15,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp2_ick = {
+	.name		= "mcbsp2_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_bit	= 16,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp2_fck = {
+	.name		= "mcbsp2_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_bit	= 16,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp3_ick = {
+	.name		= "mcbsp3_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 3,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp3_fck = {
+	.name		= "mcbsp3_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 3,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp4_ick = {
+	.name		= "mcbsp4_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 4,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp4_fck = {
+	.name		= "mcbsp4_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 4,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp5_ick = {
+	.name		= "mcbsp5_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 5,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcbsp5_fck = {
+	.name		= "mcbsp5_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 5,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcspi1_ick = {
+	.name		= "mcspi1_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 17,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcspi1_fck = {
+	.name		= "mcspi1_fck",
+	.parent		= &func_48m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 17,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcspi2_ick = {
+	.name		= "mcspi2_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 18,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcspi2_fck = {
+	.name		= "mcspi2_fck",
+	.parent		= &func_48m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 18,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcspi3_ick = {
+	.name		= "mcspi3_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 9,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mcspi3_fck = {
+	.name		= "mcspi3_fck",
+	.parent		= &func_48m_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 9,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk uart1_ick = {
+	.name		= "uart1_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 21,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk uart1_fck = {
+	.name		= "uart1_fck",
+	.parent		= &func_48m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 21,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk uart2_ick = {
+	.name		= "uart2_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 22,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk uart2_fck = {
+	.name		= "uart2_fck",
+	.parent		= &func_48m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 22,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk uart3_ick = {
+	.name		= "uart3_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 2,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk uart3_fck = {
+	.name		= "uart3_fck",
+	.parent		= &func_48m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 2,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpios_ick = {
+	.name		= "gpios_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_WKUP,
+	.enable_bit	= 2,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpios_fck = {
+	.name		= "gpios_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_WKUP,
+	.enable_bit	= 2,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mpu_wdt_ick = {
+	.name		= "mpu_wdt_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_WKUP,
+	.enable_bit	= 3,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mpu_wdt_fck = {
+	.name		= "mpu_wdt_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN_WKUP,
+	.enable_bit	= 3,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk sync_32k_ick = {
+	.name		= "sync_32k_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_WKUP,
+	.enable_bit	= 1,
+	.recalc		= &omap2_followparent_recalc,
+};
+static struct clk wdt1_ick = {
+	.name		= "wdt1_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_WKUP,
+	.enable_bit	= 4,
+	.recalc		= &omap2_followparent_recalc,
+};
+static struct clk omapctrl_ick = {
+	.name		= "omapctrl_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_WKUP,
+	.enable_bit	= 5,
+	.recalc		= &omap2_followparent_recalc,
+};
+static struct clk icr_ick = {
+	.name		= "icr_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN_WKUP,
+	.enable_bit	= 6,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk cam_ick = {
+	.name		= "cam_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 31,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk cam_fck = {
+	.name		= "cam_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 31,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mailboxes_ick = {
+	.name		= "mailboxes_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 30,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk wdt4_ick = {
+	.name		= "wdt4_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 29,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk wdt4_fck = {
+	.name		= "wdt4_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 29,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk wdt3_ick = {
+	.name		= "wdt3_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 28,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk wdt3_fck = {
+	.name		= "wdt3_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 28,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mspro_ick = {
+	.name		= "mspro_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 27,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mspro_fck = {
+	.name		= "mspro_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 27,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mmc_ick = {
+	.name		= "mmc_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 26,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mmc_fck = {
+	.name		= "mmc_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 26,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk fac_ick = {
+	.name		= "fac_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 25,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk fac_fck = {
+	.name		= "fac_fck",
+	.parent		= &func_12m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 25,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk eac_ick = {
+	.name		= "eac_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 24,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk eac_fck = {
+	.name		= "eac_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 24,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk hdq_ick = {
+	.name		= "hdq_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 23,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk hdq_fck = {
+	.name		= "hdq_fck",
+	.parent		= &func_12m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 23,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk i2c2_ick = {
+	.name		= "i2c2_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 20,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk i2c2_fck = {
+	.name		= "i2c2_fck",
+	.parent		= &func_12m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 20,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk i2chs2_fck = {
+	.name		= "i2chs2_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 20,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk i2c1_ick = {
+	.name		= "i2c1_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 19,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk i2c1_fck = {
+	.name		= "i2c1_fck",
+	.parent		= &func_12m_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 19,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk i2chs1_fck = {
+	.name		= "i2chs1_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 19,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk vlynq_ick = {
+	.name		= "vlynq_ick",
+	.parent		= &core_l3_ck,
+	.flags		= CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN1_CORE,
+	.enable_bit	= 3,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk vlynq_fck = {
+	.name		= "vlynq_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP242X  | RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN1_CORE,
+	.enable_bit	= 3,
+	.src_offset	= 15,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk sdrc_ick = {
+	.name		= "sdrc_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN3_CORE,
+	.enable_bit	= 2,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk des_ick = {
+	.name		= "des_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN4_CORE,
+	.enable_bit	= 0,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk sha_ick = {
+	.name		= "sha_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN4_CORE,
+	.enable_bit	= 1,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk rng_ick = {
+	.name		= "rng_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN4_CORE,
+	.enable_bit	= 2,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk aes_ick = {
+	.name		= "aes_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN4_CORE,
+	.enable_bit	= 3,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk pka_ick = {
+	.name		= "pka_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN4_CORE,
+	.enable_bit	= 4,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk usb_fck = {
+	.name		= "usb_fck",
+	.parent		= &func_48m_ck,
+	.flags		= CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 0,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk usbhs_ick = {
+	.name		= "usbhs_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 6,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mmchs1_ick = {
+	.name		= "mmchs1_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 7,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mmchs1_fck = {
+	.name		= "mmchs1_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 7,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mmchs2_ick = {
+	.name		= "mmchs2_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 8,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mmchs2_fck = {
+	.name		= "mmchs2_fck",
+	.parent		= &func_96m_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 8,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpio5_ick = {
+	.name		= "gpio5_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 10,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk gpio5_fck = {
+	.name		= "gpio5_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 10,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mdm_intc_ick = {
+	.name		= "mdm_intc_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_ICLKEN2_CORE,
+	.enable_bit	= 11,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mmchsdb1_fck = {
+	.name		= "mmchsdb1_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 16,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+static struct clk mmchsdb2_fck = {
+	.name		= "mmchsdb2_fck",
+	.parent		= &func_32k_ck,
+	.flags		= CLOCK_IN_OMAP243X,
+	.enable_reg	= (void __iomem *)&CM_FCLKEN2_CORE,
+	.enable_bit	= 17,
+	.recalc		= &omap2_followparent_recalc,
+};
+
+/*
+ * This clock is a composite clock which does entire set changes then
+ * forces a rebalance. It keys on the MPU speed, but it really could
+ * be any key speed part of a set in the rate table.
+ *
+ * to really change a set, you need memory table sets which get changed
+ * in sram, pre-notifiers & post notifiers, changing the top set, without
+ * having low level display recalc's won't work... this is why dpm notifiers
+ * work, isr's off, walk a list of clocks already _off_ and not messing with
+ * the bus.
+ *
+ * This clock should have no parent. It embodies the entire upper level
+ * active set. A parent will mess up some of the init also.
+ */
+static struct clk virt_prcm_set = {
+	.name		= "virt_prcm_set",
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+				VIRTUAL_CLOCK | ALWAYS_ENABLED | DELAYED_APP,
+	.parent		= &mpu_ck,	/* Indexed by mpu speed, no parent */
+	.recalc		= &omap2_mpu_recalc,	/* sets are keyed on mpu rate */
+	.set_rate	= &omap2_select_table_rate,
+	.round_rate	= &omap2_round_to_table_rate,
+};
+
+static struct clk *onchip_clks[] = {
+	/* external root sources */
+	&func_32k_ck,
+	&osc_ck,
+	&sys_ck,
+	&alt_ck,
+	/* internal analog sources */
+	&dpll_ck,
+	&apll96_ck,
+	&apll54_ck,
+	/* internal prcm root sources */
+	&func_54m_ck,
+	&core_ck,
+	&sleep_ck,
+	&func_96m_ck,
+	&func_48m_ck,
+	&func_12m_ck,
+	&wdt1_osc_ck,
+	&sys_clkout,
+	&sys_clkout2,
+	/* mpu domain clocks */
+	&mpu_ck,
+	/* dsp domain clocks */
+	&iva2_1_fck,		/* 2430 */
+	&iva2_1_ick,
+	&dsp_ick,		/* 2420 */
+	&dsp_fck,
+	&iva1_ifck,
+	&iva1_mpu_int_ifck,
+	/* GFX domain clocks */
+	&gfx_3d_fck,
+	&gfx_2d_fck,
+	&gfx_ick,
+	/* Modem domain clocks */
+	&mdm_ick,
+	&mdm_osc_ck,
+	/* DSS domain clocks */
+	&dss_ick,
+	&dss1_fck,
+	&dss2_fck,
+	&dss_54m_fck,
+	/* L3 domain clocks */
+	&core_l3_ck,
+	&ssi_ssr_sst_fck,
+	&usb_l4_ick,
+	/* L4 domain clocks */
+	&l4_ck,			/* used as both core_l4 and wu_l4 */
+	&ssi_l4_ick,
+	/* virtual meta-group clock */
+	&virt_prcm_set,
+	/* general l4 interface ck, multi-parent functional clk */
+	&gpt1_ick,
+	&gpt1_fck,
+	&gpt2_ick,
+	&gpt2_fck,
+	&gpt3_ick,
+	&gpt3_fck,
+	&gpt4_ick,
+	&gpt4_fck,
+	&gpt5_ick,
+	&gpt5_fck,
+	&gpt6_ick,
+	&gpt6_fck,
+	&gpt7_ick,
+	&gpt7_fck,
+	&gpt8_ick,
+	&gpt8_fck,
+	&gpt9_ick,
+	&gpt9_fck,
+	&gpt10_ick,
+	&gpt10_fck,
+	&gpt11_ick,
+	&gpt11_fck,
+	&gpt12_ick,
+	&gpt12_fck,
+	&mcbsp1_ick,
+	&mcbsp1_fck,
+	&mcbsp2_ick,
+	&mcbsp2_fck,
+	&mcbsp3_ick,
+	&mcbsp3_fck,
+	&mcbsp4_ick,
+	&mcbsp4_fck,
+	&mcbsp5_ick,
+	&mcbsp5_fck,
+	&mcspi1_ick,
+	&mcspi1_fck,
+	&mcspi2_ick,
+	&mcspi2_fck,
+	&mcspi3_ick,
+	&mcspi3_fck,
+	&uart1_ick,
+	&uart1_fck,
+	&uart2_ick,
+	&uart2_fck,
+	&uart3_ick,
+	&uart3_fck,
+	&gpios_ick,
+	&gpios_fck,
+	&mpu_wdt_ick,
+	&mpu_wdt_fck,
+	&sync_32k_ick,
+	&wdt1_ick,
+	&omapctrl_ick,
+	&icr_ick,
+	&cam_fck,
+	&cam_ick,
+	&mailboxes_ick,
+	&wdt4_ick,
+	&wdt4_fck,
+	&wdt3_ick,
+	&wdt3_fck,
+	&mspro_ick,
+	&mspro_fck,
+	&mmc_ick,
+	&mmc_fck,
+	&fac_ick,
+	&fac_fck,
+	&eac_ick,
+	&eac_fck,
+	&hdq_ick,
+	&hdq_fck,
+	&i2c1_ick,
+	&i2c1_fck,
+	&i2chs1_fck,
+	&i2c2_ick,
+	&i2c2_fck,
+	&i2chs2_fck,
+	&vlynq_ick,
+	&vlynq_fck,
+	&sdrc_ick,
+	&des_ick,
+	&sha_ick,
+	&rng_ick,
+	&aes_ick,
+	&pka_ick,
+	&usb_fck,
+	&usbhs_ick,
+	&mmchs1_ick,
+	&mmchs1_fck,
+	&mmchs2_ick,
+	&mmchs2_fck,
+	&gpio5_ick,
+	&gpio5_fck,
+	&mdm_intc_ick,
+	&mmchsdb1_fck,
+	&mmchsdb2_fck,
+};
+
+#endif
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
new file mode 100644
index 0000000..7181edb
--- /dev/null
+++ b/arch/arm/mach-omap2/devices.c
@@ -0,0 +1,89 @@
+/*
+ * linux/arch/arm/mach-omap2/devices.c
+ *
+ * OMAP2 platform device setup/initialization
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/tc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+
+extern void omap_nop_release(struct device *dev);
+
+/*-------------------------------------------------------------------------*/
+
+#if 	defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+
+#define OMAP2_I2C_BASE2		0x48072000
+#define OMAP2_I2C_INT2		57
+
+static struct resource i2c_resources2[] = {
+	{
+		.start		= OMAP2_I2C_BASE2,
+		.end		= OMAP2_I2C_BASE2 + 0x3f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= OMAP2_I2C_INT2,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device omap_i2c_device2 = {
+        .name           = "i2c_omap",
+        .id             = 2,
+        .dev = {
+                .release        = omap_nop_release,
+        },
+	.num_resources	= ARRAY_SIZE(i2c_resources2),
+	.resource	= i2c_resources2,
+};
+
+/* See also arch/arm/plat-omap/devices.c for first I2C on 24xx */
+static void omap_init_i2c(void)
+{
+	/* REVISIT: Second I2C not in use on H4? */
+	if (machine_is_omap_h4())
+		return;
+
+	omap_cfg_reg(J15_24XX_I2C2_SCL);
+	omap_cfg_reg(H19_24XX_I2C2_SDA);
+	(void) platform_device_register(&omap_i2c_device2);
+}
+
+#else
+
+static void omap_init_i2c(void) {}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static int __init omap2_init_devices(void)
+{
+	/* please keep these calls, and their implementations above,
+	 * in alphabetical order so they're easier to sort through.
+	 */
+	omap_init_i2c();
+
+	return 0;
+}
+arch_initcall(omap2_init_devices);
+
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
new file mode 100644
index 0000000..7618730
--- /dev/null
+++ b/arch/arm/mach-omap2/id.c
@@ -0,0 +1,124 @@
+/*
+ * linux/arch/arm/mach-omap2/id.c
+ *
+ * OMAP2 CPU identification code
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define OMAP24XX_TAP_BASE	io_p2v(0x48014000)
+
+#define OMAP_TAP_IDCODE		0x0204
+#define OMAP_TAP_PROD_ID	0x0208
+
+#define OMAP_TAP_DIE_ID_0	0x0218
+#define OMAP_TAP_DIE_ID_1	0x021C
+#define OMAP_TAP_DIE_ID_2	0x0220
+#define OMAP_TAP_DIE_ID_3	0x0224
+
+/* system_rev fields for OMAP2 processors:
+ *   CPU id bits     [31:16],
+ *   CPU device type [15:12], (unprg,normal,POP)
+ *   CPU revision    [11:08]
+ *   CPU class bits  [07:00]
+ */
+
+struct omap_id {
+	u16	hawkeye;	/* Silicon type (Hawkeye id) */
+	u8	dev;		/* Device type from production_id reg */
+	u32	type;		/* combined type id copied to system_rev */
+};
+
+/* Register values to detect the OMAP version */
+static struct omap_id omap_ids[] __initdata = {
+	{ .hawkeye = 0xb5d9, .dev = 0x0, .type = 0x24200000 },
+	{ .hawkeye = 0xb5d9, .dev = 0x1, .type = 0x24201000 },
+	{ .hawkeye = 0xb5d9, .dev = 0x2, .type = 0x24202000 },
+	{ .hawkeye = 0xb5d9, .dev = 0x4, .type = 0x24220000 },
+	{ .hawkeye = 0xb5d9, .dev = 0x8, .type = 0x24230000 },
+	{ .hawkeye = 0xb68a, .dev = 0x0, .type = 0x24300000 },
+};
+
+static u32 __init read_tap_reg(int reg)
+{
+	return __raw_readl(OMAP24XX_TAP_BASE + reg);
+}
+
+void __init omap2_check_revision(void)
+{
+	int i, j;
+	u32 idcode;
+	u32 prod_id;
+	u16 hawkeye;
+	u8  dev_type;
+	u8  rev;
+
+	idcode = read_tap_reg(OMAP_TAP_IDCODE);
+	prod_id = read_tap_reg(OMAP_TAP_PROD_ID);
+	hawkeye = (idcode >> 12) & 0xffff;
+	rev = (idcode >> 28) & 0x0f;
+	dev_type = (prod_id >> 16) & 0x0f;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "OMAP_TAP_IDCODE 0x%08x REV %i HAWKEYE 0x%04x MANF %03x\n",
+		idcode, rev, hawkeye, (idcode >> 1) & 0x7ff);
+	printk(KERN_DEBUG "OMAP_TAP_DIE_ID_0: 0x%08x\n",
+		read_tap_reg(OMAP_TAP_DIE_ID_0));
+	printk(KERN_DEBUG "OMAP_TAP_DIE_ID_1: 0x%08x DEV_REV: %i\n",
+		read_tap_reg(OMAP_TAP_DIE_ID_1),
+	       (read_tap_reg(OMAP_TAP_DIE_ID_1) >> 28) & 0xf);
+	printk(KERN_DEBUG "OMAP_TAP_DIE_ID_2: 0x%08x\n",
+		read_tap_reg(OMAP_TAP_DIE_ID_2));
+	printk(KERN_DEBUG "OMAP_TAP_DIE_ID_3: 0x%08x\n",
+		read_tap_reg(OMAP_TAP_DIE_ID_3));
+	printk(KERN_DEBUG "OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n",
+		prod_id, dev_type);
+#endif
+
+	/* Check hawkeye ids */
+	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+		if (hawkeye == omap_ids[i].hawkeye)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(omap_ids)) {
+		printk(KERN_ERR "Unknown OMAP CPU id\n");
+		return;
+	}
+
+	for (j = i; j < ARRAY_SIZE(omap_ids); j++) {
+		if (dev_type == omap_ids[j].dev)
+			break;
+	}
+
+	if (j == ARRAY_SIZE(omap_ids)) {
+		printk(KERN_ERR "Unknown OMAP device type. "
+				"Handling it as OMAP%04x\n",
+				omap_ids[i].type >> 16);
+		j = i;
+	}
+	system_rev = omap_ids[j].type;
+
+	system_rev |= rev << 8;
+
+	/* Add the cpu class info (24xx) */
+	system_rev |= 0x24;
+
+	pr_info("OMAP%04x", system_rev >> 16);
+	if ((system_rev >> 8) & 0x0f)
+		printk("%x", (system_rev >> 8) & 0x0f);
+	printk("\n");
+}
+
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
new file mode 100644
index 0000000..8ea67bf
--- /dev/null
+++ b/arch/arm/mach-omap2/io.c
@@ -0,0 +1,53 @@
+/*
+ * linux/arch/arm/mach-omap2/io.c
+ *
+ * OMAP2 I/O mapping code
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mach/map.h>
+#include <asm/io.h>
+#include <asm/arch/mux.h>
+
+extern void omap_sram_init(void);
+extern int omap2_clk_init(void);
+extern void omap2_check_revision(void);
+
+/*
+ * The machine specific code may provide the extra mapping besides the
+ * default mapping provided here.
+ */
+static struct map_desc omap2_io_desc[] __initdata = {
+	{
+		.virtual	= L3_24XX_VIRT,
+		.pfn		= __phys_to_pfn(L3_24XX_PHYS),
+		.length		= L3_24XX_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= L4_24XX_VIRT,
+		.pfn		= __phys_to_pfn(L4_24XX_PHYS),
+		.length		= L4_24XX_SIZE,
+		.type		= MT_DEVICE
+	}
+};
+
+void __init omap_map_common_io(void)
+{
+	iotable_init(omap2_io_desc, ARRAY_SIZE(omap2_io_desc));
+	omap2_check_revision();
+	omap_sram_init();
+	omap2_mux_init();
+	omap2_clk_init();
+}
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
new file mode 100644
index 0000000..d7baff6
--- /dev/null
+++ b/arch/arm/mach-omap2/irq.c
@@ -0,0 +1,149 @@
+/*
+ * linux/arch/arm/mach-omap/omap2/irq.c
+ *
+ * Interrupt handler for OMAP2 boards.
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Paul Mundt <paul.mundt@nokia.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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <asm/hardware.h>
+#include <asm/mach/irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#define INTC_REVISION	0x0000
+#define INTC_SYSCONFIG	0x0010
+#define INTC_SYSSTATUS	0x0014
+#define INTC_CONTROL	0x0048
+#define INTC_MIR_CLEAR0	0x0088
+#define INTC_MIR_SET0	0x008c
+
+/*
+ * OMAP2 has a number of different interrupt controllers, each interrupt
+ * controller is identified as its own "bank". Register definitions are
+ * fairly consistent for each bank, but not all registers are implemented
+ * for each bank.. when in doubt, consult the TRM.
+ */
+static struct omap_irq_bank {
+	unsigned long base_reg;
+	unsigned int nr_irqs;
+} __attribute__ ((aligned(4))) irq_banks[] = {
+	{
+		/* MPU INTC */
+		.base_reg	= OMAP24XX_IC_BASE,
+		.nr_irqs	= 96,
+	}, {
+		/* XXX: DSP INTC */
+
+#if 0
+	/*
+	 * Commented out for now until we fix the IVA clocking
+	 */
+#ifdef CONFIG_ARCH_OMAP2420
+	}, {
+		/* IVA INTC (2420 only) */
+		.base_reg	= OMAP24XX_IVA_INTC_BASE,
+		.nr_irqs	= 16,	/* Actually 32, but only 16 are used */
+#endif
+#endif
+	}
+};
+
+/* XXX: FIQ and additional INTC support (only MPU at the moment) */
+static void omap_ack_irq(unsigned int irq)
+{
+	omap_writel(0x1, irq_banks[0].base_reg + INTC_CONTROL);
+}
+
+static void omap_mask_irq(unsigned int irq)
+{
+	int offset = (irq >> 5) << 5;
+
+	if (irq >= 64) {
+		irq %= 64;
+	} else if (irq >= 32) {
+		irq %= 32;
+	}
+
+	omap_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_SET0 + offset);
+}
+
+static void omap_unmask_irq(unsigned int irq)
+{
+	int offset = (irq >> 5) << 5;
+
+	if (irq >= 64) {
+		irq %= 64;
+	} else if (irq >= 32) {
+		irq %= 32;
+	}
+
+	omap_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_CLEAR0 + offset);
+}
+
+static void omap_mask_ack_irq(unsigned int irq)
+{
+	omap_mask_irq(irq);
+	omap_ack_irq(irq);
+}
+
+static struct irqchip omap_irq_chip = {
+	.ack	= omap_mask_ack_irq,
+	.mask	= omap_mask_irq,
+	.unmask	= omap_unmask_irq,
+};
+
+static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
+{
+	unsigned long tmp;
+
+	tmp = omap_readl(bank->base_reg + INTC_REVISION) & 0xff;
+	printk(KERN_INFO "IRQ: Found an INTC at 0x%08lx "
+			 "(revision %ld.%ld) with %d interrupts\n",
+			 bank->base_reg, tmp >> 4, tmp & 0xf, bank->nr_irqs);
+
+	tmp = omap_readl(bank->base_reg + INTC_SYSCONFIG);
+	tmp |= 1 << 1;	/* soft reset */
+	omap_writel(tmp, bank->base_reg + INTC_SYSCONFIG);
+
+	while (!(omap_readl(bank->base_reg + INTC_SYSSTATUS) & 0x1))
+		/* Wait for reset to complete */;
+}
+
+void __init omap_init_irq(void)
+{
+	unsigned long nr_irqs = 0;
+	unsigned int nr_banks = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+		struct omap_irq_bank *bank = irq_banks + i;
+
+		/* XXX */
+		if (!bank->base_reg)
+			continue;
+
+		omap_irq_bank_init_one(bank);
+
+		nr_irqs += bank->nr_irqs;
+		nr_banks++;
+	}
+
+	printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n",
+	       nr_irqs, nr_banks, nr_banks > 1 ? "s" : "");
+
+	for (i = 0; i < nr_irqs; i++) {
+		set_irq_chip(i, &omap_irq_chip);
+		set_irq_handler(i, do_level_IRQ);
+		set_irq_flags(i, IRQF_VALID);
+	}
+}
+
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
new file mode 100644
index 0000000..ea46548
--- /dev/null
+++ b/arch/arm/mach-omap2/mux.c
@@ -0,0 +1,65 @@
+/*
+ * linux/arch/arm/mach-omap2/mux.c
+ *
+ * OMAP1 pin multiplexing configurations
+ *
+ * Copyright (C) 2003 - 2005 Nokia Corporation
+ *
+ * Written by Tony Lindgren <tony.lindgren@nokia.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/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/spinlock.h>
+
+#include <asm/arch/mux.h>
+
+#ifdef CONFIG_OMAP_MUX
+
+/* NOTE: See mux.h for the enumeration */
+
+struct pin_config __initdata_or_module omap24xx_pins[] = {
+/*
+ *	description			mux	mux	pull	pull	debug
+ *					offset	mode	ena	type
+ */
+
+/* 24xx I2C */
+MUX_CFG_24XX("M19_24XX_I2C1_SCL",	0x111,	0,	0,	0,	1)
+MUX_CFG_24XX("L15_24XX_I2C1_SDA",	0x112,	0,	0,	0,	1)
+MUX_CFG_24XX("J15_24XX_I2C2_SCL",	0x113,	0,	0,	0,	1)
+MUX_CFG_24XX("H19_24XX_I2C2_SDA",	0x114,	0,	0,	0,	1)
+
+/* Menelaus interrupt */
+MUX_CFG_24XX("W19_24XX_SYS_NIRQ",	0x12c,	0,	1,	1,	1)
+
+/* 24xx GPIO */
+MUX_CFG_24XX("Y20_24XX_GPIO60",		0x12c,	3,	0,	0,	1)
+MUX_CFG_24XX("M15_24XX_GPIO92",		0x10a,	3,	0,	0,	1)
+
+};
+
+int __init omap2_mux_init(void)
+{
+	omap_mux_register(omap24xx_pins, ARRAY_SIZE(omap24xx_pins));
+	return 0;
+}
+
+#endif
diff --git a/arch/arm/mach-omap2/prcm.h b/arch/arm/mach-omap2/prcm.h
new file mode 100644
index 0000000..2eb89b9
--- /dev/null
+++ b/arch/arm/mach-omap2/prcm.h
@@ -0,0 +1,419 @@
+/*
+ * prcm.h - Access definations for use in OMAP24XX clock and power management
+ *
+ * Copyright (C) 2005 Texas Instruments, 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.
+ *
+ * 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 __ASM_ARM_ARCH_DPM_PRCM_H
+#define __ASM_ARM_ARCH_DPM_PRCM_H
+
+/* SET_PERFORMANCE_LEVEL PARAMETERS */
+#define PRCM_HALF_SPEED 1
+#define PRCM_FULL_SPEED 2
+
+#ifndef __ASSEMBLER__
+
+#define PRCM_REG32(offset)	__REG32(OMAP24XX_PRCM_BASE + (offset))
+
+#define PRCM_REVISION		PRCM_REG32(0x000)
+#define PRCM_SYSCONFIG		PRCM_REG32(0x010)
+#define PRCM_IRQSTATUS_MPU	PRCM_REG32(0x018)
+#define PRCM_IRQENABLE_MPU	PRCM_REG32(0x01C)
+#define PRCM_VOLTCTRL		PRCM_REG32(0x050)
+#define PRCM_VOLTST		PRCM_REG32(0x054)
+#define PRCM_CLKSRC_CTRL	PRCM_REG32(0x060)
+#define PRCM_CLKOUT_CTRL	PRCM_REG32(0x070)
+#define PRCM_CLKEMUL_CTRL	PRCM_REG32(0x078)
+#define PRCM_CLKCFG_CTRL	PRCM_REG32(0x080)
+#define PRCM_CLKCFG_STATUS	PRCM_REG32(0x084)
+#define PRCM_VOLTSETUP		PRCM_REG32(0x090)
+#define PRCM_CLKSSETUP		PRCM_REG32(0x094)
+#define PRCM_POLCTRL		PRCM_REG32(0x098)
+
+/* GENERAL PURPOSE */
+#define GENERAL_PURPOSE1	PRCM_REG32(0x0B0)
+#define GENERAL_PURPOSE2	PRCM_REG32(0x0B4)
+#define GENERAL_PURPOSE3	PRCM_REG32(0x0B8)
+#define GENERAL_PURPOSE4	PRCM_REG32(0x0BC)
+#define GENERAL_PURPOSE5	PRCM_REG32(0x0C0)
+#define GENERAL_PURPOSE6	PRCM_REG32(0x0C4)
+#define GENERAL_PURPOSE7	PRCM_REG32(0x0C8)
+#define GENERAL_PURPOSE8	PRCM_REG32(0x0CC)
+#define GENERAL_PURPOSE9	PRCM_REG32(0x0D0)
+#define GENERAL_PURPOSE10	PRCM_REG32(0x0D4)
+#define GENERAL_PURPOSE11	PRCM_REG32(0x0D8)
+#define GENERAL_PURPOSE12	PRCM_REG32(0x0DC)
+#define GENERAL_PURPOSE13	PRCM_REG32(0x0E0)
+#define GENERAL_PURPOSE14	PRCM_REG32(0x0E4)
+#define GENERAL_PURPOSE15	PRCM_REG32(0x0E8)
+#define GENERAL_PURPOSE16	PRCM_REG32(0x0EC)
+#define GENERAL_PURPOSE17	PRCM_REG32(0x0F0)
+#define GENERAL_PURPOSE18	PRCM_REG32(0x0F4)
+#define GENERAL_PURPOSE19	PRCM_REG32(0x0F8)
+#define GENERAL_PURPOSE20	PRCM_REG32(0x0FC)
+
+/* MPU */
+#define CM_CLKSEL_MPU		PRCM_REG32(0x140)
+#define CM_CLKSTCTRL_MPU	PRCM_REG32(0x148)
+#define RM_RSTST_MPU		PRCM_REG32(0x158)
+#define PM_WKDEP_MPU		PRCM_REG32(0x1C8)
+#define PM_EVGENCTRL_MPU	PRCM_REG32(0x1D4)
+#define PM_EVEGENONTIM_MPU	PRCM_REG32(0x1D8)
+#define PM_EVEGENOFFTIM_MPU	PRCM_REG32(0x1DC)
+#define PM_PWSTCTRL_MPU		PRCM_REG32(0x1E0)
+#define PM_PWSTST_MPU		PRCM_REG32(0x1E4)
+
+/* CORE */
+#define CM_FCLKEN1_CORE		PRCM_REG32(0x200)
+#define CM_FCLKEN2_CORE		PRCM_REG32(0x204)
+#define CM_FCLKEN3_CORE		PRCM_REG32(0x208)
+#define CM_ICLKEN1_CORE		PRCM_REG32(0x210)
+#define CM_ICLKEN2_CORE		PRCM_REG32(0x214)
+#define CM_ICLKEN3_CORE		PRCM_REG32(0x218)
+#define CM_ICLKEN4_CORE		PRCM_REG32(0x21C)
+#define CM_IDLEST1_CORE		PRCM_REG32(0x220)
+#define CM_IDLEST2_CORE		PRCM_REG32(0x224)
+#define CM_IDLEST3_CORE		PRCM_REG32(0x228)
+#define CM_IDLEST4_CORE		PRCM_REG32(0x22C)
+#define CM_AUTOIDLE1_CORE	PRCM_REG32(0x230)
+#define CM_AUTOIDLE2_CORE	PRCM_REG32(0x234)
+#define CM_AUTOIDLE3_CORE	PRCM_REG32(0x238)
+#define CM_AUTOIDLE4_CORE	PRCM_REG32(0x23C)
+#define CM_CLKSEL1_CORE		PRCM_REG32(0x240)
+#define CM_CLKSEL2_CORE		PRCM_REG32(0x244)
+#define CM_CLKSTCTRL_CORE	PRCM_REG32(0x248)
+#define PM_WKEN1_CORE		PRCM_REG32(0x2A0)
+#define PM_WKEN2_CORE		PRCM_REG32(0x2A4)
+#define PM_WKST1_CORE		PRCM_REG32(0x2B0)
+#define PM_WKST2_CORE		PRCM_REG32(0x2B4)
+#define PM_WKDEP_CORE		PRCM_REG32(0x2C8)
+#define PM_PWSTCTRL_CORE	PRCM_REG32(0x2E0)
+#define PM_PWSTST_CORE		PRCM_REG32(0x2E4)
+
+/* GFX */
+#define CM_FCLKEN_GFX		PRCM_REG32(0x300)
+#define CM_ICLKEN_GFX		PRCM_REG32(0x310)
+#define CM_IDLEST_GFX		PRCM_REG32(0x320)
+#define CM_CLKSEL_GFX		PRCM_REG32(0x340)
+#define CM_CLKSTCTRL_GFX	PRCM_REG32(0x348)
+#define RM_RSTCTRL_GFX		PRCM_REG32(0x350)
+#define RM_RSTST_GFX		PRCM_REG32(0x358)
+#define PM_WKDEP_GFX		PRCM_REG32(0x3C8)
+#define PM_PWSTCTRL_GFX		PRCM_REG32(0x3E0)
+#define PM_PWSTST_GFX		PRCM_REG32(0x3E4)
+
+/* WAKE-UP */
+#define CM_FCLKEN_WKUP		PRCM_REG32(0x400)
+#define CM_ICLKEN_WKUP		PRCM_REG32(0x410)
+#define CM_IDLEST_WKUP		PRCM_REG32(0x420)
+#define CM_AUTOIDLE_WKUP	PRCM_REG32(0x430)
+#define CM_CLKSEL_WKUP		PRCM_REG32(0x440)
+#define RM_RSTCTRL_WKUP		PRCM_REG32(0x450)
+#define RM_RSTTIME_WKUP		PRCM_REG32(0x454)
+#define RM_RSTST_WKUP		PRCM_REG32(0x458)
+#define PM_WKEN_WKUP		PRCM_REG32(0x4A0)
+#define PM_WKST_WKUP		PRCM_REG32(0x4B0)
+
+/* CLOCKS */
+#define CM_CLKEN_PLL		PRCM_REG32(0x500)
+#define CM_IDLEST_CKGEN		PRCM_REG32(0x520)
+#define CM_AUTOIDLE_PLL		PRCM_REG32(0x530)
+#define CM_CLKSEL1_PLL		PRCM_REG32(0x540)
+#define CM_CLKSEL2_PLL		PRCM_REG32(0x544)
+
+/* DSP */
+#define CM_FCLKEN_DSP		PRCM_REG32(0x800)
+#define CM_ICLKEN_DSP		PRCM_REG32(0x810)
+#define CM_IDLEST_DSP		PRCM_REG32(0x820)
+#define CM_AUTOIDLE_DSP		PRCM_REG32(0x830)
+#define CM_CLKSEL_DSP		PRCM_REG32(0x840)
+#define CM_CLKSTCTRL_DSP	PRCM_REG32(0x848)
+#define RM_RSTCTRL_DSP		PRCM_REG32(0x850)
+#define RM_RSTST_DSP		PRCM_REG32(0x858)
+#define PM_WKEN_DSP		PRCM_REG32(0x8A0)
+#define PM_WKDEP_DSP		PRCM_REG32(0x8C8)
+#define PM_PWSTCTRL_DSP		PRCM_REG32(0x8E0)
+#define PM_PWSTST_DSP		PRCM_REG32(0x8E4)
+#define PRCM_IRQSTATUS_DSP	PRCM_REG32(0x8F0)
+#define PRCM_IRQENABLE_DSP	PRCM_REG32(0x8F4)
+
+/* IVA */
+#define PRCM_IRQSTATUS_IVA	PRCM_REG32(0x8F8)
+#define PRCM_IRQENABLE_IVA	PRCM_REG32(0x8FC)
+
+/* Modem on 2430 */
+#define CM_FCLKEN_MDM		PRCM_REG32(0xC00)
+#define CM_ICLKEN_MDM		PRCM_REG32(0xC10)
+#define CM_IDLEST_MDM		PRCM_REG32(0xC20)
+#define CM_CLKSEL_MDM		PRCM_REG32(0xC40)
+
+/* FIXME: Move to header for 2430 */
+#define DISP_BASE		(OMAP24XX_L4_IO_BASE+0x50000)
+#define DISP_REG32(offset)	__REG32(DISP_BASE + (offset))
+
+#define GPMC_BASE		(OMAP24XX_GPMC_BASE)
+#define GPMC_REG32(offset)	__REG32(GPMC_BASE + (offset))
+
+#define GPT1_BASE		(OMAP24XX_GPT1)
+#define GPT1_REG32(offset)	__REG32(GPT1_BASE + (offset))
+
+/* Misc sysconfig */
+#define DISPC_SYSCONFIG		DISP_REG32(0x410)
+#define SPI_BASE		(OMAP24XX_L4_IO_BASE+0x98000)
+#define MCSPI1_SYSCONFIG	__REG32(SPI_BASE + 0x10)
+#define MCSPI2_SYSCONFIG	__REG32(SPI_BASE+0x2000 + 0x10)
+
+//#define DSP_MMU_SYSCONFIG	0x5A000010
+#define CAMERA_MMU_SYSCONFIG	__REG32(DISP_BASE+0x2C10)
+//#define IVA_MMU_SYSCONFIG	0x5D000010
+//#define DSP_DMA_SYSCONFIG	0x00FCC02C
+#define CAMERA_DMA_SYSCONFIG	__REG32(DISP_BASE+0x282C)
+#define SYSTEM_DMA_SYSCONFIG	__REG32(DISP_BASE+0x602C)
+#define GPMC_SYSCONFIG		GPMC_REG32(0x010)
+#define MAILBOXES_SYSCONFIG	__REG32(OMAP24XX_L4_IO_BASE+0x94010)
+#define UART1_SYSCONFIG		__REG32(OMAP24XX_L4_IO_BASE+0x6A054)
+#define UART2_SYSCONFIG		__REG32(OMAP24XX_L4_IO_BASE+0x6C054)
+#define UART3_SYSCONFIG		__REG32(OMAP24XX_L4_IO_BASE+0x6E054)
+//#define IVA_SYSCONFIG		0x5C060010
+#define SDRC_SYSCONFIG		__REG32(OMAP24XX_SDRC_BASE+0x10)
+#define SMS_SYSCONFIG		__REG32(OMAP24XX_SMS_BASE+0x10)
+#define SSI_SYSCONFIG		__REG32(DISP_BASE+0x8010)
+//#define VLYNQ_SYSCONFIG	0x67FFFE10
+
+/* rkw - good cannidates for PM_ to start what nm was trying */
+#define OMAP24XX_GPT2		(OMAP24XX_L4_IO_BASE+0x2A000)
+#define OMAP24XX_GPT3		(OMAP24XX_L4_IO_BASE+0x78000)
+#define OMAP24XX_GPT4		(OMAP24XX_L4_IO_BASE+0x7A000)
+#define OMAP24XX_GPT5		(OMAP24XX_L4_IO_BASE+0x7C000)
+#define OMAP24XX_GPT6		(OMAP24XX_L4_IO_BASE+0x7E000)
+#define OMAP24XX_GPT7		(OMAP24XX_L4_IO_BASE+0x80000)
+#define OMAP24XX_GPT8		(OMAP24XX_L4_IO_BASE+0x82000)
+#define OMAP24XX_GPT9		(OMAP24XX_L4_IO_BASE+0x84000)
+#define OMAP24XX_GPT10		(OMAP24XX_L4_IO_BASE+0x86000)
+#define OMAP24XX_GPT11		(OMAP24XX_L4_IO_BASE+0x88000)
+#define OMAP24XX_GPT12		(OMAP24XX_L4_IO_BASE+0x8A000)
+
+#define GPTIMER1_SYSCONFIG	GPT1_REG32(0x010)
+#define GPTIMER2_SYSCONFIG	__REG32(OMAP24XX_GPT2 + 0x10)
+#define GPTIMER3_SYSCONFIG	__REG32(OMAP24XX_GPT3 + 0x10)
+#define GPTIMER4_SYSCONFIG	__REG32(OMAP24XX_GPT4 + 0x10)
+#define GPTIMER5_SYSCONFIG	__REG32(OMAP24XX_GPT5 + 0x10)
+#define GPTIMER6_SYSCONFIG	__REG32(OMAP24XX_GPT6 + 0x10)
+#define GPTIMER7_SYSCONFIG	__REG32(OMAP24XX_GPT7 + 0x10)
+#define GPTIMER8_SYSCONFIG	__REG32(OMAP24XX_GPT8 + 0x10)
+#define GPTIMER9_SYSCONFIG	__REG32(OMAP24XX_GPT9 + 0x10)
+#define GPTIMER10_SYSCONFIG	__REG32(OMAP24XX_GPT10 + 0x10)
+#define GPTIMER11_SYSCONFIG	__REG32(OMAP24XX_GPT11 + 0x10)
+#define GPTIMER12_SYSCONFIG	__REG32(OMAP24XX_GPT12 + 0x10)
+
+#define GPIOX_BASE(X)		(OMAP24XX_GPIO_BASE+(0x2000*((X)-1)))
+
+#define GPIO1_SYSCONFIG		__REG32((GPIOX_BASE(1)+0x10))
+#define GPIO2_SYSCONFIG		__REG32((GPIOX_BASE(2)+0x10))
+#define GPIO3_SYSCONFIG		__REG32((GPIOX_BASE(3)+0x10))
+#define GPIO4_SYSCONFIG		__REG32((GPIOX_BASE(4)+0x10))
+
+/* GP TIMER 1 */
+#define GPTIMER1_TISTAT		GPT1_REG32(0x014)
+#define GPTIMER1_TISR		GPT1_REG32(0x018)
+#define GPTIMER1_TIER		GPT1_REG32(0x01C)
+#define GPTIMER1_TWER		GPT1_REG32(0x020)
+#define GPTIMER1_TCLR		GPT1_REG32(0x024)
+#define GPTIMER1_TCRR		GPT1_REG32(0x028)
+#define GPTIMER1_TLDR		GPT1_REG32(0x02C)
+#define GPTIMER1_TTGR		GPT1_REG32(0x030)
+#define GPTIMER1_TWPS		GPT1_REG32(0x034)
+#define GPTIMER1_TMAR		GPT1_REG32(0x038)
+#define GPTIMER1_TCAR1		GPT1_REG32(0x03C)
+#define GPTIMER1_TSICR		GPT1_REG32(0x040)
+#define GPTIMER1_TCAR2		GPT1_REG32(0x044)
+
+/* rkw -- base fix up please... */
+#define GPTIMER3_TISR		__REG32(OMAP24XX_L4_IO_BASE+0x78018)
+
+/* SDRC */
+#define SDRC_DLLA_CTRL		__REG32(OMAP24XX_SDRC_BASE+0x060)
+#define SDRC_DLLA_STATUS	__REG32(OMAP24XX_SDRC_BASE+0x064)
+#define SDRC_DLLB_CTRL		__REG32(OMAP24XX_SDRC_BASE+0x068)
+#define SDRC_DLLB_STATUS	__REG32(OMAP24XX_SDRC_BASE+0x06C)
+#define SDRC_POWER		__REG32(OMAP24XX_SDRC_BASE+0x070)
+#define SDRC_MR_0		__REG32(OMAP24XX_SDRC_BASE+0x084)
+
+/* GPIO 1 */
+#define GPIO1_BASE		GPIOX_BASE(1)
+#define GPIO1_REG32(offset)	__REG32(GPIO1_BASE + (offset))
+#define GPIO1_IRQENABLE1	GPIO1_REG32(0x01C)
+#define GPIO1_IRQSTATUS1	GPIO1_REG32(0x018)
+#define GPIO1_IRQENABLE2	GPIO1_REG32(0x02C)
+#define GPIO1_IRQSTATUS2	GPIO1_REG32(0x028)
+#define GPIO1_WAKEUPENABLE	GPIO1_REG32(0x020)
+#define GPIO1_RISINGDETECT	GPIO1_REG32(0x048)
+#define GPIO1_DATAIN		GPIO1_REG32(0x038)
+#define GPIO1_OE		GPIO1_REG32(0x034)
+#define GPIO1_DATAOUT		GPIO1_REG32(0x03C)
+
+/* GPIO2 */
+#define GPIO2_BASE		GPIOX_BASE(2)
+#define GPIO2_REG32(offset)	__REG32(GPIO2_BASE + (offset))
+#define GPIO2_IRQENABLE1	GPIO2_REG32(0x01C)
+#define GPIO2_IRQSTATUS1	GPIO2_REG32(0x018)
+#define GPIO2_IRQENABLE2	GPIO2_REG32(0x02C)
+#define GPIO2_IRQSTATUS2	GPIO2_REG32(0x028)
+#define GPIO2_WAKEUPENABLE	GPIO2_REG32(0x020)
+#define GPIO2_RISINGDETECT	GPIO2_REG32(0x048)
+#define GPIO2_DATAIN		GPIO2_REG32(0x038)
+#define GPIO2_OE		GPIO2_REG32(0x034)
+#define GPIO2_DATAOUT		GPIO2_REG32(0x03C)
+
+/* GPIO 3 */
+#define GPIO3_BASE		GPIOX_BASE(3)
+#define GPIO3_REG32(offset)	__REG32(GPIO3_BASE + (offset))
+#define GPIO3_IRQENABLE1	GPIO3_REG32(0x01C)
+#define GPIO3_IRQSTATUS1	GPIO3_REG32(0x018)
+#define GPIO3_IRQENABLE2	GPIO3_REG32(0x02C)
+#define GPIO3_IRQSTATUS2	GPIO3_REG32(0x028)
+#define GPIO3_WAKEUPENABLE	GPIO3_REG32(0x020)
+#define GPIO3_RISINGDETECT	GPIO3_REG32(0x048)
+#define GPIO3_FALLINGDETECT	GPIO3_REG32(0x04C)
+#define GPIO3_DATAIN		GPIO3_REG32(0x038)
+#define GPIO3_OE		GPIO3_REG32(0x034)
+#define GPIO3_DATAOUT		GPIO3_REG32(0x03C)
+#define GPIO3_DEBOUNCENABLE	GPIO3_REG32(0x050)
+#define GPIO3_DEBOUNCINGTIME	GPIO3_REG32(0x054)
+
+/* GPIO 4 */
+#define GPIO4_BASE		GPIOX_BASE(4)
+#define GPIO4_REG32(offset)	__REG32(GPIO4_BASE + (offset))
+#define GPIO4_IRQENABLE1	GPIO4_REG32(0x01C)
+#define GPIO4_IRQSTATUS1	GPIO4_REG32(0x018)
+#define GPIO4_IRQENABLE2	GPIO4_REG32(0x02C)
+#define GPIO4_IRQSTATUS2	GPIO4_REG32(0x028)
+#define GPIO4_WAKEUPENABLE	GPIO4_REG32(0x020)
+#define GPIO4_RISINGDETECT	GPIO4_REG32(0x048)
+#define GPIO4_FALLINGDETECT	GPIO4_REG32(0x04C)
+#define GPIO4_DATAIN		GPIO4_REG32(0x038)
+#define GPIO4_OE		GPIO4_REG32(0x034)
+#define GPIO4_DATAOUT		GPIO4_REG32(0x03C)
+#define GPIO4_DEBOUNCENABLE	GPIO4_REG32(0x050)
+#define GPIO4_DEBOUNCINGTIME	GPIO4_REG32(0x054)
+
+
+/* IO CONFIG */
+#define CONTROL_BASE		(OMAP24XX_CTRL_BASE)
+#define CONTROL_REG32(offset)	__REG32(CONTROL_BASE + (offset))
+
+#define CONTROL_PADCONF_SPI1_NCS2	CONTROL_REG32(0x104)
+#define CONTROL_PADCONF_SYS_XTALOUT	CONTROL_REG32(0x134)
+#define CONTROL_PADCONF_UART1_RX	CONTROL_REG32(0x0C8)
+#define CONTROL_PADCONF_MCBSP1_DX	CONTROL_REG32(0x10C)
+#define CONTROL_PADCONF_GPMC_NCS4	CONTROL_REG32(0x090)
+#define CONTROL_PADCONF_DSS_D5		CONTROL_REG32(0x0B8)
+#define CONTROL_PADCONF_DSS_D9		CONTROL_REG32(0x0BC)
+#define CONTROL_PADCONF_DSS_D13		CONTROL_REG32(0x0C0)
+#define CONTROL_PADCONF_DSS_VSYNC	CONTROL_REG32(0x0CC)
+
+/* CONTROL */
+#define CONTROL_DEVCONF		CONTROL_REG32(0x274)
+
+/* INTERRUPT CONTROLLER */
+#define INTC_BASE		(OMAP24XX_L4_IO_BASE+0xfe000)
+#define INTC_REG32(offset)	__REG32(INTC_BASE + (offset))
+
+#define INTC1_U_BASE		INTC_REG32(0x000)
+#define INTC_MIR0		INTC_REG32(0x084)
+#define INTC_MIR_SET0		INTC_REG32(0x08C)
+#define INTC_MIR_CLEAR0		INTC_REG32(0x088)
+#define INTC_ISR_CLEAR0		INTC_REG32(0x094)
+#define INTC_MIR1		INTC_REG32(0x0A4)
+#define INTC_MIR_SET1		INTC_REG32(0x0AC)
+#define INTC_MIR_CLEAR1		INTC_REG32(0x0A8)
+#define INTC_ISR_CLEAR1		INTC_REG32(0x0B4)
+#define INTC_MIR2		INTC_REG32(0x0C4)
+#define INTC_MIR_SET2		INTC_REG32(0x0CC)
+#define INTC_MIR_CLEAR2		INTC_REG32(0x0C8)
+#define INTC_ISR_CLEAR2		INTC_REG32(0x0D4)
+#define INTC_SIR_IRQ		INTC_REG32(0x040)
+#define INTC_CONTROL		INTC_REG32(0x048)
+#define INTC_ILR11		INTC_REG32(0x12C)
+#define INTC_ILR32		INTC_REG32(0x180)
+#define INTC_ILR37		INTC_REG32(0x194)
+#define INTC_SYSCONFIG		INTC_REG32(0x010)
+
+/* RAM FIREWALL */
+#define RAMFW_BASE		(0x68005000)
+#define RAMFW_REG32(offset)	__REG32(RAMFW_BASE + (offset))
+
+#define RAMFW_REQINFOPERM0	RAMFW_REG32(0x048)
+#define RAMFW_READPERM0		RAMFW_REG32(0x050)
+#define RAMFW_WRITEPERM0	RAMFW_REG32(0x058)
+
+/* GPMC CS1 FPGA ON USER INTERFACE MODULE */
+//#define DEBUG_BOARD_LED_REGISTER 0x04000014
+
+/* GPMC CS0 */
+#define GPMC_CONFIG1_0		GPMC_REG32(0x060)
+#define GPMC_CONFIG2_0		GPMC_REG32(0x064)
+#define GPMC_CONFIG3_0		GPMC_REG32(0x068)
+#define GPMC_CONFIG4_0		GPMC_REG32(0x06C)
+#define GPMC_CONFIG5_0		GPMC_REG32(0x070)
+#define GPMC_CONFIG6_0		GPMC_REG32(0x074)
+#define GPMC_CONFIG7_0		GPMC_REG32(0x078)
+
+/* DSS */
+#define DSS_CONTROL		DISP_REG32(0x040)
+#define DISPC_CONTROL		DISP_REG32(0x440)
+#define DISPC_SYSSTATUS		DISP_REG32(0x414)
+#define DISPC_IRQSTATUS		DISP_REG32(0x418)
+#define DISPC_IRQENABLE		DISP_REG32(0x41C)
+#define DISPC_CONFIG		DISP_REG32(0x444)
+#define DISPC_DEFAULT_COLOR0	DISP_REG32(0x44C)
+#define DISPC_DEFAULT_COLOR1	DISP_REG32(0x450)
+#define DISPC_TRANS_COLOR0	DISP_REG32(0x454)
+#define DISPC_TRANS_COLOR1	DISP_REG32(0x458)
+#define DISPC_LINE_NUMBER	DISP_REG32(0x460)
+#define DISPC_TIMING_H		DISP_REG32(0x464)
+#define DISPC_TIMING_V		DISP_REG32(0x468)
+#define DISPC_POL_FREQ		DISP_REG32(0x46C)
+#define DISPC_DIVISOR		DISP_REG32(0x470)
+#define DISPC_SIZE_DIG		DISP_REG32(0x478)
+#define DISPC_SIZE_LCD		DISP_REG32(0x47C)
+#define DISPC_GFX_BA0		DISP_REG32(0x480)
+#define DISPC_GFX_BA1		DISP_REG32(0x484)
+#define DISPC_GFX_POSITION	DISP_REG32(0x488)
+#define DISPC_GFX_SIZE		DISP_REG32(0x48C)
+#define DISPC_GFX_ATTRIBUTES	DISP_REG32(0x4A0)
+#define DISPC_GFX_FIFO_THRESHOLD	DISP_REG32(0x4A4)
+#define DISPC_GFX_ROW_INC	DISP_REG32(0x4AC)
+#define DISPC_GFX_PIXEL_INC	DISP_REG32(0x4B0)
+#define DISPC_GFX_WINDOW_SKIP	DISP_REG32(0x4B4)
+#define DISPC_GFX_TABLE_BA	DISP_REG32(0x4B8)
+#define DISPC_DATA_CYCLE1	DISP_REG32(0x5D4)
+#define DISPC_DATA_CYCLE2	DISP_REG32(0x5D8)
+#define DISPC_DATA_CYCLE3	DISP_REG32(0x5DC)
+
+/* Wake up define for board */
+#define GPIO97			(1 << 1)
+#define GPIO88			(1 << 24)
+
+#endif /* __ASSEMBLER__ */
+
+#endif
+
+
+
+
+
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
new file mode 100644
index 0000000..f4df04f
--- /dev/null
+++ b/arch/arm/mach-omap2/serial.c
@@ -0,0 +1,180 @@
+/*
+ * arch/arm/mach-omap/omap2/serial.c
+ *
+ * OMAP2 serial support.
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * Based off of arch/arm/mach-omap/omap1/serial.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/kernel.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/io.h>
+#include <asm/hardware/clock.h>
+
+#include <asm/arch/common.h>
+#include <asm/arch/board.h>
+
+static struct clk * uart1_ick = NULL;
+static struct clk * uart1_fck = NULL;
+static struct clk * uart2_ick = NULL;
+static struct clk * uart2_fck = NULL;
+static struct clk * uart3_ick = NULL;
+static struct clk * uart3_fck = NULL;
+
+static struct plat_serial8250_port serial_platform_data[] = {
+	{
+		.membase	= (char *)IO_ADDRESS(OMAP_UART1_BASE),
+		.mapbase	= (unsigned long)OMAP_UART1_BASE,
+		.irq		= 72,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= OMAP16XX_BASE_BAUD * 16,
+	}, {
+		.membase	= (char *)IO_ADDRESS(OMAP_UART2_BASE),
+		.mapbase	= (unsigned long)OMAP_UART2_BASE,
+		.irq		= 73,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= OMAP16XX_BASE_BAUD * 16,
+	}, {
+		.membase	= (char *)IO_ADDRESS(OMAP_UART3_BASE),
+		.mapbase	= (unsigned long)OMAP_UART3_BASE,
+		.irq		= 74,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= OMAP16XX_BASE_BAUD * 16,
+	}, {
+		.flags		= 0
+	}
+};
+
+static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
+					   int offset)
+{
+	offset <<= up->regshift;
+	return (unsigned int)__raw_readb(up->membase + offset);
+}
+
+static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
+				    int value)
+{
+	offset <<= p->regshift;
+	__raw_writeb(value, (unsigned long)(p->membase + offset));
+}
+
+/*
+ * Internal UARTs need to be initialized for the 8250 autoconfig to work
+ * properly. Note that the TX watermark initialization may not be needed
+ * once the 8250.c watermark handling code is merged.
+ */
+static inline void __init omap_serial_reset(struct plat_serial8250_port *p)
+{
+	serial_write_reg(p, UART_OMAP_MDR1, 0x07);
+	serial_write_reg(p, UART_OMAP_SCR, 0x08);
+	serial_write_reg(p, UART_OMAP_MDR1, 0x00);
+	serial_write_reg(p, UART_OMAP_SYSC, 0x01);
+}
+
+void __init omap_serial_init()
+{
+	int i;
+	const struct omap_uart_config *info;
+
+	/*
+	 * Make sure the serial ports are muxed on at this point.
+	 * You have to mux them off in device drivers later on
+	 * if not needed.
+	 */
+
+	info = omap_get_config(OMAP_TAG_UART,
+			       struct omap_uart_config);
+
+	if (info == NULL)
+		return;
+
+	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+		struct plat_serial8250_port *p = serial_platform_data + i;
+
+		if (!(info->enabled_uarts & (1 << i))) {
+			p->membase = 0;
+			p->mapbase = 0;
+			continue;
+		}
+
+		switch (i) {
+		case 0:
+			uart1_ick = clk_get(NULL, "uart1_ick");
+			if (IS_ERR(uart1_ick))
+				printk("Could not get uart1_ick\n");
+			else {
+				clk_use(uart1_ick);
+			}
+
+			uart1_fck = clk_get(NULL, "uart1_fck");
+			if (IS_ERR(uart1_fck))
+				printk("Could not get uart1_fck\n");
+			else {
+				clk_use(uart1_fck);
+			}
+			break;
+		case 1:
+			uart2_ick = clk_get(NULL, "uart2_ick");
+			if (IS_ERR(uart2_ick))
+				printk("Could not get uart2_ick\n");
+			else {
+				clk_use(uart2_ick);
+			}
+
+			uart2_fck = clk_get(NULL, "uart2_fck");
+			if (IS_ERR(uart2_fck))
+				printk("Could not get uart2_fck\n");
+			else {
+				clk_use(uart2_fck);
+			}
+			break;
+		case 2:
+			uart3_ick = clk_get(NULL, "uart3_ick");
+			if (IS_ERR(uart3_ick))
+				printk("Could not get uart3_ick\n");
+			else {
+				clk_use(uart3_ick);
+			}
+
+			uart3_fck = clk_get(NULL, "uart3_fck");
+			if (IS_ERR(uart3_fck))
+				printk("Could not get uart3_fck\n");
+			else {
+				clk_use(uart3_fck);
+			}
+			break;
+		}
+
+		omap_serial_reset(p);
+	}
+}
+
+static struct platform_device serial_device = {
+	.name			= "serial8250",
+	.id			= 0,
+	.dev			= {
+		.platform_data	= serial_platform_data,
+	},
+};
+
+static int __init omap_init(void)
+{
+	return platform_device_register(&serial_device);
+}
+arch_initcall(omap_init);
diff --git a/arch/arm/mach-omap2/sram-fn.S b/arch/arm/mach-omap2/sram-fn.S
new file mode 100644
index 0000000..2a869e2
--- /dev/null
+++ b/arch/arm/mach-omap2/sram-fn.S
@@ -0,0 +1,333 @@
+/*
+ * linux/arch/arm/mach-omap1/sram.S
+ *
+ * Omap2 specific functions that need to be run in internal SRAM
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.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/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/arch/io.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/prcm.h>
+
+#define TIMER_32KSYNCT_CR_V	IO_ADDRESS(OMAP24XX_32KSYNCT_BASE + 0x010)
+
+#define CM_CLKSEL2_PLL_V	IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x544)
+#define PRCM_VOLTCTRL_V		IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x050)
+#define PRCM_CLKCFG_CTRL_V	IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x080)
+#define CM_CLKEN_PLL_V		IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x500)
+#define CM_IDLEST_CKGEN_V	IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x520)
+#define CM_CLKSEL1_PLL_V	IO_ADDRESS(OMAP24XX_PRCM_BASE + 0x540)
+
+#define SDRC_DLLA_CTRL_V	IO_ADDRESS(OMAP24XX_SDRC_BASE + 0x060)
+#define SDRC_RFR_CTRL_V		IO_ADDRESS(OMAP24XX_SDRC_BASE + 0x0a4)
+
+	.text
+
+ENTRY(sram_ddr_init)
+	stmfd	sp!, {r0 - r12, lr}	@ save registers on stack
+
+	mov	r12, r2			@ capture CS1 vs CS0
+	mov	r8, r3			@ capture force parameter
+
+	/* frequency shift down */
+	ldr	r2, cm_clksel2_pll	@ get address of dpllout reg
+	mov	r3, #0x1		@ value for 1x operation
+	str	r3, [r2]		@ go to L1-freq operation
+
+	/* voltage shift down */
+	mov r9, #0x1			@ set up for L1 voltage call
+	bl voltage_shift		@ go drop voltage
+
+	/* dll lock mode */
+	ldr	r11, sdrc_dlla_ctrl	@ addr of dlla ctrl
+	ldr	r10, [r11]		@ get current val
+	cmp	r12, #0x1		@ cs1 base (2422 es2.05/1)
+	addeq	r11, r11, #0x8		@ if cs1 base, move to DLLB
+	mvn	r9, #0x4		@ mask to get clear bit2
+	and	r10, r10, r9		@ clear bit2 for lock mode.
+	orr	r10, r10, #0x8		@ make sure DLL on (es2 bit pos)
+	orr	r10, r10, #0x2		@ 90 degree phase for all below 133Mhz
+	str	r10, [r11]		@ commit to DLLA_CTRL
+	bl	i_dll_wait		@ wait for dll to lock
+
+	/* get dll value */
+	add	r11, r11, #0x4		@ get addr of status reg
+	ldr	r10, [r11]		@ get locked value
+
+	/* voltage shift up */
+	mov r9, #0x0			@ shift back to L0-voltage
+	bl voltage_shift		@ go raise voltage
+
+	/* frequency shift up */
+	mov	r3, #0x2		@ value for 2x operation
+	str	r3, [r2]		@ go to L0-freq operation
+
+	/* reset entry mode for dllctrl */
+	sub	r11, r11, #0x4		@ move from status to ctrl
+	cmp	r12, #0x1		@ normalize if cs1 based
+	subeq	r11, r11, #0x8		@ possibly back to DLLA
+	cmp	r8, #0x1		@ if forced unlock exit
+	orreq	r1, r1, #0x4		@ make sure exit with unlocked value
+	str	r1, [r11]		@ restore DLLA_CTRL high value
+	add	r11, r11, #0x8		@ move to DLLB_CTRL addr
+	str	r1, [r11]		@ set value DLLB_CTRL
+	bl	i_dll_wait		@ wait for possible lock
+
+	/* set up for return, DDR should be good */
+	str r10, [r0]			@ write dll_status and return counter
+	ldmfd	sp!, {r0 - r12, pc}	@ restore regs and return
+
+	/* ensure the DLL has relocked */
+i_dll_wait:
+	mov	r4, #0x800		@ delay DLL relock, min 0x400 L3 clocks
+i_dll_delay:
+	subs	r4, r4, #0x1
+	bne	i_dll_delay
+	mov	pc, lr
+
+	/*
+	 * shift up or down voltage, use R9 as input to tell level.
+	 * wait for it to finish, use 32k sync counter, 1tick=31uS.
+	 */
+voltage_shift:
+	ldr	r4, prcm_voltctrl	@ get addr of volt ctrl.
+	ldr	r5, [r4]		@ get value.
+	ldr	r6, prcm_mask_val	@ get value of mask
+	and	r5, r5, r6		@ apply mask to clear bits
+	orr	r5, r5, r9		@ bulld value for L0/L1-volt operation.
+	str	r5, [r4]		@ set up for change.
+	mov	r3, #0x4000		@ get val for force
+	orr	r5, r5, r3		@ build value for force
+	str	r5, [r4]		@ Force transition to L1
+
+	ldr	r3, timer_32ksynct_cr	@ get addr of counter
+	ldr	r5, [r3]		@ get value
+	add	r5, r5, #0x3		@ give it at most 93uS
+volt_delay:
+	ldr	r7, [r3]		@ get timer value
+	cmp	r5, r7			@ time up?
+	bhi	volt_delay		@ not yet->branch
+	mov	pc, lr			@ back to caller.
+
+/* relative load constants */
+cm_clksel2_pll:
+	.word CM_CLKSEL2_PLL_V
+sdrc_dlla_ctrl:
+	.word SDRC_DLLA_CTRL_V
+prcm_voltctrl:
+	.word PRCM_VOLTCTRL_V
+prcm_mask_val:
+	.word 0xFFFF3FFC
+timer_32ksynct_cr:
+	.word TIMER_32KSYNCT_CR_V
+ENTRY(sram_ddr_init_sz)
+	.word	. - sram_ddr_init
+
+/*
+ * Reprograms memory timings.
+ * r0 = [PRCM_FULL | PRCM_HALF] r1 = SDRC_DLLA_CTRL value r2 = [DDR | SDR]
+ * PRCM_FULL = 2, PRCM_HALF = 1, DDR = 1, SDR = 0
+ */
+ENTRY(sram_reprogram_sdrc)
+	stmfd	sp!, {r0 - r10, lr}	@ save registers on stack
+	mov	r3, #0x0		@ clear for mrc call
+	mcr	p15, 0, r3, c7, c10, 4	@ memory barrier, finish ARM SDR/DDR
+	nop
+	nop
+	ldr	r6, ddr_sdrc_rfr_ctrl	@ get addr of refresh reg
+	ldr	r5, [r6]		@ get value
+	mov	r5, r5, lsr #8		@ isolate rfr field and drop burst
+
+	cmp	r0, #0x1		@ going to half speed?
+	movne	r9, #0x0		@ if up set flag up for pre up, hi volt
+
+	blne	voltage_shift_c		@ adjust voltage
+
+	cmp	r0, #0x1		@ going to half speed (post branch link)
+	moveq	r5, r5, lsr #1		@ divide by 2 if to half
+	movne	r5, r5, lsl #1		@ mult by 2 if to full
+	mov	r5, r5, lsl #8		@ put rfr field back into place
+	add	r5, r5, #0x1		@ turn on burst of 1
+	ldr	r4, ddr_cm_clksel2_pll	@ get address of out reg
+	ldr	r3, [r4]		@ get curr value
+	orr	r3, r3, #0x3
+	bic	r3, r3, #0x3		@ clear lower bits
+	orr	r3, r3, r0		@ new state value
+	str	r3, [r4]		@ set new state (pll/x, x=1 or 2)
+	nop
+	nop
+
+	moveq	r9, #0x1		@ if speed down, post down, drop volt
+	bleq	voltage_shift_c
+
+	mcr	p15, 0, r3, c7, c10, 4	@ memory barrier
+	str	r5, [r6]		@ set new RFR_1 value
+	add	r6, r6, #0x30		@ get RFR_2 addr
+	str	r5, [r6]		@ set RFR_2
+	nop
+	cmp	r2, #0x1		@ (SDR or DDR) do we need to adjust DLL
+	bne	freq_out		@ leave if SDR, no DLL function
+
+	/* With DDR, we need to take care of the DLL for the frequency change */
+	ldr	r2, ddr_sdrc_dlla_ctrl	@ addr of dlla ctrl
+	str	r1, [r2]		@ write out new SDRC_DLLA_CTRL
+	add	r2, r2, #0x8		@ addr to SDRC_DLLB_CTRL
+	str	r1, [r2]		@ commit to SDRC_DLLB_CTRL
+	mov	r1, #0x2000		@ wait DLL relock, min 0x400 L3 clocks
+dll_wait:
+	subs	r1, r1, #0x1
+	bne	dll_wait
+freq_out:
+	ldmfd	sp!, {r0 - r10, pc}	@ restore regs and return
+
+    /*
+     * shift up or down voltage, use R9 as input to tell level.
+     *	wait for it to finish, use 32k sync counter, 1tick=31uS.
+     */
+voltage_shift_c:
+	ldr	r10, ddr_prcm_voltctrl	@ get addr of volt ctrl
+	ldr	r8, [r10]		@ get value
+	ldr	r7, ddr_prcm_mask_val	@ get value of mask
+	and	r8, r8, r7		@ apply mask to clear bits
+	orr	r8, r8, r9		@ bulld value for L0/L1-volt operation.
+	str	r8, [r10]		@ set up for change.
+	mov	r7, #0x4000		@ get val for force
+	orr	r8, r8, r7		@ build value for force
+	str	r8, [r10]		@ Force transition to L1
+
+	ldr	r10, ddr_timer_32ksynct	@ get addr of counter
+	ldr	r8, [r10]		@ get value
+	add	r8, r8, #0x2		@ give it at most 62uS (min 31+)
+volt_delay_c:
+	ldr	r7, [r10]		@ get timer value
+	cmp	r8, r7			@ time up?
+	bhi	volt_delay_c		@ not yet->branch
+	mov	pc, lr			@ back to caller
+
+ddr_cm_clksel2_pll:
+	.word CM_CLKSEL2_PLL_V
+ddr_sdrc_dlla_ctrl:
+	.word SDRC_DLLA_CTRL_V
+ddr_sdrc_rfr_ctrl:
+	.word SDRC_RFR_CTRL_V
+ddr_prcm_voltctrl:
+	.word PRCM_VOLTCTRL_V
+ddr_prcm_mask_val:
+	.word 0xFFFF3FFC
+ddr_timer_32ksynct:
+	.word TIMER_32KSYNCT_CR_V
+
+ENTRY(sram_reprogram_sdrc_sz)
+	.word	. - sram_reprogram_sdrc
+
+/*
+ * Set dividers and pll. Also recalculate DLL value for DDR and unlock mode.
+ */
+ENTRY(sram_set_prcm)
+	stmfd	sp!, {r0-r12, lr}	@ regs to stack
+	adr	r4, pbegin		@ addr of preload start
+	adr	r8, pend		@ addr of preload end
+	mcrr	p15, 1, r8, r4, c12	@ preload into icache
+pbegin:
+	/* move into fast relock bypass */
+	ldr	r8, pll_ctl		@ get addr
+	ldr	r5, [r8]		@ get val
+	mvn	r6, #0x3		@ clear mask
+	and	r5, r5, r6		@ clear field
+	orr	r7, r5, #0x2		@ fast relock val
+	str	r7, [r8]		@ go to fast relock
+	ldr	r4, pll_stat		@ addr of stat
+block:
+	/* wait for bypass */
+	ldr	r8, [r4]		@ stat value
+	and	r8, r8, #0x3		@ mask for stat
+	cmp	r8, #0x1		@ there yet
+	bne	block			@ loop if not
+
+	/* set new dpll dividers _after_ in bypass */
+	ldr	r4, pll_div		@ get addr
+	str	r0, [r4]		@ set dpll ctrl val
+
+	ldr	r4, set_config		@ get addr
+	mov	r8, #1			@ valid cfg msk
+	str	r8, [r4]		@ make dividers take
+
+	mov	r4, #100		@ dead spin a bit
+wait_a_bit:
+	subs	r4, r4, #1		@ dec loop
+	bne	wait_a_bit		@ delay done?
+
+	/* check if staying in bypass */
+	cmp	r2, #0x1		@ stay in bypass?
+	beq	pend			@ jump over dpll relock
+
+	/* relock DPLL with new vals */
+	ldr	r5, pll_stat		@ get addr
+	ldr	r4, pll_ctl		@ get addr
+	orr	r8, r7, #0x3		@ val for lock dpll
+	str	r8, [r4]		@ set val
+	mov	r0, #1000		@ dead spin a bit
+wait_more:
+	subs	r0, r0, #1		@ dec loop
+	bne	wait_more		@ delay done?
+wait_lock:
+	ldr	r8, [r5]		@ get lock val
+	and	r8, r8, #3		@ isolate field
+	cmp	r8, #2			@ locked?
+	bne	wait_lock		@ wait if not
+pend:
+	/* update memory timings & briefly lock dll */
+	ldr	r4, sdrc_rfr		@ get addr
+	str	r1, [r4]		@ update refresh timing
+	ldr	r11, dlla_ctrl		@ get addr of DLLA ctrl
+	ldr	r10, [r11]		@ get current val
+	mvn	r9, #0x4		@ mask to get clear bit2
+	and	r10, r10, r9		@ clear bit2 for lock mode
+	orr	r10, r10, #0x8		@ make sure DLL on (es2 bit pos)
+	str	r10, [r11]		@ commit to DLLA_CTRL
+	add	r11, r11, #0x8		@ move to dllb
+	str	r10, [r11]		@ hit DLLB also
+
+	mov	r4, #0x800		@ relock time (min 0x400 L3 clocks)
+wait_dll_lock:
+	subs	r4, r4, #0x1
+	bne	wait_dll_lock
+	nop
+	ldmfd	sp!, {r0-r12, pc}	@ restore regs and return
+
+set_config:
+	.word PRCM_CLKCFG_CTRL_V
+pll_ctl:
+	.word CM_CLKEN_PLL_V
+pll_stat:
+	.word CM_IDLEST_CKGEN_V
+pll_div:
+	.word CM_CLKSEL1_PLL_V
+sdrc_rfr:
+	.word SDRC_RFR_CTRL_V
+dlla_ctrl:
+	.word SDRC_DLLA_CTRL_V
+
+ENTRY(sram_set_prcm_sz)
+	.word	. - sram_set_prcm
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
new file mode 100644
index 0000000..9ec1144
--- /dev/null
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -0,0 +1,126 @@
+/*
+ * linux/arch/arm/mach-omap2/timer-gp.c
+ *
+ * OMAP2 GP timer support.
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Paul Mundt <paul.mundt@nokia.com>
+ *         Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * Some parts based off of TI's 24xx code:
+ *
+ *   Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Roughly modelled after the OMAP1 MPU timer code.
+ *
+ * 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/time.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <asm/mach/time.h>
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/hardware/clock.h>
+
+#define OMAP2_GP_TIMER1_BASE	0x48028000
+#define OMAP2_GP_TIMER2_BASE	0x4802a000
+#define OMAP2_GP_TIMER3_BASE	0x48078000
+#define OMAP2_GP_TIMER4_BASE	0x4807a000
+
+#define GP_TIMER_TIDR		0x00
+#define GP_TIMER_TISR		0x18
+#define GP_TIMER_TIER		0x1c
+#define GP_TIMER_TCLR		0x24
+#define GP_TIMER_TCRR		0x28
+#define GP_TIMER_TLDR		0x2c
+#define GP_TIMER_TSICR		0x40
+
+#define OS_TIMER_NR		1  /* GP timer 2 */
+
+static unsigned long timer_base[] = {
+	IO_ADDRESS(OMAP2_GP_TIMER1_BASE),
+	IO_ADDRESS(OMAP2_GP_TIMER2_BASE),
+	IO_ADDRESS(OMAP2_GP_TIMER3_BASE),
+	IO_ADDRESS(OMAP2_GP_TIMER4_BASE),
+};
+
+static inline unsigned int timer_read_reg(int nr, unsigned int reg)
+{
+	return __raw_readl(timer_base[nr] + reg);
+}
+
+static inline void timer_write_reg(int nr, unsigned int reg, unsigned int val)
+{
+	__raw_writel(val, timer_base[nr] + reg);
+}
+
+/* Note that we always enable the clock prescale divider bit */
+static inline void omap2_gp_timer_start(int nr, unsigned long load_val)
+{
+	unsigned int tmp;
+
+	tmp = 0xffffffff - load_val;
+
+	timer_write_reg(nr, GP_TIMER_TLDR, tmp);
+	timer_write_reg(nr, GP_TIMER_TCRR, tmp);
+	timer_write_reg(nr, GP_TIMER_TIER, 1 << 1);
+	timer_write_reg(nr, GP_TIMER_TCLR, (1 << 5) | (1 << 1) | 1);
+}
+
+static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id,
+					    struct pt_regs *regs)
+{
+	write_seqlock(&xtime_lock);
+
+	timer_write_reg(OS_TIMER_NR, GP_TIMER_TISR, 1 << 1);
+	timer_tick(regs);
+
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction omap2_gp_timer_irq = {
+	.name		= "gp timer",
+	.flags		= SA_INTERRUPT,
+	.handler	= omap2_gp_timer_interrupt,
+};
+
+static void __init omap2_gp_timer_init(void)
+{
+	struct clk * sys_ck;
+	u32 tick_period = 120000;
+	u32 l;
+
+	/* Reset clock and prescale value */
+	timer_write_reg(OS_TIMER_NR, GP_TIMER_TCLR, 0);
+
+	sys_ck = clk_get(NULL, "sys_ck");
+	if (IS_ERR(sys_ck))
+		printk(KERN_ERR "Could not get sys_ck\n");
+	else {
+		clk_use(sys_ck);
+		tick_period = clk_get_rate(sys_ck) / 100;
+		clk_put(sys_ck);
+	}
+
+	tick_period /= 2;	/* Minimum prescale divider is 2 */
+	tick_period -= 1;
+
+	l = timer_read_reg(OS_TIMER_NR, GP_TIMER_TIDR);
+	printk(KERN_INFO "OMAP2 GP timer (HW version %d.%d)\n",
+	       (l >> 4) & 0x0f, l & 0x0f);
+
+	setup_irq(38, &omap2_gp_timer_irq);
+
+	omap2_gp_timer_start(OS_TIMER_NR, tick_period);
+}
+
+struct sys_timer omap_timer = {
+	.init	= omap2_gp_timer_init,
+};
+
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index b380a438..e201aa9 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -60,6 +60,7 @@
 	bool "Enable Sharp SL-C700 (Corgi) Support"
 	depends PXA_SHARPSL_25x
 	select PXA_SHARP_C7xx
+	select PXA_SSP
 
 config MACH_SHEPHERD
 	bool "Enable Sharp SL-C750 (Shepherd) Support"
@@ -102,12 +103,18 @@
 
 config PXA_SHARP_C7xx
 	bool
+	select PXA_SSP
 	help
 	  Enable support for all Sharp C7xx models
 
 config PXA_SHARP_Cxx00
 	bool
+	select PXA_SSP
 	help
 	  Enable common support for Sharp Cxx00 models
 
+config PXA_SSP
+	tristate
+	help
+	  Enable support for PXA2xx SSP ports
 endif
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 8bc72d0..d210bd5 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -11,8 +11,8 @@
 obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
 obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
 obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
-obj-$(CONFIG_PXA_SHARP_C7xx)	+= corgi.o corgi_ssp.o corgi_lcd.o ssp.o
-obj-$(CONFIG_PXA_SHARP_Cxx00)	+= spitz.o corgi_ssp.o corgi_lcd.o ssp.o
+obj-$(CONFIG_PXA_SHARP_C7xx)	+= corgi.o corgi_ssp.o corgi_lcd.o
+obj-$(CONFIG_PXA_SHARP_Cxx00)	+= spitz.o corgi_ssp.o corgi_lcd.o
 obj-$(CONFIG_MACH_POODLE)	+= poodle.o
 obj-$(CONFIG_MACH_TOSA)         += tosa.o
 
@@ -26,6 +26,7 @@
 
 # Misc features
 obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_PXA_SSP) += ssp.o
 
 ifeq ($(CONFIG_PXA27x),y)
 obj-$(CONFIG_PM) += standby.o
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index eb5f6d74..100fb31 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -62,15 +62,6 @@
 	.io_out		= CORGI_SCOOP_IO_OUT,
 };
 
-static struct scoop_pcmcia_dev corgi_pcmcia_scoop[] = {
-{
-	.dev        = &corgiscoop_device.dev,
-	.irq        = CORGI_IRQ_GPIO_CF_IRQ,
-	.cd_irq     = CORGI_IRQ_GPIO_CF_CD,
-	.cd_irq_str = "PCMCIA0 CD",
-},
-};
-
 struct platform_device corgiscoop_device = {
 	.name		= "sharp-scoop",
 	.id		= -1,
@@ -81,6 +72,44 @@
 	.resource	= corgi_scoop_resources,
 };
 
+static void corgi_pcmcia_init(void)
+{
+	/* Setup default state of GPIO outputs
+	   before we enable them as outputs. */
+	GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+		GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
+		GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) |
+		GPIO_bit(GPIO53_nPCE_2);
+
+	pxa_gpio_mode(GPIO48_nPOE_MD);
+	pxa_gpio_mode(GPIO49_nPWE_MD);
+	pxa_gpio_mode(GPIO50_nPIOR_MD);
+	pxa_gpio_mode(GPIO51_nPIOW_MD);
+	pxa_gpio_mode(GPIO55_nPREG_MD);
+	pxa_gpio_mode(GPIO56_nPWAIT_MD);
+	pxa_gpio_mode(GPIO57_nIOIS16_MD);
+	pxa_gpio_mode(GPIO52_nPCE_1_MD);
+	pxa_gpio_mode(GPIO53_nPCE_2_MD);
+	pxa_gpio_mode(GPIO54_pSKTSEL_MD);
+}
+
+static struct scoop_pcmcia_dev corgi_pcmcia_scoop[] = {
+{
+	.dev        = &corgiscoop_device.dev,
+	.irq        = CORGI_IRQ_GPIO_CF_IRQ,
+	.cd_irq     = CORGI_IRQ_GPIO_CF_CD,
+	.cd_irq_str = "PCMCIA0 CD",
+},
+};
+
+static struct scoop_pcmcia_config corgi_pcmcia_config = {
+	.devs         = &corgi_pcmcia_scoop[0],
+	.num_devs     = 1,
+	.pcmcia_init  = corgi_pcmcia_init,
+};
+
+EXPORT_SYMBOL(corgiscoop_device);
+
 
 /*
  * Corgi SSP Device
@@ -294,8 +323,7 @@
 	pxa_set_mci_info(&corgi_mci_platform_data);
 	pxa_set_ficp_info(&corgi_ficp_platform_data);
 
-	scoop_num = 1;
-	scoop_devs = &corgi_pcmcia_scoop[0];
+	platform_scoop_config = &corgi_pcmcia_config;
 
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c
index 591e5f3..b371d72 100644
--- a/arch/arm/mach-pxa/corgi_ssp.c
+++ b/arch/arm/mach-pxa/corgi_ssp.c
@@ -191,7 +191,7 @@
 	ssp_machinfo = machinfo;
 }
 
-static int __init corgi_ssp_probe(struct device *dev)
+static int __init corgi_ssp_probe(struct platform_device *dev)
 {
 	int ret;
 
@@ -203,7 +203,7 @@
 	GPDR(ssp_machinfo->cs_ads7846) |= GPIO_bit(ssp_machinfo->cs_ads7846);  /* output */
 	GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);   /* High - Disable ADS7846*/
 
-	ret = ssp_init(&corgi_ssp_dev,ssp_machinfo->port);
+	ret = ssp_init(&corgi_ssp_dev, ssp_machinfo->port, 0);
 
 	if (ret)
 		printk(KERN_ERR "Unable to register SSP handler!\n");
@@ -216,13 +216,13 @@
 	return ret;
 }
 
-static int corgi_ssp_remove(struct device *dev)
+static int corgi_ssp_remove(struct platform_device *dev)
 {
 	ssp_exit(&corgi_ssp_dev);
 	return 0;
 }
 
-static int corgi_ssp_suspend(struct device *dev, pm_message_t state)
+static int corgi_ssp_suspend(struct platform_device *dev, pm_message_t state)
 {
 	ssp_flush(&corgi_ssp_dev);
 	ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state);
@@ -230,7 +230,7 @@
 	return 0;
 }
 
-static int corgi_ssp_resume(struct device *dev)
+static int corgi_ssp_resume(struct platform_device *dev)
 {
 	GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);  /* High - Disable LCD Control/Timing Gen */
 	GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/
@@ -241,18 +241,19 @@
 	return 0;
 }
 
-static struct device_driver corgissp_driver = {
-	.name		= "corgi-ssp",
-	.bus		= &platform_bus_type,
+static struct platform_driver corgissp_driver = {
 	.probe		= corgi_ssp_probe,
 	.remove		= corgi_ssp_remove,
 	.suspend	= corgi_ssp_suspend,
 	.resume		= corgi_ssp_resume,
+	.driver		= {
+		.name	= "corgi-ssp",
+	},
 };
 
 int __init corgi_ssp_init(void)
 {
-	return driver_register(&corgissp_driver);
+	return platform_driver_register(&corgissp_driver);
 }
 
 arch_initcall(corgi_ssp_init);
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index ad6a13f..eef3de2 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -65,6 +65,27 @@
 	.resource	= poodle_scoop_resources,
 };
 
+static void poodle_pcmcia_init(void)
+{
+	/* Setup default state of GPIO outputs
+	   before we enable them as outputs. */
+	GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+		GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
+		GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) |
+		GPIO_bit(GPIO53_nPCE_2);
+
+	pxa_gpio_mode(GPIO48_nPOE_MD);
+	pxa_gpio_mode(GPIO49_nPWE_MD);
+	pxa_gpio_mode(GPIO50_nPIOR_MD);
+	pxa_gpio_mode(GPIO51_nPIOW_MD);
+	pxa_gpio_mode(GPIO55_nPREG_MD);
+	pxa_gpio_mode(GPIO56_nPWAIT_MD);
+	pxa_gpio_mode(GPIO57_nIOIS16_MD);
+	pxa_gpio_mode(GPIO52_nPCE_1_MD);
+	pxa_gpio_mode(GPIO53_nPCE_2_MD);
+	pxa_gpio_mode(GPIO54_pSKTSEL_MD);
+}
+
 static struct scoop_pcmcia_dev poodle_pcmcia_scoop[] = {
 {
 	.dev        = &poodle_scoop_device.dev,
@@ -74,6 +95,14 @@
 },
 };
 
+static struct scoop_pcmcia_config poodle_pcmcia_config = {
+	.devs         = &poodle_pcmcia_scoop[0],
+	.num_devs     = 1,
+	.pcmcia_init  = poodle_pcmcia_init,
+};
+
+EXPORT_SYMBOL(poodle_scoop_device);
+
 
 /* LoCoMo device */
 static struct resource locomo_resources[] = {
@@ -268,8 +297,7 @@
 	pxa_set_mci_info(&poodle_mci_platform_data);
 	pxa_set_ficp_info(&poodle_ficp_platform_data);
 
-	scoop_num = 1;
-	scoop_devs = &poodle_pcmcia_scoop[0];
+	platform_scoop_config = &poodle_pcmcia_config;
 
 	ret = platform_add_devices(devices, ARRAY_SIZE(devices));
 	if (ret) {
diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h
index 3977a77..4879c0f 100644
--- a/arch/arm/mach-pxa/sharpsl.h
+++ b/arch/arm/mach-pxa/sharpsl.h
@@ -32,3 +32,90 @@
 void spitz_put_hsync(void);
 void corgi_wait_hsync(void);
 void spitz_wait_hsync(void);
+
+/*
+ * SharpSL Battery/PM Driver
+ */
+
+struct sharpsl_charger_machinfo {
+	void (*init)(void);
+	int gpio_acin;
+	int gpio_batfull;
+	int gpio_batlock;
+	int gpio_fatal;
+	int (*status_acin)(void);
+	void (*discharge)(int);
+	void (*discharge1)(int);
+	void (*charge)(int);
+	void (*chargeled)(int);
+	void (*measure_temp)(int);
+	void (*presuspend)(void);
+	void (*postsuspend)(void);
+	unsigned long (*charger_wakeup)(void);
+	int (*should_wakeup)(unsigned int resume_on_alarm);
+	int bat_levels;
+	struct battery_thresh *bat_levels_noac;
+	struct battery_thresh *bat_levels_acin;
+	int status_high_acin;
+	int status_low_acin;
+	int status_high_noac;
+	int status_low_noac;
+};
+
+struct battery_thresh {
+	int voltage;
+	int percentage;
+};
+
+struct battery_stat {
+	int ac_status;         /* APM AC Present/Not Present */
+	int mainbat_status;    /* APM Main Battery Status */
+	int mainbat_percent;   /* Main Battery Percentage Charge */
+	int mainbat_voltage;   /* Main Battery Voltage */
+};
+
+struct sharpsl_pm_status {
+	struct device *dev;
+	struct timer_list ac_timer;
+	struct timer_list chrg_full_timer;
+
+	int charge_mode;
+#define CHRG_ERROR    (-1)
+#define CHRG_OFF      (0)
+#define CHRG_ON       (1)
+#define CHRG_DONE     (2)
+
+	unsigned int flags;
+#define SHARPSL_SUSPENDED       (1 << 0)  /* Device is Suspended */
+#define SHARPSL_ALARM_ACTIVE    (1 << 1)  /* Alarm is for charging event (not user) */
+#define SHARPSL_BL_LIMIT        (1 << 2)  /* Backlight Intensity Limited */
+#define SHARPSL_APM_QUEUED      (1 << 3)  /* APM Event Queued */
+#define SHARPSL_DO_OFFLINE_CHRG (1 << 4)  /* Trigger the offline charger */
+
+	int full_count;
+	unsigned long charge_start_time;
+	struct sharpsl_charger_machinfo *machinfo;
+	struct battery_stat battstat;
+};
+
+extern struct sharpsl_pm_status sharpsl_pm;
+extern struct battery_thresh spitz_battery_levels_acin[];
+extern struct battery_thresh spitz_battery_levels_noac[];
+
+#define READ_GPIO_BIT(x)    (GPLR(x) & GPIO_bit(x))
+
+#define SHARPSL_LED_ERROR  2
+#define SHARPSL_LED_ON     1
+#define SHARPSL_LED_OFF    0
+
+#define CHARGE_ON()         sharpsl_pm.machinfo->charge(1)
+#define CHARGE_OFF()        sharpsl_pm.machinfo->charge(0)
+#define CHARGE_LED_ON()     sharpsl_pm.machinfo->chargeled(SHARPSL_LED_ON)
+#define CHARGE_LED_OFF()    sharpsl_pm.machinfo->chargeled(SHARPSL_LED_OFF)
+#define CHARGE_LED_ERR()    sharpsl_pm.machinfo->chargeled(SHARPSL_LED_ERROR)
+#define DISCHARGE_ON()      sharpsl_pm.machinfo->discharge(1)
+#define DISCHARGE_OFF()     sharpsl_pm.machinfo->discharge(0)
+#define STATUS_AC_IN        sharpsl_pm.machinfo->status_acin()
+#define STATUS_BATT_LOCKED  READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock)
+#define STATUS_CHRG_FULL    READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull)
+#define STATUS_FATAL        READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal)
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
new file mode 100644
index 0000000..6c9e871
--- /dev/null
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -0,0 +1,992 @@
+/*
+ * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00
+ * series of PDAs
+ *
+ * Copyright (c) 2004-2005 Richard Purdie
+ *
+ * Based on code written by Sharp for 2.4 kernels
+ *
+ * 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.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/apm_bios.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/scoop.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <asm/apm.h>
+
+#include <asm/arch/pm.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/sharpsl.h>
+#include "sharpsl.h"
+
+/*
+ * Constants
+ */
+#define SHARPSL_CHARGE_ON_TIME_INTERVAL        (msecs_to_jiffies(1*60*1000))  /* 1 min */
+#define SHARPSL_CHARGE_FINISH_TIME             (msecs_to_jiffies(10*60*1000)) /* 10 min */
+#define SHARPSL_BATCHK_TIME                    (msecs_to_jiffies(15*1000))    /* 15 sec */
+#define SHARPSL_BATCHK_TIME_SUSPEND            (60*10)                        /* 10 min */
+#define SHARPSL_WAIT_CO_TIME                   15  /* 15 sec */
+#define SHARPSL_WAIT_DISCHARGE_ON              100 /* 100 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP   10  /* 10 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT   10  /* 10 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD  10  /* 10 msec */
+#define SHARPSL_CHARGE_WAIT_TIME               15  /* 15 msec */
+#define SHARPSL_CHARGE_CO_CHECK_TIME           5   /* 5 msec */
+#define SHARPSL_CHARGE_RETRY_CNT               1   /* eqv. 10 min */
+
+#define SHARPSL_CHARGE_ON_VOLT         0x99  /* 2.9V */
+#define SHARPSL_CHARGE_ON_TEMP         0xe0  /* 2.9V */
+#define SHARPSL_CHARGE_ON_JKVAD_HIGH   0x9b  /* 6V */
+#define SHARPSL_CHARGE_ON_JKVAD_LOW    0x34  /* 2V */
+#define SHARPSL_FATAL_ACIN_VOLT        182   /* 3.45V */
+#define SHARPSL_FATAL_NOACIN_VOLT      170   /* 3.40V */
+
+struct battery_thresh spitz_battery_levels_acin[] = {
+	{ 213, 100},
+	{ 212,  98},
+	{ 211,  95},
+	{ 210,  93},
+	{ 209,  90},
+	{ 208,  88},
+	{ 207,  85},
+	{ 206,  83},
+	{ 205,  80},
+	{ 204,  78},
+	{ 203,  75},
+	{ 202,  73},
+	{ 201,  70},
+	{ 200,  68},
+	{ 199,  65},
+	{ 198,  63},
+	{ 197,  60},
+	{ 196,  58},
+	{ 195,  55},
+	{ 194,  53},
+	{ 193,  50},
+	{ 192,  48},
+	{ 192,  45},
+	{ 191,  43},
+	{ 191,  40},
+	{ 190,  38},
+	{ 190,  35},
+	{ 189,  33},
+	{ 188,  30},
+	{ 187,  28},
+	{ 186,  25},
+	{ 185,  23},
+	{ 184,  20},
+	{ 183,  18},
+	{ 182,  15},
+	{ 181,  13},
+	{ 180,  10},
+	{ 179,   8},
+	{ 178,   5},
+	{   0,   0},
+};
+
+struct battery_thresh  spitz_battery_levels_noac[] = {
+	{ 213, 100},
+	{ 212,  98},
+	{ 211,  95},
+	{ 210,  93},
+	{ 209,  90},
+	{ 208,  88},
+	{ 207,  85},
+	{ 206,  83},
+	{ 205,  80},
+	{ 204,  78},
+	{ 203,  75},
+	{ 202,  73},
+	{ 201,  70},
+	{ 200,  68},
+	{ 199,  65},
+	{ 198,  63},
+	{ 197,  60},
+	{ 196,  58},
+	{ 195,  55},
+	{ 194,  53},
+	{ 193,  50},
+	{ 192,  48},
+	{ 191,  45},
+	{ 190,  43},
+	{ 189,  40},
+	{ 188,  38},
+	{ 187,  35},
+	{ 186,  33},
+	{ 185,  30},
+	{ 184,  28},
+	{ 183,  25},
+	{ 182,  23},
+	{ 181,  20},
+	{ 180,  18},
+	{ 179,  15},
+	{ 178,  13},
+	{ 177,  10},
+	{ 176,   8},
+	{ 175,   5},
+	{   0,   0},
+};
+
+/* MAX1111 Commands */
+#define MAXCTRL_PD0      1u << 0
+#define MAXCTRL_PD1      1u << 1
+#define MAXCTRL_SGL      1u << 2
+#define MAXCTRL_UNI      1u << 3
+#define MAXCTRL_SEL_SH   4
+#define MAXCTRL_STR      1u << 7
+
+/* MAX1111 Channel Definitions */
+#define BATT_AD    4u
+#define BATT_THM   2u
+#define JK_VAD     6u
+
+
+/*
+ * Prototypes
+ */
+static int sharpsl_read_MainBattery(void);
+static int sharpsl_off_charge_battery(void);
+static int sharpsl_check_battery(int mode);
+static int sharpsl_ac_check(void);
+static int sharpsl_fatal_check(void);
+static int sharpsl_average_value(int ad);
+static void sharpsl_average_clear(void);
+static void sharpsl_charge_toggle(void *private_);
+static void sharpsl_battery_thread(void *private_);
+
+
+/*
+ * Variables
+ */
+struct sharpsl_pm_status sharpsl_pm;
+DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL);
+DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL);
+
+
+static int get_percentage(int voltage)
+{
+	int i = sharpsl_pm.machinfo->bat_levels - 1;
+	struct battery_thresh *thresh;
+
+	if (sharpsl_pm.charge_mode == CHRG_ON)
+		thresh=sharpsl_pm.machinfo->bat_levels_acin;
+	else
+		thresh=sharpsl_pm.machinfo->bat_levels_noac;
+
+	while (i > 0 && (voltage > thresh[i].voltage))
+		i--;
+
+	return thresh[i].percentage;
+}
+
+static int get_apm_status(int voltage)
+{
+	int low_thresh, high_thresh;
+
+	if (sharpsl_pm.charge_mode == CHRG_ON) {
+		high_thresh = sharpsl_pm.machinfo->status_high_acin;
+		low_thresh = sharpsl_pm.machinfo->status_low_acin;
+	} else {
+		high_thresh = sharpsl_pm.machinfo->status_high_noac;
+		low_thresh = sharpsl_pm.machinfo->status_low_noac;
+	}
+
+	if (voltage >= high_thresh)
+		return APM_BATTERY_STATUS_HIGH;
+	if (voltage >= low_thresh)
+		return APM_BATTERY_STATUS_LOW;
+	return APM_BATTERY_STATUS_CRITICAL;
+}
+
+void sharpsl_battery_kick(void)
+{
+	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));
+}
+EXPORT_SYMBOL(sharpsl_battery_kick);
+
+
+static void sharpsl_battery_thread(void *private_)
+{
+	int voltage, percent, apm_status, i = 0;
+
+	if (!sharpsl_pm.machinfo)
+		return;
+
+	sharpsl_pm.battstat.ac_status = (!(STATUS_AC_IN) ? APM_AC_OFFLINE : APM_AC_ONLINE);
+
+	/* Corgi cannot confirm when battery fully charged so periodically kick! */
+	if (machine_is_corgi() && (sharpsl_pm.charge_mode == CHRG_ON)
+			&& time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))
+		schedule_work(&toggle_charger);
+
+	while(1) {
+		voltage = sharpsl_read_MainBattery();
+		if (voltage > 0) break;
+		if (i++ > 5) {
+			voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
+			dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");
+			break;
+		}
+	}
+
+	voltage = sharpsl_average_value(voltage);
+	apm_status = get_apm_status(voltage);
+	percent = get_percentage(voltage);
+
+	/* At low battery voltages, the voltage has a tendency to start
+           creeping back up so we try to avoid this here */
+	if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) ||  percent <= sharpsl_pm.battstat.mainbat_percent) {
+		sharpsl_pm.battstat.mainbat_voltage = voltage;
+		sharpsl_pm.battstat.mainbat_status = apm_status;
+		sharpsl_pm.battstat.mainbat_percent = percent;
+	}
+
+	dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %d\n", voltage,
+			sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies);
+
+	/* If battery is low. limit backlight intensity to save power. */
+	if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
+			&& ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) ||
+			(sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) {
+		if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) {
+			corgibl_limit_intensity(1);
+			sharpsl_pm.flags |= SHARPSL_BL_LIMIT;
+		}
+	} else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) {
+		corgibl_limit_intensity(0);
+		sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT;
+	}
+
+	/* Suspend if critical battery level */
+	if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
+			&& (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL)
+			&& !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) {
+		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
+		dev_err(sharpsl_pm.dev, "Fatal Off\n");
+		apm_queue_event(APM_CRITICAL_SUSPEND);
+	}
+
+	schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME);
+}
+
+static void sharpsl_charge_on(void)
+{
+	dev_dbg(sharpsl_pm.dev, "Turning Charger On\n");
+
+	sharpsl_pm.full_count = 0;
+	sharpsl_pm.charge_mode = CHRG_ON;
+	schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250));
+	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500));
+}
+
+static void sharpsl_charge_off(void)
+{
+	dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n");
+
+	CHARGE_OFF();
+	CHARGE_LED_OFF();
+	sharpsl_pm.charge_mode = CHRG_OFF;
+
+	schedule_work(&sharpsl_bat);
+}
+
+static void sharpsl_charge_error(void)
+{
+	CHARGE_LED_ERR();
+	CHARGE_OFF();
+	sharpsl_pm.charge_mode = CHRG_ERROR;
+}
+
+static void sharpsl_charge_toggle(void *private_)
+{
+	dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
+
+	if (STATUS_AC_IN == 0) {
+		sharpsl_charge_off();
+		return;
+	} else if ((sharpsl_check_battery(1) < 0) || (sharpsl_ac_check() < 0)) {
+		sharpsl_charge_error();
+		return;
+	}
+
+	CHARGE_LED_ON();
+	CHARGE_OFF();
+	mdelay(SHARPSL_CHARGE_WAIT_TIME);
+	CHARGE_ON();
+
+	sharpsl_pm.charge_start_time = jiffies;
+}
+
+static void sharpsl_ac_timer(unsigned long data)
+{
+	int acin = STATUS_AC_IN;
+
+	dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);
+
+	sharpsl_average_clear();
+	if (acin && (sharpsl_pm.charge_mode != CHRG_ON))
+		sharpsl_charge_on();
+	else if (sharpsl_pm.charge_mode == CHRG_ON)
+		sharpsl_charge_off();
+
+	schedule_work(&sharpsl_bat);
+}
+
+
+static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp)
+{
+	/* Delay the event slightly to debounce */
+	/* Must be a smaller delay than the chrg_full_isr below */
+	mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+static void sharpsl_chrg_full_timer(unsigned long data)
+{
+	dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);
+
+	sharpsl_pm.full_count++;
+
+	if (STATUS_AC_IN == 0) {
+		dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
+		if (sharpsl_pm.charge_mode == CHRG_ON)
+			sharpsl_charge_off();
+	} else if (sharpsl_pm.full_count < 2) {
+		dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n");
+		schedule_work(&toggle_charger);
+	} else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) {
+		dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n");
+		schedule_work(&toggle_charger);
+	} else {
+		sharpsl_charge_off();
+		sharpsl_pm.charge_mode = CHRG_DONE;
+		dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n");
+	}
+}
+
+/* Charging Finished Interrupt (Not present on Corgi) */
+/* Can trigger at the same time as an AC staus change so
+   delay until after that has been processed */
+static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp)
+{
+	if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
+		return IRQ_HANDLED;
+
+	/* delay until after any ac interrupt */
+	mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp)
+{
+	int is_fatal = 0;
+
+	if (STATUS_BATT_LOCKED == 0) {
+		dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
+		is_fatal = 1;
+	}
+
+	if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL == 0)) {
+		dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
+		is_fatal = 1;
+	}
+
+	if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) {
+		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
+		apm_queue_event(APM_CRITICAL_SUSPEND);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Maintain an average of the last 10 readings
+ */
+#define SHARPSL_CNV_VALUE_NUM    10
+static int sharpsl_ad_index;
+
+static void sharpsl_average_clear(void)
+{
+	sharpsl_ad_index = 0;
+}
+
+static int sharpsl_average_value(int ad)
+{
+	int i, ad_val = 0;
+	static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1];
+
+	if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) {
+		sharpsl_ad_index = 0;
+		return ad;
+	}
+
+	sharpsl_ad[sharpsl_ad_index] = ad;
+	sharpsl_ad_index++;
+	if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) {
+		for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)
+			sharpsl_ad[i] = sharpsl_ad[i+1];
+		sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
+	}
+	for (i=0; i < sharpsl_ad_index; i++)
+		ad_val += sharpsl_ad[i];
+
+	return (ad_val / sharpsl_ad_index);
+}
+
+
+/*
+ * Read MAX1111 ADC
+ */
+static int read_max1111(int channel)
+{
+	return corgi_ssp_max1111_get((channel << MAXCTRL_SEL_SH) | MAXCTRL_PD0 | MAXCTRL_PD1
+			| MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR);
+}
+
+static int sharpsl_read_MainBattery(void)
+{
+	return read_max1111(BATT_AD);
+}
+
+static int sharpsl_read_Temp(void)
+{
+	int temp;
+
+	sharpsl_pm.machinfo->measure_temp(1);
+
+	mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
+	temp = read_max1111(BATT_THM);
+
+	sharpsl_pm.machinfo->measure_temp(0);
+
+	return temp;
+}
+
+static int sharpsl_read_jkvad(void)
+{
+	return read_max1111(JK_VAD);
+}
+
+/*
+ * Take an array of 5 integers, remove the maximum and minimum values
+ * and return the average.
+ */
+static int get_select_val(int *val)
+{
+	int i, j, k, temp, sum = 0;
+
+	/* Find MAX val */
+	temp = val[0];
+	j=0;
+	for (i=1; i<5; i++) {
+		if (temp < val[i]) {
+			temp = val[i];
+			j = i;
+		}
+	}
+
+	/* Find MIN val */
+	temp = val[4];
+	k=4;
+	for (i=3; i>=0; i--) {
+		if (temp > val[i]) {
+			temp = val[i];
+			k = i;
+		}
+	}
+
+	for (i=0; i<5; i++)
+		if (i != j && i != k )
+			sum += val[i];
+
+	dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]);
+
+	return (sum/3);
+}
+
+/*  mode 0 - Check temperature and voltage
+ *       1 - Check temperature only */
+static int sharpsl_check_battery(int mode)
+{
+	int val, i, buff[5];
+
+	/* Check battery temperature */
+	for (i=0; i<5; i++) {
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
+		buff[i] = sharpsl_read_Temp();
+	}
+
+	val = get_select_val(buff);
+
+	dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
+	if (val > SHARPSL_CHARGE_ON_TEMP)
+		return -1;
+	if (mode == 1)
+		return 0;
+
+	/* disable charge, enable discharge */
+	CHARGE_OFF();
+	DISCHARGE_ON();
+	mdelay(SHARPSL_WAIT_DISCHARGE_ON);
+
+	if (sharpsl_pm.machinfo->discharge1)
+		sharpsl_pm.machinfo->discharge1(1);
+
+	/* Check battery voltage */
+	for (i=0; i<5; i++) {
+		buff[i] = sharpsl_read_MainBattery();
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
+	}
+
+	if (sharpsl_pm.machinfo->discharge1)
+		sharpsl_pm.machinfo->discharge1(0);
+
+	DISCHARGE_OFF();
+
+	val = get_select_val(buff);
+	dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val);
+
+	if (val < SHARPSL_CHARGE_ON_VOLT)
+		return -1;
+
+	return 0;
+}
+
+static int sharpsl_ac_check(void)
+{
+	int temp, i, buff[5];
+
+	for (i=0; i<5; i++) {
+		buff[i] = sharpsl_read_jkvad();
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD);
+	}
+
+	temp = get_select_val(buff);
+	dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp);
+
+	if ((temp > SHARPSL_CHARGE_ON_JKVAD_HIGH) || (temp < SHARPSL_CHARGE_ON_JKVAD_LOW)) {
+		dev_err(sharpsl_pm.dev, "Error: AC check failed.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int sharpsl_pm_suspend(struct device *dev, pm_message_t state)
+{
+	sharpsl_pm.flags |= SHARPSL_SUSPENDED;
+	flush_scheduled_work();
+
+	if (sharpsl_pm.charge_mode == CHRG_ON)
+		sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
+	else
+		sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
+
+	return 0;
+}
+
+static int sharpsl_pm_resume(struct device *dev)
+{
+	/* Clear the reset source indicators as they break the bootloader upon reboot */
+	RCSR = 0x0f;
+	sharpsl_average_clear();
+	sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED;
+	sharpsl_pm.flags &= ~SHARPSL_SUSPENDED;
+
+	return 0;
+}
+
+static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
+{
+	dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR);
+
+	dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
+	/* not charging and AC-IN! */
+
+	if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (STATUS_AC_IN != 0)) {
+		dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
+		sharpsl_pm.charge_mode = CHRG_OFF;
+		sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
+		sharpsl_off_charge_battery();
+	}
+
+	sharpsl_pm.machinfo->presuspend();
+
+	PEDR = 0xffffffff; /* clear it */
+
+	sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE;
+	if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) {
+		RTSR &= RTSR_ALE;
+		RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND;
+		dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR);
+		sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE;
+	} else if (alarm_enable) {
+		RTSR &= RTSR_ALE;
+		RTAR = alarm_time;
+		dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR);
+	} else {
+		dev_dbg(sharpsl_pm.dev, "No alarms set.\n");
+	}
+
+	pxa_pm_enter(state);
+
+	sharpsl_pm.machinfo->postsuspend();
+
+	dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR);
+}
+
+static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
+{
+	if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) )
+	{
+		if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) {
+			dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n");
+			corgi_goto_sleep(alarm_time, alarm_enable, state);
+			return 1;
+		}
+		if(sharpsl_off_charge_battery()) {
+			dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n");
+			corgi_goto_sleep(alarm_time, alarm_enable, state);
+			return 1;
+		}
+		dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
+	}
+
+	if ((STATUS_BATT_LOCKED == 0) || (sharpsl_fatal_check() < 0) )
+	{
+		dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
+		corgi_goto_sleep(alarm_time, alarm_enable, state);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int corgi_pxa_pm_enter(suspend_state_t state)
+{
+	unsigned long alarm_time = RTAR;
+	unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0);
+
+	dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n");
+
+	corgi_goto_sleep(alarm_time, alarm_status, state);
+
+	while (corgi_enter_suspend(alarm_time,alarm_status,state))
+		{}
+
+	dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");
+
+	return 0;
+}
+#endif
+
+
+/*
+ * Check for fatal battery errors
+ * Fatal returns -1
+ */
+static int sharpsl_fatal_check(void)
+{
+	int buff[5], temp, i, acin;
+
+	dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
+
+	/* Check AC-Adapter */
+	acin = STATUS_AC_IN;
+
+	if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
+		CHARGE_OFF();
+		udelay(100);
+		DISCHARGE_ON();	/* enable discharge */
+		mdelay(SHARPSL_WAIT_DISCHARGE_ON);
+	}
+
+	if (sharpsl_pm.machinfo->discharge1)
+		sharpsl_pm.machinfo->discharge1(1);
+
+	/* Check battery : check inserting battery ? */
+	for (i=0; i<5; i++) {
+		buff[i] = sharpsl_read_MainBattery();
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
+	}
+
+	if (sharpsl_pm.machinfo->discharge1)
+		sharpsl_pm.machinfo->discharge1(0);
+
+	if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
+		udelay(100);
+		CHARGE_ON();
+		DISCHARGE_OFF();
+	}
+
+	temp = get_select_val(buff);
+	dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_read_MainBattery());
+
+	if ((acin && (temp < SHARPSL_FATAL_ACIN_VOLT)) ||
+			(!acin && (temp < SHARPSL_FATAL_NOACIN_VOLT)))
+		return -1;
+	return 0;
+}
+
+static int sharpsl_off_charge_error(void)
+{
+	dev_err(sharpsl_pm.dev, "Offline Charger: Error occured.\n");
+	CHARGE_OFF();
+	CHARGE_LED_ERR();
+	sharpsl_pm.charge_mode = CHRG_ERROR;
+	return 1;
+}
+
+/*
+ * Charging Control while suspended
+ * Return 1 - go straight to sleep
+ * Return 0 - sleep or wakeup depending on other factors
+ */
+static int sharpsl_off_charge_battery(void)
+{
+	int time;
+
+	dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode);
+
+	if (sharpsl_pm.charge_mode == CHRG_OFF) {
+		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
+
+		/* AC Check */
+		if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery(1) < 0))
+			return sharpsl_off_charge_error();
+
+		/* Start Charging */
+		CHARGE_LED_ON();
+		CHARGE_OFF();
+		mdelay(SHARPSL_CHARGE_WAIT_TIME);
+		CHARGE_ON();
+
+		sharpsl_pm.charge_mode = CHRG_ON;
+		sharpsl_pm.full_count = 0;
+
+		return 1;
+	} else if (sharpsl_pm.charge_mode != CHRG_ON) {
+		return 1;
+	}
+
+	if (sharpsl_pm.full_count == 0) {
+		int time;
+
+		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
+
+		if (sharpsl_check_battery(0) < 0)
+			return sharpsl_off_charge_error();
+
+		CHARGE_OFF();
+		mdelay(SHARPSL_CHARGE_WAIT_TIME);
+		CHARGE_ON();
+		sharpsl_pm.charge_mode = CHRG_ON;
+
+		mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
+
+		time = RCNR;
+		while(1) {
+			/* Check if any wakeup event had occured */
+			if (sharpsl_pm.machinfo->charger_wakeup() != 0)
+				return 0;
+			/* Check for timeout */
+			if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
+				return 1;
+			if (STATUS_CHRG_FULL) {
+				dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occured. Retrying to check\n");
+	   			sharpsl_pm.full_count++;
+				CHARGE_OFF();
+				mdelay(SHARPSL_CHARGE_WAIT_TIME);
+				CHARGE_ON();
+				return 1;
+			}
+		}
+	}
+
+	dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n");
+
+	mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
+
+	time = RCNR;
+	while(1) {
+		/* Check if any wakeup event had occured */
+		if (sharpsl_pm.machinfo->charger_wakeup() != 0)
+			return 0;
+		/* Check for timeout */
+		if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) {
+			if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) {
+				dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n");
+				sharpsl_pm.full_count = 0;
+			}
+			sharpsl_pm.full_count++;
+			return 1;
+		}
+		if (STATUS_CHRG_FULL) {
+			dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
+			CHARGE_LED_OFF();
+			CHARGE_OFF();
+			sharpsl_pm.charge_mode = CHRG_DONE;
+			return 1;
+		}
+	}
+}
+
+
+static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent);
+}
+
+static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage);
+}
+
+static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL);
+static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL);
+
+extern void (*apm_get_power_status)(struct apm_power_info *);
+
+static void sharpsl_apm_get_power_status(struct apm_power_info *info)
+{
+	info->ac_line_status = sharpsl_pm.battstat.ac_status;
+
+	if (sharpsl_pm.charge_mode == CHRG_ON)
+		info->battery_status = APM_BATTERY_STATUS_CHARGING;
+	else
+		info->battery_status = sharpsl_pm.battstat.mainbat_status;
+
+	info->battery_flag = (1 << info->battery_status);
+	info->battery_life = sharpsl_pm.battstat.mainbat_percent;
+}
+
+static struct pm_ops sharpsl_pm_ops = {
+	.pm_disk_mode	= PM_DISK_FIRMWARE,
+	.prepare	= pxa_pm_prepare,
+	.enter		= corgi_pxa_pm_enter,
+	.finish		= pxa_pm_finish,
+};
+
+static int __init sharpsl_pm_probe(struct device *dev)
+{
+	if (!dev->platform_data)
+		return -EINVAL;
+
+	sharpsl_pm.dev = dev;
+	sharpsl_pm.machinfo = dev->platform_data;
+	sharpsl_pm.charge_mode = CHRG_OFF;
+	sharpsl_pm.flags = 0;
+
+	sharpsl_pm.machinfo->init();
+
+	init_timer(&sharpsl_pm.ac_timer);
+	sharpsl_pm.ac_timer.function = sharpsl_ac_timer;
+
+	init_timer(&sharpsl_pm.chrg_full_timer);
+	sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer;
+
+	pxa_gpio_mode(sharpsl_pm.machinfo->gpio_acin | GPIO_IN);
+	pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batfull | GPIO_IN);
+	pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batlock | GPIO_IN);
+
+	/* Register interrupt handlers */
+	if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, SA_INTERRUPT, "AC Input Detect", sharpsl_ac_isr)) {
+		dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin));
+	}
+	else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin),IRQT_BOTHEDGE);
+
+	if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, SA_INTERRUPT, "Battery Cover", sharpsl_fatal_isr)) {
+		dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock));
+	}
+	else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock),IRQT_FALLING);
+
+	if (sharpsl_pm.machinfo->gpio_fatal) {
+		if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, SA_INTERRUPT, "Fatal Battery", sharpsl_fatal_isr)) {
+			dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal));
+		}
+		else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal),IRQT_FALLING);
+	}
+
+	if (!machine_is_corgi())
+	{
+		/* Register interrupt handler. */
+		if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, SA_INTERRUPT, "CO", sharpsl_chrg_full_isr)) {
+			dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull));
+		}
+		else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQT_RISING);
+	}
+
+	device_create_file(dev, &dev_attr_battery_percentage);
+	device_create_file(dev, &dev_attr_battery_voltage);
+
+	apm_get_power_status = sharpsl_apm_get_power_status;
+
+	pm_set_ops(&sharpsl_pm_ops);
+
+	mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
+
+	return 0;
+}
+
+static int sharpsl_pm_remove(struct device *dev)
+{
+	pm_set_ops(NULL);
+
+	device_remove_file(dev, &dev_attr_battery_percentage);
+	device_remove_file(dev, &dev_attr_battery_voltage);
+
+	free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr);
+	free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr);
+
+	if (sharpsl_pm.machinfo->gpio_fatal)
+		free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr);
+
+	if (!machine_is_corgi())
+		free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr);
+
+	del_timer_sync(&sharpsl_pm.chrg_full_timer);
+	del_timer_sync(&sharpsl_pm.ac_timer);
+
+	return 0;
+}
+
+static struct device_driver sharpsl_pm_driver = {
+	.name		= "sharpsl-pm",
+	.bus		= &platform_bus_type,
+	.probe		= sharpsl_pm_probe,
+	.remove		= sharpsl_pm_remove,
+	.suspend	= sharpsl_pm_suspend,
+	.resume		= sharpsl_pm_resume,
+};
+
+static int __devinit sharpsl_pm_init(void)
+{
+	return driver_register(&sharpsl_pm_driver);
+}
+
+static void sharpsl_pm_exit(void)
+{
+ 	driver_unregister(&sharpsl_pm_driver);
+}
+
+late_initcall(sharpsl_pm_init);
+module_exit(sharpsl_pm_exit);
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 6c6878c..4e9a699 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -104,6 +104,66 @@
 	.resource	= spitz_scoop2_resources,
 };
 
+#define SPITZ_PWR_SD 0x01
+#define SPITZ_PWR_CF 0x02
+
+/* Power control is shared with between one of the CF slots and SD */
+static void spitz_card_pwr_ctrl(int device, unsigned short new_cpr)
+{
+	unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR);
+
+	if (new_cpr & 0x0007) {
+	        set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+		if (!(cpr & 0x0002) && !(cpr & 0x0004))
+		        mdelay(5);
+		if (device == SPITZ_PWR_CF)
+		        cpr |= 0x0002;
+		if (device == SPITZ_PWR_SD)
+		        cpr |= 0x0004;
+	        write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr);
+	} else {
+		if (device == SPITZ_PWR_CF)
+		        cpr &= ~0x0002;
+		if (device == SPITZ_PWR_SD)
+		        cpr &= ~0x0004;
+	        write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr);
+		if (!(cpr & 0x0002) && !(cpr & 0x0004)) {
+		        mdelay(1);
+		        reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+		}
+	}
+}
+
+static void spitz_pcmcia_init(void)
+{
+	/* Setup default state of GPIO outputs
+	   before we enable them as outputs. */
+	GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+		GPIO_bit(GPIO49_nPWE) |	GPIO_bit(GPIO50_nPIOR) |
+		GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO54_nPCE_2);
+	GPSR(GPIO85_nPCE_1) = GPIO_bit(GPIO85_nPCE_1);
+
+	pxa_gpio_mode(GPIO48_nPOE_MD);
+	pxa_gpio_mode(GPIO49_nPWE_MD);
+	pxa_gpio_mode(GPIO50_nPIOR_MD);
+	pxa_gpio_mode(GPIO51_nPIOW_MD);
+	pxa_gpio_mode(GPIO55_nPREG_MD);
+	pxa_gpio_mode(GPIO56_nPWAIT_MD);
+	pxa_gpio_mode(GPIO57_nIOIS16_MD);
+	pxa_gpio_mode(GPIO85_nPCE_1_MD);
+	pxa_gpio_mode(GPIO54_nPCE_2_MD);
+	pxa_gpio_mode(GPIO104_pSKTSEL_MD);
+}
+
+static void spitz_pcmcia_pwr(struct device *scoop, unsigned short cpr, int nr)
+{
+	/* Only need to override behaviour for slot 0 */
+	if (nr == 0)
+		spitz_card_pwr_ctrl(SPITZ_PWR_CF, cpr);
+	else
+		write_scoop_reg(scoop, SCOOP_CPR, cpr);
+}
+
 static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = {
 {
 	.dev        = &spitzscoop_device.dev,
@@ -117,6 +177,16 @@
 },
 };
 
+static struct scoop_pcmcia_config spitz_pcmcia_config = {
+	.devs         = &spitz_pcmcia_scoop[0],
+	.num_devs     = 2,
+	.pcmcia_init  = spitz_pcmcia_init,
+	.power_ctrl   = spitz_pcmcia_pwr,
+};
+
+EXPORT_SYMBOL(spitzscoop_device);
+EXPORT_SYMBOL(spitzscoop2_device);
+
 
 /*
  * Spitz SSP Device
@@ -235,27 +305,14 @@
 	return 0;
 }
 
-/* Power control is shared with one of the CF slots so we have a mess */
 static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
 {
 	struct pxamci_platform_data* p_d = dev->platform_data;
 
-	unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR);
-
-	if (( 1 << vdd) & p_d->ocr_mask) {
-		/* printk(KERN_DEBUG "%s: on\n", __FUNCTION__); */
-		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
-		mdelay(2);
-		write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | 0x04);
-	} else {
-		/* printk(KERN_DEBUG "%s: off\n", __FUNCTION__); */
-		write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr & ~0x04);
-
-		if (!(cpr | 0x02)) {
-			mdelay(1);
-			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
-		}
-	}
+	if (( 1 << vdd) & p_d->ocr_mask)
+		spitz_card_pwr_ctrl(SPITZ_PWR_SD, 0x0004);
+	else
+		spitz_card_pwr_ctrl(SPITZ_PWR_SD, 0x0000);
 }
 
 static int spitz_mci_get_ro(struct device *dev)
@@ -351,8 +408,8 @@
 
 static void __init spitz_init(void)
 {
-	scoop_num = 2;
-	scoop_devs = &spitz_pcmcia_scoop[0];
+	platform_scoop_config = &spitz_pcmcia_config;
+
 	spitz_bl_machinfo.set_bl_intensity = spitz_bl_set_intensity;
 
 	common_init();
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
index 4d826c0..a68b30e 100644
--- a/arch/arm/mach-pxa/ssp.c
+++ b/arch/arm/mach-pxa/ssp.c
@@ -19,6 +19,8 @@
  *   22nd Aug 2003 Initial version.
  *   20th Dec 2004 Added ssp_config for changing port config without
  *                 closing the port.
+ *    4th Aug 2005 Added option to disable irq handler registration and
+ *                 cleaned up irq and clock detection.
  */
 
 #include <linux/module.h>
@@ -37,6 +39,26 @@
 
 #define PXA_SSP_PORTS 	3
 
+struct ssp_info_ {
+	int irq;
+	u32 clock;
+};
+
+/*
+ * SSP port clock and IRQ settings
+ */
+static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = {
+#if defined (CONFIG_PXA27x)
+	{IRQ_SSP,	CKEN23_SSP1},
+	{IRQ_SSP2,	CKEN3_SSP2},
+	{IRQ_SSP3,	CKEN4_SSP3},
+#else
+	{IRQ_SSP,	CKEN3_SSP},
+	{IRQ_NSSP,	CKEN9_NSSP},
+	{IRQ_ASSP,	CKEN10_ASSP},
+#endif
+};
+
 static DECLARE_MUTEX(sem);
 static int use_count[PXA_SSP_PORTS] = {0, 0, 0};
 
@@ -210,9 +232,9 @@
  *   %-EBUSY	if the resources are already in use
  *   %0		on success
  */
-int ssp_init(struct ssp_dev *dev, u32 port)
+int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags)
 {
-	int ret, irq;
+	int ret;
 
 	if (port > PXA_SSP_PORTS || port == 0)
 		return -ENODEV;
@@ -229,61 +251,20 @@
 		up(&sem);
 		return -EBUSY;
 	}
-
-	switch (port) {
-		case 1:
-			irq = IRQ_SSP;
-			break;
-#if defined (CONFIG_PXA27x)
-		case 2:
-			irq = IRQ_SSP2;
-			break;
-		case 3:
-			irq = IRQ_SSP3;
-			break;
-#else
-		case 2:
-			irq = IRQ_NSSP;
-			break;
-		case 3:
-			irq = IRQ_ASSP;
-			break;
-#endif
-		default:
-			return -ENODEV;
-	}
-
 	dev->port = port;
 
-	ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev);
-	if (ret)
-		goto out_region;
+	/* do we need to get irq */
+	if (!(init_flags & SSP_NO_IRQ)) {
+		ret = request_irq(ssp_info[port-1].irq, ssp_interrupt,
+				0, "SSP", dev);
+	    	if (ret)
+			goto out_region;
+	    	dev->irq = ssp_info[port-1].irq;
+	} else
+		dev->irq = 0;
 
 	/* turn on SSP port clock */
-	switch (dev->port) {
-#if defined (CONFIG_PXA27x)
-		case 1:
-			pxa_set_cken(CKEN23_SSP1, 1);
-			break;
-		case 2:
-			pxa_set_cken(CKEN3_SSP2, 1);
-			break;
-		case 3:
-			pxa_set_cken(CKEN4_SSP3, 1);
-			break;
-#else
-		case 1:
-			pxa_set_cken(CKEN3_SSP, 1);
-			break;
-		case 2:
-			pxa_set_cken(CKEN9_NSSP, 1);
-			break;
-		case 3:
-			pxa_set_cken(CKEN10_ASSP, 1);
-			break;
-#endif
-	}
-
+	pxa_set_cken(ssp_info[port-1].clock, 1);
 	up(&sem);
 	return 0;
 
@@ -301,46 +282,17 @@
  */
 void ssp_exit(struct ssp_dev *dev)
 {
-	int irq;
-
 	down(&sem);
 	SSCR0_P(dev->port) &= ~SSCR0_SSE;
 
-	/* find irq, save power and turn off SSP port clock */
-	switch (dev->port) {
-#if defined (CONFIG_PXA27x)
-		case 1:
-			irq = IRQ_SSP;
-			pxa_set_cken(CKEN23_SSP1, 0);
-			break;
-		case 2:
-			irq = IRQ_SSP2;
-			pxa_set_cken(CKEN3_SSP2, 0);
-			break;
-		case 3:
-			irq = IRQ_SSP3;
-			pxa_set_cken(CKEN4_SSP3, 0);
-			break;
-#else
-		case 1:
-			irq = IRQ_SSP;
-			pxa_set_cken(CKEN3_SSP, 0);
-			break;
-		case 2:
-			irq = IRQ_NSSP;
-			pxa_set_cken(CKEN9_NSSP, 0);
-			break;
-		case 3:
-			irq = IRQ_ASSP;
-			pxa_set_cken(CKEN10_ASSP, 0);
-			break;
-#endif
-		default:
-			printk(KERN_WARNING "SSP: tried to close invalid port\n");
-			return;
+    	if (dev->port > PXA_SSP_PORTS || dev->port == 0) {
+		printk(KERN_WARNING "SSP: tried to close invalid port\n");
+		return;
 	}
 
-	free_irq(irq, dev);
+	pxa_set_cken(ssp_info[dev->port-1].clock, 0);
+	if (dev->irq)
+		free_irq(dev->irq, dev);
 	release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
 	use_count[dev->port - 1]--;
 	up(&sem);
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 7dad3f1..b9b2057 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -132,11 +132,13 @@
 	tv.tv_sec = pxa_get_rtc_time();
 	do_settimeofday(&tv);
 
-	OSMR0 = 0;		/* set initial match at 0 */
+	OIER = 0;		/* disable any timer interrupts */
+	OSCR = LATCH*2;		/* push OSCR out of the way */
+	OSMR0 = LATCH;		/* set initial match */
 	OSSR = 0xf;		/* clear status on all timers */
 	setup_irq(IRQ_OST0, &pxa_timer_irq);
-	OIER |= OIER_E0;	/* enable match on timer 0 to cause interrupts */
-	OSCR = 0;		/* initialize free-running timer, force first match */
+	OIER = OIER_E0;		/* enable match on timer 0 to cause interrupts */
+	OSCR = 0;		/* initialize free-running timer */
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 400609f..c312054 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -98,6 +98,9 @@
 	.resource	= tosa_scoop_jc_resources,
 };
 
+/*
+ * PCMCIA
+ */
 static struct scoop_pcmcia_dev tosa_pcmcia_scoop[] = {
 {
 	.dev        = &tosascoop_device.dev,
@@ -111,16 +114,155 @@
 },
 };
 
+static void tosa_pcmcia_init(void)
+{
+	/* Setup default state of GPIO outputs
+	   before we enable them as outputs. */
+	GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+		GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
+		GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) |
+		GPIO_bit(GPIO53_nPCE_2);
+
+	pxa_gpio_mode(GPIO48_nPOE_MD);
+	pxa_gpio_mode(GPIO49_nPWE_MD);
+	pxa_gpio_mode(GPIO50_nPIOR_MD);
+	pxa_gpio_mode(GPIO51_nPIOW_MD);
+	pxa_gpio_mode(GPIO55_nPREG_MD);
+	pxa_gpio_mode(GPIO56_nPWAIT_MD);
+	pxa_gpio_mode(GPIO57_nIOIS16_MD);
+	pxa_gpio_mode(GPIO52_nPCE_1_MD);
+	pxa_gpio_mode(GPIO53_nPCE_2_MD);
+	pxa_gpio_mode(GPIO54_pSKTSEL_MD);
+}
+
+static struct scoop_pcmcia_config tosa_pcmcia_config = {
+	.devs         = &tosa_pcmcia_scoop[0],
+	.num_devs     = 2,
+	.pcmcia_init  = tosa_pcmcia_init,
+};
+
+/*
+ * USB Device Controller
+ */
+static void tosa_udc_command(int cmd)
+{
+	switch(cmd)	{
+		case PXA2XX_UDC_CMD_CONNECT:
+			set_scoop_gpio(&tosascoop_jc_device.dev,TOSA_SCOOP_JC_USB_PULLUP);
+			break;
+		case PXA2XX_UDC_CMD_DISCONNECT:
+			reset_scoop_gpio(&tosascoop_jc_device.dev,TOSA_SCOOP_JC_USB_PULLUP);
+			break;
+	}
+}
+
+static int tosa_udc_is_connected(void)
+{
+	return ((GPLR(TOSA_GPIO_USB_IN) & GPIO_bit(TOSA_GPIO_USB_IN)) == 0);
+}
+
+
+static struct pxa2xx_udc_mach_info udc_info __initdata = {
+	.udc_command		= tosa_udc_command,
+	.udc_is_connected	= tosa_udc_is_connected,
+};
+
+/*
+ * MMC/SD Device
+ */
+static struct pxamci_platform_data tosa_mci_platform_data;
+
+static int tosa_mci_init(struct device *dev, irqreturn_t (*tosa_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+	int err;
+
+	/* setup GPIO for PXA25x MMC controller */
+	pxa_gpio_mode(GPIO6_MMCCLK_MD);
+	pxa_gpio_mode(GPIO8_MMCCS0_MD);
+	pxa_gpio_mode(TOSA_GPIO_nSD_DETECT | GPIO_IN);
+
+	tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250);
+
+	err = request_irq(TOSA_IRQ_GPIO_nSD_DETECT, tosa_detect_int, SA_INTERRUPT,
+				"MMC/SD card detect", data);
+	if (err) {
+		printk(KERN_ERR "tosa_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+		return -1;
+	}
+
+	set_irq_type(TOSA_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE);
+
+	return 0;
+}
+
+static void tosa_mci_setpower(struct device *dev, unsigned int vdd)
+{
+	struct pxamci_platform_data* p_d = dev->platform_data;
+
+	if (( 1 << vdd) & p_d->ocr_mask) {
+		set_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_PWR_ON);
+	} else {
+		reset_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_PWR_ON);
+	}
+}
+
+static int tosa_mci_get_ro(struct device *dev)
+{
+	return (read_scoop_reg(&tosascoop_device.dev, SCOOP_GPWR)&TOSA_SCOOP_SD_WP);
+}
+
+static void tosa_mci_exit(struct device *dev, void *data)
+{
+	free_irq(TOSA_IRQ_GPIO_nSD_DETECT, data);
+}
+
+static struct pxamci_platform_data tosa_mci_platform_data = {
+	.ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
+	.init           = tosa_mci_init,
+	.get_ro		= tosa_mci_get_ro,
+	.setpower       = tosa_mci_setpower,
+	.exit           = tosa_mci_exit,
+};
+
+/*
+ * Irda
+ */
+static void tosa_irda_transceiver_mode(struct device *dev, int mode)
+{
+	if (mode & IR_OFF) {
+		reset_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_IR_POWERDWN);
+		pxa_gpio_mode(GPIO47_STTXD|GPIO_DFLT_LOW);
+		pxa_gpio_mode(GPIO47_STTXD|GPIO_OUT);
+	} else {
+		pxa_gpio_mode(GPIO47_STTXD_MD);
+		set_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_IR_POWERDWN);
+	}
+}
+
+static struct pxaficp_platform_data tosa_ficp_platform_data = {
+	.transceiver_cap  = IR_SIRMODE | IR_OFF,
+	.transceiver_mode = tosa_irda_transceiver_mode,
+};
+
+/*
+ * Tosa Keyboard
+ */
+static struct platform_device tosakbd_device = {
+	.name		= "tosa-keyboard",
+	.id		= -1,
+};
 
 static struct platform_device *devices[] __initdata = {
 	&tosascoop_device,
 	&tosascoop_jc_device,
+	&tosakbd_device,
 };
 
 static void __init tosa_init(void)
 {
 	pxa_gpio_mode(TOSA_GPIO_ON_RESET | GPIO_IN);
 	pxa_gpio_mode(TOSA_GPIO_TC6393_INT | GPIO_IN);
+	pxa_gpio_mode(TOSA_GPIO_USB_IN | GPIO_IN);
 
 	/* setup sleep mode values */
 	PWER  = 0x00000002;
@@ -131,13 +273,15 @@
 	PGSR2 = 0x00014000;
 	PCFR |= PCFR_OPDE;
 
-	// enable batt_fault
+	/* enable batt_fault */
 	PMCR = 0x01;
 
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	pxa_set_mci_info(&tosa_mci_platform_data);
+	pxa_set_udc_info(&udc_info);
+	pxa_set_ficp_info(&tosa_ficp_platform_data);
+	platform_scoop_config = &tosa_pcmcia_config;
 
-	scoop_num = 2;
-	scoop_devs = &tosa_pcmcia_scoop[0];
+	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
 static void __init fixup_tosa(struct machine_desc *desc,
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index 011a85c..36e76ba 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -5,3 +5,5 @@
 obj-y					:= core.o clock.o
 obj-$(CONFIG_MACH_REALVIEW_EB)		+= realview_eb.o
 obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
+obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
+obj-$(CONFIG_LOCAL_TIMERS)		+= localtimer.o
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 482eb51..e2c6fa2 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -550,6 +550,11 @@
 
 	timer_tick(regs);
 
+#if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
+	smp_send_timer();
+	update_process_times(user_mode(regs));
+#endif
+
 	write_sequnlock(&xtime_lock);
 
 	return IRQ_HANDLED;
diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c
new file mode 100644
index 0000000..09748cb
--- /dev/null
+++ b/arch/arm/mach-realview/hotplug.c
@@ -0,0 +1,138 @@
+/*
+ *  linux/arch/arm/mach-realview/hotplug.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/completion.h>
+
+extern volatile int pen_release;
+
+static DECLARE_COMPLETION(cpu_killed);
+
+static inline void cpu_enter_lowpower(void)
+{
+	unsigned int v;
+
+	asm volatile(	"mcr	p15, 0, %1, c7, c14, 0\n"
+	"	mcr	p15, 0, %1, c7, c5, 0\n"
+	"	mcr	p15, 0, %1, c7, c10, 4\n"
+	/*
+	 * Turn off coherency
+	 */
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	bic	%0, %0, #0x20\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	"	mrc	p15, 0, %0, c1, c0, 0\n"
+	"	bic	%0, %0, #0x04\n"
+	"	mcr	p15, 0, %0, c1, c0, 0\n"
+	  : "=&r" (v)
+	  : "r" (0)
+	  : "cc");
+}
+
+static inline void cpu_leave_lowpower(void)
+{
+	unsigned int v;
+
+	asm volatile(	"mrc	p15, 0, %0, c1, c0, 0\n"
+	"	orr	%0, %0, #0x04\n"
+	"	mcr	p15, 0, %0, c1, c0, 0\n"
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	orr	%0, %0, #0x20\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	  : "=&r" (v)
+	  :
+	  : "cc");
+}
+
+static inline void platform_do_lowpower(unsigned int cpu)
+{
+	/*
+	 * there is no power-control hardware on this platform, so all
+	 * we can do is put the core into WFI; this is safe as the calling
+	 * code will have already disabled interrupts
+	 */
+	for (;;) {
+		/*
+		 * here's the WFI
+		 */
+		asm(".word	0xe320f003\n"
+		    :
+		    :
+		    : "memory", "cc");
+
+		if (pen_release == cpu) {
+			/*
+			 * OK, proper wakeup, we're done
+			 */
+			break;
+		}
+
+		/*
+		 * getting here, means that we have come out of WFI without
+		 * having been woken up - this shouldn't happen
+		 *
+		 * The trouble is, letting people know about this is not really
+		 * possible, since we are currently running incoherently, and
+		 * therefore cannot safely call printk() or anything else
+		 */
+#ifdef DEBUG
+		printk("CPU%u: spurious wakeup call\n", cpu);
+#endif
+	}
+}
+
+int platform_cpu_kill(unsigned int cpu)
+{
+	return wait_for_completion_timeout(&cpu_killed, 5000);
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void platform_cpu_die(unsigned int cpu)
+{
+#ifdef DEBUG
+	unsigned int this_cpu = hard_smp_processor_id();
+
+	if (cpu != this_cpu) {
+		printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n",
+			   this_cpu, cpu);
+		BUG();
+	}
+#endif
+
+	printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+	complete(&cpu_killed);
+
+	/*
+	 * we're ready for shutdown now, so do it
+	 */
+	cpu_enter_lowpower();
+	platform_do_lowpower(cpu);
+
+	/*
+	 * bring this CPU back into the world of cache
+	 * coherency, and then restore interrupts
+	 */
+	cpu_leave_lowpower();
+}
+
+int mach_cpu_disable(unsigned int cpu)
+{
+	/*
+	 * we don't allow CPU 0 to be shutdown (it is still too special
+	 * e.g. clock tick interrupts)
+	 */
+	return cpu == 0 ? -EPERM : 0;
+}
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c
new file mode 100644
index 0000000..5e917e3
--- /dev/null
+++ b/arch/arm/mach-realview/localtimer.c
@@ -0,0 +1,130 @@
+/*
+ *  linux/arch/arm/mach-realview/localtimer.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+
+#include <asm/mach/time.h>
+#include <asm/hardware/arm_twd.h>
+#include <asm/hardware/gic.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "core.h"
+
+#define TWD_BASE(cpu)	(__io_address(REALVIEW_TWD_BASE) + \
+			 ((cpu) * REALVIEW_TWD_SIZE))
+
+static unsigned long mpcore_timer_rate;
+
+/*
+ * local_timer_ack: checks for a local timer interrupt.
+ *
+ * If a local timer interrupt has occured, acknowledge and return 1.
+ * Otherwise, return 0.
+ */
+int local_timer_ack(void)
+{
+	void __iomem *base = TWD_BASE(smp_processor_id());
+
+	if (__raw_readl(base + TWD_TIMER_INTSTAT)) {
+		__raw_writel(1, base + TWD_TIMER_INTSTAT);
+		return 1;
+	}
+
+	return 0;
+}
+
+void __cpuinit local_timer_setup(unsigned int cpu)
+{
+	void __iomem *base = TWD_BASE(cpu);
+	unsigned int load, offset;
+	u64 waitjiffies;
+	unsigned int count;
+
+	/*
+	 * If this is the first time round, we need to work out how fast
+	 * the timer ticks
+	 */
+	if (mpcore_timer_rate == 0) {
+		printk("Calibrating local timer... ");
+
+		/* Wait for a tick to start */
+		waitjiffies = get_jiffies_64() + 1;
+
+		while (get_jiffies_64() < waitjiffies)
+			udelay(10);
+
+		/* OK, now the tick has started, let's get the timer going */
+		waitjiffies += 5;
+
+				 /* enable, no interrupt or reload */
+		__raw_writel(0x1, base + TWD_TIMER_CONTROL);
+
+				 /* maximum value */
+		__raw_writel(0xFFFFFFFFU, base + TWD_TIMER_COUNTER);
+
+		while (get_jiffies_64() < waitjiffies)
+			udelay(10);
+
+		count = __raw_readl(base + TWD_TIMER_COUNTER);
+
+		mpcore_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
+
+		printk("%lu.%02luMHz.\n", mpcore_timer_rate / 1000000,
+			(mpcore_timer_rate / 100000) % 100);
+	}
+
+	load = mpcore_timer_rate / HZ;
+
+	__raw_writel(load, base + TWD_TIMER_LOAD);
+	__raw_writel(0x7,  base + TWD_TIMER_CONTROL);
+
+	/*
+	 * Now maneuver our local tick into the right part of the jiffy.
+	 * Start by working out where within the tick our local timer
+	 * interrupt should go.
+	 */
+	offset = ((mpcore_timer_rate / HZ) / (NR_CPUS + 1)) * (cpu + 1);
+
+	/*
+	 * gettimeoffset() will return a number of us since the last tick.
+	 * Convert this number of us to a local timer tick count.
+	 * Be careful of integer overflow whilst keeping maximum precision.
+	 *
+	 * with HZ=100 and 1MHz (fpga) ~ 1GHz processor:
+	 * load = 1 ~ 10,000
+	 * mpcore_timer_rate/10000 = 100 ~ 100,000
+	 *
+	 * so the multiply value will be less than 10^9 always.
+	 */
+	load = (system_timer->offset() * (mpcore_timer_rate / 10000)) / 100;
+
+	/* Add on our offset to get the load value */
+	load = (load + offset) % (mpcore_timer_rate / HZ);
+
+	__raw_writel(load, base + TWD_TIMER_COUNTER);
+
+	/* Make sure our local interrupt controller has this enabled */
+	__raw_writel(1 << IRQ_LOCALTIMER,
+		     __io_address(REALVIEW_GIC_DIST_BASE) + GIC_DIST_ENABLE_SET);
+}
+
+/*
+ * take a local timer down
+ */
+void __cpuexit local_timer_stop(unsigned int cpu)
+{
+	__raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL);
+}
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 9844644..0c7d4ac 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -32,7 +32,7 @@
 {
 	unsigned int ncores;
 
-	ncores = __raw_readl(IO_ADDRESS(REALVIEW_MPCORE_SCU_BASE) + SCU_CONFIG);
+	ncores = __raw_readl(__io_address(REALVIEW_MPCORE_SCU_BASE) + SCU_CONFIG);
 
 	return (ncores & 0x03) + 1;
 }
@@ -133,12 +133,12 @@
 #if 1
 #define REALVIEW_SYS_FLAGSS_OFFSET 0x30
 	__raw_writel(virt_to_phys(realview_secondary_startup),
-		     (IO_ADDRESS(REALVIEW_SYS_BASE) +
-		      REALVIEW_SYS_FLAGSS_OFFSET));
+		     __io_address(REALVIEW_SYS_BASE) +
+		     REALVIEW_SYS_FLAGSS_OFFSET);
 #define REALVIEW_SYS_FLAGSC_OFFSET 0x34
 	__raw_writel(3,
-		     (IO_ADDRESS(REALVIEW_SYS_BASE) +
-		      REALVIEW_SYS_FLAGSC_OFFSET));
+		     __io_address(REALVIEW_SYS_BASE) +
+		     REALVIEW_SYS_FLAGSC_OFFSET);
 #endif
 
 	mb();
@@ -175,6 +175,11 @@
 		max_cpus = ncores;
 
 	/*
+	 * Enable the local timer for primary CPU
+	 */
+	local_timer_setup(cpu);
+
+	/*
 	 * Initialise the possible/present maps.
 	 * cpu_possible_map describes the set of CPUs which may be present
 	 * cpu_present_map describes the set of CPUs populated
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index c796bcd..0b9d7ca 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -121,6 +121,14 @@
 	  system resets depends on the value of PCLK. The timeout on an
 	  200MHz s3c2410 should be about 30 seconds.
 
+config S3C2410_BOOT_ERROR_RESET
+	bool "S3C2410 Reboot on decompression error"
+	depends on ARCH_S3C2410
+	help
+	  Say y here to use the watchdog to reset the system if the
+	  kernel decompressor detects an error during decompression.
+
+
 comment "S3C2410 Setup"
 
 config S3C2410_DMA
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c
index 8390b68..0f81fc0 100644
--- a/arch/arm/mach-s3c2410/mach-anubis.c
+++ b/arch/arm/mach-s3c2410/mach-anubis.c
@@ -56,8 +56,16 @@
 static struct map_desc anubis_iodesc[] __initdata = {
   /* ISA IO areas */
 
-  { (u32)S3C24XX_VA_ISA_BYTE, 0x0,	   SZ_16M, MT_DEVICE },
-  { (u32)S3C24XX_VA_ISA_WORD, 0x0,	   SZ_16M, MT_DEVICE },
+  {
+	.virtual	= (u32)S3C24XX_VA_ISA_BYTE,
+	.pfn		= __phys_to_pfn(0x0),
+	.length		= SZ_4M,
+	.type		= MT_DEVICE
+  }, {
+	.virtual	= (u32)S3C24XX_VA_ISA_WORD,
+	.pfn		= __phys_to_pfn(0x0),
+	.length 	= SZ_4M, MT_DEVICE
+  },
 
   /* we could possibly compress the next set down into a set of smaller tables
    * pagetables, but that would mean using an L2 section, and it still means
@@ -66,16 +74,41 @@
 
   /* CPLD control registers */
 
-  { (u32)ANUBIS_VA_CTRL1,	ANUBIS_PA_CTRL1,	SZ_4K, MT_DEVICE },
-  { (u32)ANUBIS_VA_CTRL2,	ANUBIS_PA_CTRL2,	SZ_4K, MT_DEVICE },
+  {
+	.virtual	= (u32)ANUBIS_VA_CTRL1,
+	.pfn		= __phys_to_pfn(ANUBIS_PA_CTRL1),
+	.length		= SZ_4K,
+	.type		= MT_DEVICE
+  }, {
+	.virtual	= (u32)ANUBIS_VA_CTRL2,
+	.pfn		= __phys_to_pfn(ANUBIS_PA_CTRL2),
+	.length		= SZ_4K,
+	.type		=MT_DEVICE
+  },
 
   /* IDE drives */
 
-  { (u32)ANUBIS_IDEPRI,		S3C2410_CS3,		SZ_1M, MT_DEVICE },
-  { (u32)ANUBIS_IDEPRIAUX,	S3C2410_CS3+(1<<26),	SZ_1M, MT_DEVICE },
-
-  { (u32)ANUBIS_IDESEC,		S3C2410_CS4,		SZ_1M, MT_DEVICE },
-  { (u32)ANUBIS_IDESECAUX,	S3C2410_CS4+(1<<26),	SZ_1M, MT_DEVICE },
+  {
+	.virtual	= (u32)ANUBIS_IDEPRI,
+	.pfn		= __phys_to_pfn(S3C2410_CS3),
+	.length		= SZ_1M,
+	.type		= MT_DEVICE
+  }, {
+	.virtual	= (u32)ANUBIS_IDEPRIAUX,
+	.pfn		= __phys_to_pfn(S3C2410_CS3+(1<<26)),
+	.length		= SZ_1M,
+	.type		= MT_DEVICE
+  }, {
+	.virtual	= (u32)ANUBIS_IDESEC,
+	.pfn		= __phys_to_pfn(S3C2410_CS4),
+	.length		= SZ_1M,
+	.type		= MT_DEVICE
+  }, {
+	.virtual	= (u32)ANUBIS_IDESECAUX,
+	.pfn		= __phys_to_pfn(S3C2410_CS4+(1<<26)),
+	.length		= SZ_1M,
+	.type		= MT_DEVICE
+  },
 };
 
 #define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 0b71c89..1be2567 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -89,32 +89,63 @@
 
 /* macros to modify the physical addresses for io space */
 
-#define PA_CS2(item) ((item) + S3C2410_CS2)
-#define PA_CS3(item) ((item) + S3C2410_CS3)
-#define PA_CS4(item) ((item) + S3C2410_CS4)
-#define PA_CS5(item) ((item) + S3C2410_CS5)
+#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
+#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
+#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
+#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
 
 static struct map_desc bast_iodesc[] __initdata = {
   /* ISA IO areas */
-
-  { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO),   SZ_16M, MT_DEVICE },
-  { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO),   SZ_16M, MT_DEVICE },
-
-  /* we could possibly compress the next set down into a set of smaller tables
-   * pagetables, but that would mean using an L2 section, and it still means
-   * we cannot actually feed the same register to an LDR due to 16K spacing
-   */
-
+  {
+	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE,
+	  .pfn		= PA_CS2(BAST_PA_ISAIO),
+	  .length	= SZ_16M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)S3C24XX_VA_ISA_WORD,
+	  .pfn		= PA_CS3(BAST_PA_ISAIO),
+	  .length	= SZ_16M,
+	  .type		= MT_DEVICE,
+  },
   /* bast CPLD control registers, and external interrupt controls */
-  { (u32)BAST_VA_CTRL1, BAST_PA_CTRL1,		   SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_CTRL2, BAST_PA_CTRL2,		   SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_CTRL3, BAST_PA_CTRL3,		   SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_CTRL4, BAST_PA_CTRL4,		   SZ_1M, MT_DEVICE },
-
+  {
+	  .virtual	= (u32)BAST_VA_CTRL1,
+	  .pfn		= __phys_to_pfn(BAST_PA_CTRL1),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_CTRL2,
+	  .pfn		= __phys_to_pfn(BAST_PA_CTRL2),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_CTRL3,
+	  .pfn		= __phys_to_pfn(BAST_PA_CTRL3),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_CTRL4,
+	  .pfn		= __phys_to_pfn(BAST_PA_CTRL4),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  },
   /* PC104 IRQ mux */
-  { (u32)BAST_VA_PC104_IRQREQ,  BAST_PA_PC104_IRQREQ,   SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_PC104_IRQRAW,  BAST_PA_PC104_IRQRAW,   SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_PC104_IRQMASK, BAST_PA_PC104_IRQMASK,  SZ_1M, MT_DEVICE },
+  {
+	  .virtual	= (u32)BAST_VA_PC104_IRQREQ,
+	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQREQ),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_PC104_IRQRAW,
+	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQRAW),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)BAST_VA_PC104_IRQMASK,
+	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQMASK),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  },
 
   /* peripheral space... one for each of fast/slow/byte/16bit */
   /* note, ide is only decoded in word space, even though some registers
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c
index 24d6901..f8d86d1 100644
--- a/arch/arm/mach-s3c2410/mach-rx3715.c
+++ b/arch/arm/mach-s3c2410/mach-rx3715.c
@@ -56,8 +56,17 @@
 static struct map_desc rx3715_iodesc[] __initdata = {
 	/* dump ISA space somewhere unused */
 
-	{ (u32)S3C24XX_VA_ISA_WORD, S3C2410_CS3, SZ_16M, MT_DEVICE },
-	{ (u32)S3C24XX_VA_ISA_BYTE, S3C2410_CS3, SZ_16M, MT_DEVICE },
+	{
+		.virtual	= (u32)S3C24XX_VA_ISA_WORD,
+		.pfn		= __phys_to_pfn(S3C2410_CS3),
+		.length		= SZ_1M,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (u32)S3C24XX_VA_ISA_BYTE,
+		.pfn		= __phys_to_pfn(S3C2410_CS3),
+		.length		= SZ_1M,
+		.type		= MT_DEVICE,
+	},
 };
 
 
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
index d666c62..4e31118 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
@@ -58,8 +58,27 @@
 static struct map_desc smdk2440_iodesc[] __initdata = {
 	/* ISA IO Space map (memory space selected by A24) */
 
-	{ (u32)S3C24XX_VA_ISA_WORD, S3C2410_CS2, SZ_16M, MT_DEVICE },
-	{ (u32)S3C24XX_VA_ISA_BYTE, S3C2410_CS2, SZ_16M, MT_DEVICE },
+	{
+		.virtual	= (u32)S3C24XX_VA_ISA_WORD,
+		.pfn		= __phys_to_pfn(S3C2410_CS2),
+		.length		= 0x10000,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (u32)S3C24XX_VA_ISA_WORD + 0x10000,
+		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+		.length		= SZ_4M,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (u32)S3C24XX_VA_ISA_BYTE,
+		.pfn		= __phys_to_pfn(S3C2410_CS2),
+		.length		= 0x10000,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
+		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+		.length		= SZ_4M,
+		.type		= MT_DEVICE,
+	}
 };
 
 #define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index 46b2596..ae7e099 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -74,27 +74,47 @@
 
 /* macros to modify the physical addresses for io space */
 
-#define PA_CS2(item) ((item) + S3C2410_CS2)
-#define PA_CS3(item) ((item) + S3C2410_CS3)
-#define PA_CS4(item) ((item) + S3C2410_CS4)
-#define PA_CS5(item) ((item) + S3C2410_CS5)
+#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
+#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
+#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
+#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
 
 static struct map_desc vr1000_iodesc[] __initdata = {
   /* ISA IO areas */
+  {
+	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE,
+	  .pfn		= PA_CS2(BAST_PA_ISAIO),
+	  .length	= SZ_16M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)S3C24XX_VA_ISA_WORD,
+	  .pfn		= PA_CS3(BAST_PA_ISAIO),
+	  .length	= SZ_16M,
+	  .type		= MT_DEVICE,
+  },
 
-  { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO),	   SZ_16M, MT_DEVICE },
-  { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO),	   SZ_16M, MT_DEVICE },
-
-  /* we could possibly compress the next set down into a set of smaller tables
-   * pagetables, but that would mean using an L2 section, and it still means
-   * we cannot actually feed the same register to an LDR due to 16K spacing
-   */
-
-  /* bast CPLD control registers, and external interrupt controls */
-  { (u32)VR1000_VA_CTRL1, VR1000_PA_CTRL1,	       SZ_1M, MT_DEVICE },
-  { (u32)VR1000_VA_CTRL2, VR1000_PA_CTRL2,	       SZ_1M, MT_DEVICE },
-  { (u32)VR1000_VA_CTRL3, VR1000_PA_CTRL3,	       SZ_1M, MT_DEVICE },
-  { (u32)VR1000_VA_CTRL4, VR1000_PA_CTRL4,	       SZ_1M, MT_DEVICE },
+  /*  CPLD control registers, and external interrupt controls */
+  {
+	  .virtual	= (u32)VR1000_VA_CTRL1,
+	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL1),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)VR1000_VA_CTRL2,
+	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL2),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)VR1000_VA_CTRL3,
+	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL3),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  }, {
+	  .virtual	= (u32)VR1000_VA_CTRL4,
+	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL4),
+	  .length	= SZ_1M,
+	  .type		= MT_DEVICE,
+  },
 
   /* peripheral space... one for each of fast/slow/byte/16bit */
   /* note, ide is only decoded in word space, even though some registers
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 69f1970..9e02bc3 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -137,7 +137,7 @@
 	.get_mctrl	= neponset_get_mctrl,
 };
 
-static int neponset_probe(struct device *dev)
+static int neponset_probe(struct platform_device *dev)
 {
 	sa1100_register_uart_fns(&neponset_port_fns);
 
@@ -178,27 +178,27 @@
 /*
  * LDM power management.
  */
-static int neponset_suspend(struct device *dev, pm_message_t state)
+static int neponset_suspend(struct platform_device *dev, pm_message_t state)
 {
 	/*
 	 * Save state.
 	 */
-	if (!dev->power.saved_state)
-		dev->power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
-	if (!dev->power.saved_state)
+	if (!dev->dev.power.saved_state)
+		dev->dev.power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
+	if (!dev->dev.power.saved_state)
 		return -ENOMEM;
 
-	*(unsigned int *)dev->power.saved_state = NCR_0;
+	*(unsigned int *)dev->dev.power.saved_state = NCR_0;
 
 	return 0;
 }
 
-static int neponset_resume(struct device *dev)
+static int neponset_resume(struct platform_device *dev)
 {
-	if (dev->power.saved_state) {
-		NCR_0 = *(unsigned int *)dev->power.saved_state;
-		kfree(dev->power.saved_state);
-		dev->power.saved_state = NULL;
+	if (dev->dev.power.saved_state) {
+		NCR_0 = *(unsigned int *)dev->dev.power.saved_state;
+		kfree(dev->dev.power.saved_state);
+		dev->dev.power.saved_state = NULL;
 	}
 
 	return 0;
@@ -209,12 +209,13 @@
 #define neponset_resume  NULL
 #endif
 
-static struct device_driver neponset_device_driver = {
-	.name		= "neponset",
-	.bus		= &platform_bus_type,
+static struct platform_driver neponset_device_driver = {
 	.probe		= neponset_probe,
 	.suspend	= neponset_suspend,
 	.resume		= neponset_resume,
+	.driver		= {
+		.name	= "neponset",
+	},
 };
 
 static struct resource neponset_resources[] = {
@@ -293,7 +294,7 @@
 
 static int __init neponset_init(void)
 {
-	driver_register(&neponset_device_driver);
+	platform_driver_register(&neponset_device_driver);
 
 	/*
 	 * The Neponset is only present on the Assabet machine type.
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 47e0420..e4b435e 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -124,11 +124,13 @@
 	tv.tv_sec = sa1100_get_rtc_time();
 	do_settimeofday(&tv);
 
-	OSMR0 = 0;		/* set initial match at 0 */
+	OIER = 0;		/* disable any timer interrupts */
+	OSCR = LATCH*2;		/* push OSCR out of the way */
+	OSMR0 = LATCH;		/* set initial match */
 	OSSR = 0xf;		/* clear status on all timers */
 	setup_irq(IRQ_OST0, &sa1100_timer_irq);
-	OIER |= OIER_E0;	/* enable match on timer 0 to cause interrupts */
-	OSCR = 0;		/* initialize free-running timer, force first match */
+	OIER = OIER_E0;		/* enable match on timer 0 to cause interrupts */
+	OSCR = 0;		/* initialize free-running timer */
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index e3c14d6..e84fdde 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -102,8 +102,8 @@
 # ARM925T
 config CPU_ARM925T
  	bool "Support ARM925T processor" if ARCH_OMAP1
- 	depends on ARCH_OMAP1510
- 	default y if ARCH_OMAP1510
+ 	depends on ARCH_OMAP15XX
+ 	default y if ARCH_OMAP15XX
 	select CPU_32v4
 	select CPU_ABRT_EV4T
 	select CPU_CACHE_V4WT
@@ -242,7 +242,7 @@
 # ARMv6
 config CPU_V6
 	bool "Support ARM V6 processor"
-	depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB
+	depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2
 	select CPU_32v6
 	select CPU_ABRT_EV6
 	select CPU_CACHE_V6
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 7e144f9..9ccf194 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := common.o sram.o sram-fn.o clock.o dma.o mux.o gpio.o mcbsp.o usb.o
+obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o
 obj-m :=
 obj-n :=
 obj-  :=
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index a020fe1..7ce39b9 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -1,15 +1,20 @@
 /*
  *  linux/arch/arm/plat-omap/clock.c
  *
- *  Copyright (C) 2004 Nokia corporation
+ *  Copyright (C) 2004 - 2005 Nokia corporation
  *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
  *
+ *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
+ *
  * 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/version.h>
+#include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/err.h>
@@ -18,562 +23,20 @@
 #include <asm/io.h>
 #include <asm/semaphore.h>
 #include <asm/hardware/clock.h>
-#include <asm/arch/board.h>
-#include <asm/arch/usb.h>
 
-#include "clock.h"
-#include "sram.h"
+#include <asm/arch/clock.h>
 
-static LIST_HEAD(clocks);
+LIST_HEAD(clocks);
 static DECLARE_MUTEX(clocks_sem);
-static DEFINE_SPINLOCK(clockfw_lock);
-static void propagate_rate(struct clk *  clk);
-/* UART clock function */
-static int set_uart_rate(struct clk * clk, unsigned long rate);
-/* External clock (MCLK & BCLK) functions */
-static int set_ext_clk_rate(struct clk *  clk, unsigned long rate);
-static long round_ext_clk_rate(struct clk *  clk, unsigned long rate);
-static void init_ext_clk(struct clk *  clk);
-/* MPU virtual clock functions */
-static int select_table_rate(struct clk *  clk, unsigned long rate);
-static long round_to_table_rate(struct clk *  clk, unsigned long rate);
-void clk_setdpll(__u16, __u16);
+DEFINE_SPINLOCK(clockfw_lock);
 
-static struct mpu_rate rate_table[] = {
-	/* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
-	 * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
-	 */
-#if defined(CONFIG_OMAP_ARM_216MHZ)
-	{ 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */
-#endif
-#if defined(CONFIG_OMAP_ARM_195MHZ)
-	{ 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */
-#endif
-#if defined(CONFIG_OMAP_ARM_192MHZ)
-	{ 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */
-	{ 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */
-	{  96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */
-	{  48000000, 12000000, 192000000, 0x0baf, 0x2810 }, /* 4/8/4/4/8/8 */
-	{  24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */
-#endif
-#if defined(CONFIG_OMAP_ARM_182MHZ)
-	{ 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */
-#endif
-#if defined(CONFIG_OMAP_ARM_168MHZ)
-	{ 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
-#endif
-#if defined(CONFIG_OMAP_ARM_150MHZ)
-	{ 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */
-#endif
-#if defined(CONFIG_OMAP_ARM_120MHZ)
-	{ 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
-#endif
-#if defined(CONFIG_OMAP_ARM_96MHZ)
-	{  96000000, 12000000,  96000000, 0x0005, 0x2410 }, /* 1/1/1/1/2/2 */
-#endif
-#if defined(CONFIG_OMAP_ARM_60MHZ)
-	{  60000000, 12000000,  60000000, 0x0005, 0x2290 }, /* 1/1/1/1/2/2 */
-#endif
-#if defined(CONFIG_OMAP_ARM_30MHZ)
-	{  30000000, 12000000,  60000000, 0x0555, 0x2290 }, /* 2/2/2/2/2/2 */
-#endif
-	{ 0, 0, 0, 0, 0 },
-};
+static struct clk_functions *arch_clock;
 
+/*-------------------------------------------------------------------------
+ * Standard clock functions defined in asm/hardware/clock.h
+ *-------------------------------------------------------------------------*/
 
-static void ckctl_recalc(struct clk *  clk);
-int __clk_enable(struct clk *clk);
-void __clk_disable(struct clk *clk);
-void __clk_unuse(struct clk *clk);
-int __clk_use(struct clk *clk);
-
-
-static void followparent_recalc(struct clk *  clk)
-{
-	clk->rate = clk->parent->rate;
-}
-
-
-static void watchdog_recalc(struct clk *  clk)
-{
-	clk->rate = clk->parent->rate / 14;
-}
-
-static void uart_recalc(struct clk * clk)
-{
-	unsigned int val = omap_readl(clk->enable_reg);
-	if (val & clk->enable_bit)
-		clk->rate = 48000000;
-	else
-		clk->rate = 12000000;
-}
-
-static struct clk ck_ref = {
-	.name		= "ck_ref",
-	.rate		= 12000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  ALWAYS_ENABLED,
-};
-
-static struct clk ck_dpll1 = {
-	.name		= "ck_dpll1",
-	.parent		= &ck_ref,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_PROPAGATES | ALWAYS_ENABLED,
-};
-
-static struct clk ck_dpll1out = {
-	.name		= "ck_dpll1out",
-	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP16XX,
-	.enable_reg	= ARM_IDLECT2,
-	.enable_bit	= EN_CKOUT_ARM,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk arm_ck = {
-	.name		= "arm_ck",
-	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
-	.rate_offset	= CKCTL_ARMDIV_OFFSET,
-	.recalc		= &ckctl_recalc,
-};
-
-static struct clk armper_ck = {
-	.name		= "armper_ck",
-	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_CKCTL,
-	.enable_reg	= ARM_IDLECT2,
-	.enable_bit	= EN_PERCK,
-	.rate_offset	= CKCTL_PERDIV_OFFSET,
-	.recalc		= &ckctl_recalc,
-};
-
-static struct clk arm_gpio_ck = {
-	.name		= "arm_gpio_ck",
-	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510,
-	.enable_reg	= ARM_IDLECT2,
-	.enable_bit	= EN_GPIOCK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk armxor_ck = {
-	.name		= "armxor_ck",
-	.parent		= &ck_ref,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-	.enable_reg	= ARM_IDLECT2,
-	.enable_bit	= EN_XORPCK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk armtim_ck = {
-	.name		= "armtim_ck",
-	.parent		= &ck_ref,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-	.enable_reg	= ARM_IDLECT2,
-	.enable_bit	= EN_TIMCK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk armwdt_ck = {
-	.name		= "armwdt_ck",
-	.parent		= &ck_ref,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-	.enable_reg	= ARM_IDLECT2,
-	.enable_bit	= EN_WDTCK,
-	.recalc		= &watchdog_recalc,
-};
-
-static struct clk arminth_ck16xx = {
-	.name		= "arminth_ck",
-	.parent		= &arm_ck,
-	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-	.recalc		= &followparent_recalc,
-	/* Note: On 16xx the frequency can be divided by 2 by programming
-	 * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
-	 *
-	 * 1510 version is in TC clocks.
-	 */
-};
-
-static struct clk dsp_ck = {
-	.name		= "dsp_ck",
-	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_CKCTL,
-	.enable_reg	= ARM_CKCTL,
-	.enable_bit	= EN_DSPCK,
-	.rate_offset	= CKCTL_DSPDIV_OFFSET,
-	.recalc		= &ckctl_recalc,
-};
-
-static struct clk dspmmu_ck = {
-	.name		= "dspmmu_ck",
-	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_CKCTL | ALWAYS_ENABLED,
-	.rate_offset	= CKCTL_DSPMMUDIV_OFFSET,
-	.recalc		= &ckctl_recalc,
-};
-
-static struct clk dspper_ck = {
-	.name		= "dspper_ck",
-	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_CKCTL | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
-	.enable_reg	= DSP_IDLECT2,
-	.enable_bit	= EN_PERCK,
-	.rate_offset	= CKCTL_PERDIV_OFFSET,
-	.recalc		= &followparent_recalc,
-	//.recalc		= &ckctl_recalc,
-};
-
-static struct clk dspxor_ck = {
-	.name		= "dspxor_ck",
-	.parent		= &ck_ref,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
-	.enable_reg	= DSP_IDLECT2,
-	.enable_bit	= EN_XORPCK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk dsptim_ck = {
-	.name		= "dsptim_ck",
-	.parent		= &ck_ref,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
-	.enable_reg	= DSP_IDLECT2,
-	.enable_bit	= EN_DSPTIMCK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk tc_ck = {
-	.name		= "tc_ck",
-	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 |
-			  RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
-	.rate_offset	= CKCTL_TCDIV_OFFSET,
-	.recalc		= &ckctl_recalc,
-};
-
-static struct clk arminth_ck1510 = {
-	.name		= "arminth_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
-	.recalc		= &followparent_recalc,
-	/* Note: On 1510 the frequency follows TC_CK
-	 *
-	 * 16xx version is in MPU clocks.
-	 */
-};
-
-static struct clk tipb_ck = {
-	.name		= "tibp_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk l3_ocpi_ck = {
-	.name		= "l3_ocpi_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
-	.enable_reg	= ARM_IDLECT3,
-	.enable_bit	= EN_OCPI_CK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk tc1_ck = {
-	.name		= "tc1_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
-	.enable_reg	= ARM_IDLECT3,
-	.enable_bit	= EN_TC1_CK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk tc2_ck = {
-	.name		= "tc2_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX,
-	.enable_reg	= ARM_IDLECT3,
-	.enable_bit	= EN_TC2_CK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk dma_ck = {
-	.name		= "dma_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  ALWAYS_ENABLED,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk dma_lcdfree_ck = {
-	.name		= "dma_lcdfree_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk api_ck = {
-	.name		= "api_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-	.enable_reg	= ARM_IDLECT2,
-	.enable_bit	= EN_APICK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk lb_ck = {
-	.name		= "lb_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP1510,
-	.enable_reg	= ARM_IDLECT2,
-	.enable_bit	= EN_LBCK,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk rhea1_ck = {
-	.name		= "rhea1_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk rhea2_ck = {
-	.name		= "rhea2_ck",
-	.parent		= &tc_ck,
-	.flags		= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-	.recalc		= &followparent_recalc,
-};
-
-static struct clk lcd_ck = {
-	.name		= "lcd_ck",
-	.parent		= &ck_dpll1,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 |
-			  RATE_CKCTL,
-	.enable_reg	= ARM_IDLECT2,
-	.enable_bit	= EN_LCDCK,
-	.rate_offset	= CKCTL_LCDDIV_OFFSET,
-	.recalc		= &ckctl_recalc,
-};
-
-static struct clk uart1_1510 = {
-	.name		= "uart1_ck",
-	/* Direct from ULPD, no parent */
-	.rate		= 12000000,
-	.flags		= CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
-	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= 29,	/* Chooses between 12MHz and 48MHz */
-	.set_rate	= &set_uart_rate,
-	.recalc		= &uart_recalc,
-};
-
-static struct clk uart1_16xx = {
-	.name		= "uart1_ck",
-	/* Direct from ULPD, no parent */
-	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
-	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= 29,
-};
-
-static struct clk uart2_ck = {
-	.name		= "uart2_ck",
-	/* Direct from ULPD, no parent */
-	.rate		= 12000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT |
-			  ALWAYS_ENABLED,
-	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= 30,	/* Chooses between 12MHz and 48MHz */
-	.set_rate	= &set_uart_rate,
-	.recalc		= &uart_recalc,
-};
-
-static struct clk uart3_1510 = {
-	.name		= "uart3_ck",
-	/* Direct from ULPD, no parent */
-	.rate		= 12000000,
-	.flags		= CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
-	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= 31,	/* Chooses between 12MHz and 48MHz */
-	.set_rate	= &set_uart_rate,
-	.recalc		= &uart_recalc,
-};
-
-static struct clk uart3_16xx = {
-	.name		= "uart3_ck",
-	/* Direct from ULPD, no parent */
-	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
-	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= 31,
-};
-
-static struct clk usb_clko = {	/* 6 MHz output on W4_USB_CLKO */
-	.name		= "usb_clko",
-	/* Direct from ULPD, no parent */
-	.rate		= 6000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
-	.enable_reg	= ULPD_CLOCK_CTRL,
-	.enable_bit	= USB_MCLK_EN_BIT,
-};
-
-static struct clk usb_hhc_ck1510 = {
-	.name		= "usb_hhc_ck",
-	/* Direct from ULPD, no parent */
-	.rate		= 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
-	.flags		= CLOCK_IN_OMAP1510 |
-			  RATE_FIXED | ENABLE_REG_32BIT,
-	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= USB_HOST_HHC_UHOST_EN,
-};
-
-static struct clk usb_hhc_ck16xx = {
-	.name		= "usb_hhc_ck",
-	/* Direct from ULPD, no parent */
-	.rate		= 48000000,
-	/* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
-	.flags		= CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
-	.enable_reg	= OTG_BASE + 0x08 /* OTG_SYSCON_2 */,
-	.enable_bit	= 8 /* UHOST_EN */,
-};
-
-static struct clk usb_dc_ck = {
-	.name		= "usb_dc_ck",
-	/* Direct from ULPD, no parent */
-	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED,
-	.enable_reg	= SOFT_REQ_REG,
-	.enable_bit	= 4,
-};
-
-static struct clk mclk_1510 = {
-	.name		= "mclk",
-	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
-	.rate		= 12000000,
-	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,
-};
-
-static struct clk mclk_16xx = {
-	.name		= "mclk",
-	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
-	.flags		= CLOCK_IN_OMAP16XX,
-	.enable_reg	= COM_CLK_DIV_CTRL_SEL,
-	.enable_bit	= COM_ULPD_PLL_CLK_REQ,
-	.set_rate	= &set_ext_clk_rate,
-	.round_rate	= &round_ext_clk_rate,
-	.init		= &init_ext_clk,
-};
-
-static struct clk bclk_1510 = {
-	.name		= "bclk",
-	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
-	.rate		= 12000000,
-	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,
-};
-
-static struct clk bclk_16xx = {
-	.name		= "bclk",
-	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
-	.flags		= CLOCK_IN_OMAP16XX,
-	.enable_reg	= SWD_CLK_DIV_CTRL_SEL,
-	.enable_bit	= SWD_ULPD_PLL_CLK_REQ,
-	.set_rate	= &set_ext_clk_rate,
-	.round_rate	= &round_ext_clk_rate,
-	.init		= &init_ext_clk,
-};
-
-static struct clk mmc1_ck = {
-	.name		= "mmc1_ck",
-	/* Functional clock is direct from ULPD, interface clock is ARMPER */
-	.parent		= &armper_ck,
-	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
-	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= 23,
-};
-
-static struct clk mmc2_ck = {
-	.name		= "mmc2_ck",
-	/* Functional clock is direct from ULPD, interface clock is ARMPER */
-	.parent		= &armper_ck,
-	.rate		= 48000000,
-	.flags		= CLOCK_IN_OMAP16XX |
-			  RATE_FIXED | ENABLE_REG_32BIT,
-	.enable_reg	= MOD_CONF_CTRL_0,
-	.enable_bit	= 20,
-};
-
-static struct clk virtual_ck_mpu = {
-	.name		= "mpu",
-	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-			  VIRTUAL_CLOCK | ALWAYS_ENABLED,
-	.parent		= &arm_ck, /* Is smarter alias for */
-	.recalc		= &followparent_recalc,
-	.set_rate	= &select_table_rate,
-	.round_rate	= &round_to_table_rate,
-};
-
-
-static struct clk *  onchip_clks[] = {
-	/* non-ULPD clocks */
-	&ck_ref,
-	&ck_dpll1,
-	/* CK_GEN1 clocks */
-	&ck_dpll1out,
-	&arm_ck,
-	&armper_ck,
-	&arm_gpio_ck,
-	&armxor_ck,
-	&armtim_ck,
-	&armwdt_ck,
-	&arminth_ck1510,  &arminth_ck16xx,
-	/* CK_GEN2 clocks */
-	&dsp_ck,
-	&dspmmu_ck,
-	&dspper_ck,
-	&dspxor_ck,
-	&dsptim_ck,
-	/* CK_GEN3 clocks */
-	&tc_ck,
-	&tipb_ck,
-	&l3_ocpi_ck,
-	&tc1_ck,
-	&tc2_ck,
-	&dma_ck,
-	&dma_lcdfree_ck,
-	&api_ck,
-	&lb_ck,
-	&rhea1_ck,
-	&rhea2_ck,
-	&lcd_ck,
-	/* ULPD clocks */
-	&uart1_1510,
-	&uart1_16xx,
-	&uart2_ck,
-	&uart3_1510,
-	&uart3_16xx,
-	&usb_clko,
-	&usb_hhc_ck1510, &usb_hhc_ck16xx,
-	&usb_dc_ck,
-	&mclk_1510,  &mclk_16xx,
-	&bclk_1510,  &bclk_16xx,
-	&mmc1_ck,
-	&mmc2_ck,
-	/* Virtual clocks */
-	&virtual_ck_mpu,
-};
-
-struct clk *clk_get(struct device *dev, const char *id)
+struct clk * clk_get(struct device *dev, const char *id)
 {
 	struct clk *p, *clk = ERR_PTR(-ENOENT);
 
@@ -590,6 +53,89 @@
 }
 EXPORT_SYMBOL(clk_get);
 
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (clk->enable)
+		ret = clk->enable(clk);
+	else if (arch_clock->clk_enable)
+		ret = arch_clock->clk_enable(clk);
+	else
+		printk(KERN_ERR "Could not enable clock %s\n", clk->name);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (clk->disable)
+		clk->disable(clk);
+	else if (arch_clock->clk_disable)
+		arch_clock->clk_disable(clk);
+	else
+		printk(KERN_ERR "Could not disable clock %s\n", clk->name);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+int clk_use(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_use)
+		ret = arch_clock->clk_use(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_use);
+
+void clk_unuse(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_unuse)
+		arch_clock->clk_unuse(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_unuse);
+
+int clk_get_usecount(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	ret = clk->usecount;
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get_usecount);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	unsigned long flags;
+	unsigned long ret = 0;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	ret = clk->rate;
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get_rate);
 
 void clk_put(struct clk *clk)
 {
@@ -598,526 +144,109 @@
 }
 EXPORT_SYMBOL(clk_put);
 
-
-int __clk_enable(struct clk *clk)
-{
-	__u16 regval16;
-	__u32 regval32;
-
-	if (clk->flags & ALWAYS_ENABLED)
-		return 0;
-
-	if (unlikely(clk->enable_reg == 0)) {
-		printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
-		       clk->name);
-		return 0;
-	}
-
-	if (clk->flags & DSP_DOMAIN_CLOCK) {
-		__clk_use(&api_ck);
-	}
-
-	if (clk->flags & ENABLE_REG_32BIT) {
-		if (clk->flags & VIRTUAL_IO_ADDRESS) {
-			regval32 = __raw_readl(clk->enable_reg);
-			regval32 |= (1 << clk->enable_bit);
-			__raw_writel(regval32, clk->enable_reg);
-		} else {
-			regval32 = omap_readl(clk->enable_reg);
-			regval32 |= (1 << clk->enable_bit);
-			omap_writel(regval32, clk->enable_reg);
-		}
-	} else {
-		if (clk->flags & VIRTUAL_IO_ADDRESS) {
-			regval16 = __raw_readw(clk->enable_reg);
-			regval16 |= (1 << clk->enable_bit);
-			__raw_writew(regval16, clk->enable_reg);
-		} else {
-			regval16 = omap_readw(clk->enable_reg);
-			regval16 |= (1 << clk->enable_bit);
-			omap_writew(regval16, clk->enable_reg);
-		}
-	}
-
-	if (clk->flags & DSP_DOMAIN_CLOCK) {
-		__clk_unuse(&api_ck);
-	}
-
-	return 0;
-}
-
-
-void __clk_disable(struct clk *clk)
-{
-	__u16 regval16;
-	__u32 regval32;
-
-	if (clk->enable_reg == 0)
-		return;
-
-	if (clk->flags & DSP_DOMAIN_CLOCK) {
-		__clk_use(&api_ck);
-	}
-
-	if (clk->flags & ENABLE_REG_32BIT) {
-		if (clk->flags & VIRTUAL_IO_ADDRESS) {
-			regval32 = __raw_readl(clk->enable_reg);
-			regval32 &= ~(1 << clk->enable_bit);
-			__raw_writel(regval32, clk->enable_reg);
-		} else {
-			regval32 = omap_readl(clk->enable_reg);
-			regval32 &= ~(1 << clk->enable_bit);
-			omap_writel(regval32, clk->enable_reg);
-		}
-	} else {
-		if (clk->flags & VIRTUAL_IO_ADDRESS) {
-			regval16 = __raw_readw(clk->enable_reg);
-			regval16 &= ~(1 << clk->enable_bit);
-			__raw_writew(regval16, clk->enable_reg);
-		} else {
-			regval16 = omap_readw(clk->enable_reg);
-			regval16 &= ~(1 << clk->enable_bit);
-			omap_writew(regval16, clk->enable_reg);
-		}
-	}
-
-	if (clk->flags & DSP_DOMAIN_CLOCK) {
-		__clk_unuse(&api_ck);
-	}
-}
-
-
-void __clk_unuse(struct clk *clk)
-{
-	if (clk->usecount > 0 && !(--clk->usecount)) {
-		__clk_disable(clk);
-		if (likely(clk->parent))
-			__clk_unuse(clk->parent);
-	}
-}
-
-
-int __clk_use(struct clk *clk)
-{
-	int ret = 0;
-	if (clk->usecount++ == 0) {
-		if (likely(clk->parent))
-			ret = __clk_use(clk->parent);
-
-		if (unlikely(ret != 0)) {
-			clk->usecount--;
-			return ret;
-		}
-
-		ret = __clk_enable(clk);
-
-		if (unlikely(ret != 0) && clk->parent) {
-			__clk_unuse(clk->parent);
-			clk->usecount--;
-		}
-	}
-
-	return ret;
-}
-
-
-int clk_enable(struct clk *clk)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&clockfw_lock, flags);
-	ret = __clk_enable(clk);
-	spin_unlock_irqrestore(&clockfw_lock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(clk_enable);
-
-
-void clk_disable(struct clk *clk)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&clockfw_lock, flags);
-	__clk_disable(clk);
-	spin_unlock_irqrestore(&clockfw_lock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-
-int clk_use(struct clk *clk)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&clockfw_lock, flags);
-	ret = __clk_use(clk);
-	spin_unlock_irqrestore(&clockfw_lock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(clk_use);
-
-
-void clk_unuse(struct clk *clk)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&clockfw_lock, flags);
-	__clk_unuse(clk);
-	spin_unlock_irqrestore(&clockfw_lock, flags);
-}
-EXPORT_SYMBOL(clk_unuse);
-
-
-int clk_get_usecount(struct clk *clk)
-{
-        return clk->usecount;
-}
-EXPORT_SYMBOL(clk_get_usecount);
-
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-	return clk->rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-
-static __u16 verify_ckctl_value(__u16 newval)
-{
-	/* This function checks for following limitations set
-	 * by the hardware (all conditions must be true):
-	 * DSPMMU_CK == DSP_CK  or  DSPMMU_CK == DSP_CK/2
-	 * ARM_CK >= TC_CK
-	 * DSP_CK >= TC_CK
-	 * DSPMMU_CK >= TC_CK
-	 *
-	 * In addition following rules are enforced:
-	 * LCD_CK <= TC_CK
-	 * ARMPER_CK <= TC_CK
-	 *
-	 * However, maximum frequencies are not checked for!
-	 */
-	__u8 per_exp;
-	__u8 lcd_exp;
-	__u8 arm_exp;
-	__u8 dsp_exp;
-	__u8 tc_exp;
-	__u8 dspmmu_exp;
-
-	per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3;
-	lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3;
-	arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3;
-	dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3;
-	tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3;
-	dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3;
-
-	if (dspmmu_exp < dsp_exp)
-		dspmmu_exp = dsp_exp;
-	if (dspmmu_exp > dsp_exp+1)
-		dspmmu_exp = dsp_exp+1;
-	if (tc_exp < arm_exp)
-		tc_exp = arm_exp;
-	if (tc_exp < dspmmu_exp)
-		tc_exp = dspmmu_exp;
-	if (tc_exp > lcd_exp)
-		lcd_exp = tc_exp;
-	if (tc_exp > per_exp)
-		per_exp = tc_exp;
-
-	newval &= 0xf000;
-	newval |= per_exp << CKCTL_PERDIV_OFFSET;
-	newval |= lcd_exp << CKCTL_LCDDIV_OFFSET;
-	newval |= arm_exp << CKCTL_ARMDIV_OFFSET;
-	newval |= dsp_exp << CKCTL_DSPDIV_OFFSET;
-	newval |= tc_exp << CKCTL_TCDIV_OFFSET;
-	newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET;
-
-	return newval;
-}
-
-
-static int calc_dsor_exp(struct clk *clk, unsigned long rate)
-{
-	/* Note: If target frequency is too low, this function will return 4,
-	 * which is invalid value. Caller must check for this value and act
-	 * accordingly.
-	 *
-	 * Note: This function does not check for following limitations set
-	 * by the hardware (all conditions must be true):
-	 * DSPMMU_CK == DSP_CK  or  DSPMMU_CK == DSP_CK/2
-	 * ARM_CK >= TC_CK
-	 * DSP_CK >= TC_CK
-	 * DSPMMU_CK >= TC_CK
-	 */
-	unsigned long realrate;
-	struct clk *  parent;
-	unsigned  dsor_exp;
-
-	if (unlikely(!(clk->flags & RATE_CKCTL)))
-		return -EINVAL;
-
-	parent = clk->parent;
-	if (unlikely(parent == 0))
-		return -EIO;
-
-	realrate = parent->rate;
-	for (dsor_exp=0; dsor_exp<4; dsor_exp++) {
-		if (realrate <= rate)
-			break;
-
-		realrate /= 2;
-	}
-
-	return dsor_exp;
-}
-
-
-static void ckctl_recalc(struct clk *  clk)
-{
-	int dsor;
-
-	/* Calculate divisor encoded as 2-bit exponent */
-	if (clk->flags & DSP_DOMAIN_CLOCK) {
-		/* The clock control bits are in DSP domain,
-		 * so api_ck is needed for access.
-		 * Note that DSP_CKCTL virt addr = phys addr, so
-		 * we must use __raw_readw() instead of omap_readw().
-		 */
-		__clk_use(&api_ck);
-		dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
-		__clk_unuse(&api_ck);
-	} else {
-		dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
-	}
-	if (unlikely(clk->rate == clk->parent->rate / dsor))
-		return; /* No change, quick exit */
-	clk->rate = clk->parent->rate / dsor;
-
-	if (unlikely(clk->flags & RATE_PROPAGATES))
-		propagate_rate(clk);
-}
-
+/*-------------------------------------------------------------------------
+ * Optional clock functions defined in asm/hardware/clock.h
+ *-------------------------------------------------------------------------*/
 
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-	int dsor_exp;
+	unsigned long flags;
+	long ret = 0;
 
-	if (clk->flags & RATE_FIXED)
-		return clk->rate;
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_round_rate)
+		ret = arch_clock->clk_round_rate(clk, rate);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
 
-	if (clk->flags & RATE_CKCTL) {
-		dsor_exp = calc_dsor_exp(clk, rate);
-		if (dsor_exp < 0)
-			return dsor_exp;
-		if (dsor_exp > 3)
-			dsor_exp = 3;
-		return clk->parent->rate / (1 << dsor_exp);
-	}
-
-	if(clk->round_rate != 0)
-		return clk->round_rate(clk, rate);
-
-	return clk->rate;
+	return ret;
 }
 EXPORT_SYMBOL(clk_round_rate);
 
-
-static void propagate_rate(struct clk *  clk)
-{
-	struct clk **  clkp;
-
-	for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
-		if (likely((*clkp)->parent != clk)) continue;
-		if (likely((*clkp)->recalc))
-			(*clkp)->recalc(*clkp);
-	}
-}
-
-
-static int select_table_rate(struct clk *  clk, unsigned long rate)
-{
-	/* Find the highest supported frequency <= rate and switch to it */
-	struct mpu_rate *  ptr;
-
-	if (clk != &virtual_ck_mpu)
-		return -EINVAL;
-
-	for (ptr = rate_table; ptr->rate; ptr++) {
-		if (ptr->xtal != ck_ref.rate)
-			continue;
-
-		/* DPLL1 cannot be reprogrammed without risking system crash */
-		if (likely(ck_dpll1.rate!=0) && ptr->pll_rate != ck_dpll1.rate)
-			continue;
-
-		/* Can check only after xtal frequency check */
-		if (ptr->rate <= rate)
-			break;
-	}
-
-	if (!ptr->rate)
-		return -EINVAL;
-
-	/*
-	 * In most cases we should not need to reprogram DPLL.
-	 * Reprogramming the DPLL is tricky, it must be done from SRAM.
-	 */
-	omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
-
-	ck_dpll1.rate = ptr->pll_rate;
-	propagate_rate(&ck_dpll1);
-	return 0;
-}
-
-
-static long round_to_table_rate(struct clk *  clk, unsigned long rate)
-{
-	/* Find the highest supported frequency <= rate */
-	struct mpu_rate *  ptr;
-	long  highest_rate;
-
-	if (clk != &virtual_ck_mpu)
-		return -EINVAL;
-
-	highest_rate = -EINVAL;
-
-	for (ptr = rate_table; ptr->rate; ptr++) {
-		if (ptr->xtal != ck_ref.rate)
-			continue;
-
-		highest_rate = ptr->rate;
-
-		/* Can check only after xtal frequency check */
-		if (ptr->rate <= rate)
-			break;
-	}
-
-	return highest_rate;
-}
-
-
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
-	int  ret = -EINVAL;
-	int  dsor_exp;
-	__u16  regval;
-	unsigned long  flags;
+	unsigned long flags;
+	int ret = 0;
 
-	if (clk->flags & RATE_CKCTL) {
-		dsor_exp = calc_dsor_exp(clk, rate);
-		if (dsor_exp > 3)
-			dsor_exp = -EINVAL;
-		if (dsor_exp < 0)
-			return dsor_exp;
-
-		spin_lock_irqsave(&clockfw_lock, flags);
-		regval = omap_readw(ARM_CKCTL);
-		regval &= ~(3 << clk->rate_offset);
-		regval |= dsor_exp << clk->rate_offset;
-		regval = verify_ckctl_value(regval);
-		omap_writew(regval, ARM_CKCTL);
-		clk->rate = clk->parent->rate / (1 << dsor_exp);
-		spin_unlock_irqrestore(&clockfw_lock, flags);
-		ret = 0;
-	} else if(clk->set_rate != 0) {
-		spin_lock_irqsave(&clockfw_lock, flags);
-		ret = clk->set_rate(clk, rate);
-		spin_unlock_irqrestore(&clockfw_lock, flags);
-	}
-
-	if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
-		propagate_rate(clk);
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_set_rate)
+		ret = arch_clock->clk_set_rate(clk, rate);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
 
 	return ret;
 }
 EXPORT_SYMBOL(clk_set_rate);
 
-
-static unsigned calc_ext_dsor(unsigned long rate)
+int clk_set_parent(struct clk *clk, struct clk *parent)
 {
-	unsigned dsor;
+	unsigned long flags;
+	int ret = 0;
 
-	/* MCLK and BCLK divisor selection is not linear:
-	 * freq = 96MHz / dsor
-	 *
-	 * RATIO_SEL range: dsor <-> RATIO_SEL
-	 * 0..6: (RATIO_SEL+2) <-> (dsor-2)
-	 * 6..48:  (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6)
-	 * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9
-	 * can not be used.
-	 */
-	for (dsor = 2; dsor < 96; ++dsor) {
-		if ((dsor & 1) && dsor > 8)
-		  	continue;
-		if (rate >= 96000000 / dsor)
-			break;
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_set_parent)
+		ret =  arch_clock->clk_set_parent(clk, parent);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	unsigned long flags;
+	struct clk * ret = NULL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_get_parent)
+		ret = arch_clock->clk_get_parent(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+/*-------------------------------------------------------------------------
+ * OMAP specific clock functions shared between omap1 and omap2
+ *-------------------------------------------------------------------------*/
+
+unsigned int __initdata mpurate;
+
+/*
+ * By default we use the rate set by the bootloader.
+ * You can override this with mpurate= cmdline option.
+ */
+static int __init omap_clk_setup(char *str)
+{
+	get_option(&str, &mpurate);
+
+	if (!mpurate)
+		return 1;
+
+	if (mpurate < 1000)
+		mpurate *= 1000000;
+
+	return 1;
+}
+__setup("mpurate=", omap_clk_setup);
+
+/* Used for clocks that always have same value as the parent clock */
+void followparent_recalc(struct clk *clk)
+{
+	clk->rate = clk->parent->rate;
+}
+
+/* Propagate rate to children */
+void propagate_rate(struct clk * tclk)
+{
+	struct clk *clkp;
+
+	list_for_each_entry(clkp, &clocks, node) {
+		if (likely(clkp->parent != tclk))
+			continue;
+		if (likely((u32)clkp->recalc))
+			clkp->recalc(clkp);
 	}
-	return dsor;
 }
 
-/* Only needed on 1510 */
-static int set_uart_rate(struct clk * clk, unsigned long rate)
-{
-	unsigned int val;
-
-	val = omap_readl(clk->enable_reg);
-	if (rate == 12000000)
-		val &= ~(1 << clk->enable_bit);
-	else if (rate == 48000000)
-		val |= (1 << clk->enable_bit);
-	else
-		return -EINVAL;
-	omap_writel(val, clk->enable_reg);
-	clk->rate = rate;
-
-	return 0;
-}
-
-static int set_ext_clk_rate(struct clk *  clk, unsigned long rate)
-{
-	unsigned dsor;
-	__u16 ratio_bits;
-
-	dsor = calc_ext_dsor(rate);
-	clk->rate = 96000000 / dsor;
-	if (dsor > 8)
-		ratio_bits = ((dsor - 8) / 2 + 6) << 2;
-	else
-		ratio_bits = (dsor - 2) << 2;
-
-	ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd;
-	omap_writew(ratio_bits, clk->enable_reg);
-
-	return 0;
-}
-
-
-static long round_ext_clk_rate(struct clk *  clk, unsigned long rate)
-{
-	return 96000000 / calc_ext_dsor(rate);
-}
-
-
-static void init_ext_clk(struct clk *  clk)
-{
-	unsigned dsor;
-	__u16 ratio_bits;
-
-	/* Determine current rate and ensure clock is based on 96MHz APLL */
-	ratio_bits = omap_readw(clk->enable_reg) & ~1;
-	omap_writew(ratio_bits, clk->enable_reg);
-
-	ratio_bits = (ratio_bits & 0xfc) >> 2;
-	if (ratio_bits > 6)
-		dsor = (ratio_bits - 6) * 2 + 8;
-	else
-		dsor = ratio_bits + 2;
-
-	clk-> rate = 96000000 / dsor;
-}
-
-
 int clk_register(struct clk *clk)
 {
 	down(&clocks_sem);
@@ -1125,6 +254,7 @@
 	if (clk->init)
 		clk->init(clk);
 	up(&clocks_sem);
+
 	return 0;
 }
 EXPORT_SYMBOL(clk_register);
@@ -1137,203 +267,38 @@
 }
 EXPORT_SYMBOL(clk_unregister);
 
-#ifdef CONFIG_OMAP_RESET_CLOCKS
-/*
- * Resets some clocks that may be left on from bootloader,
- * but leaves serial clocks on. See also omap_late_clk_reset().
- */
-static inline void omap_early_clk_reset(void)
+void clk_deny_idle(struct clk *clk)
 {
-	//omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_deny_idle)
+		arch_clock->clk_deny_idle(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
 }
-#else
-#define omap_early_clk_reset()	{}
-#endif
+EXPORT_SYMBOL(clk_deny_idle);
 
-int __init clk_init(void)
+void clk_allow_idle(struct clk *clk)
 {
-	struct clk **  clkp;
-	const struct omap_clock_config *info;
-	int crystal_type = 0; /* Default 12 MHz */
+	unsigned long flags;
 
-	omap_early_clk_reset();
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_allow_idle)
+		arch_clock->clk_allow_idle(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_allow_idle);
 
-	for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
-		if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) {
-			clk_register(*clkp);
-			continue;
-		}
+/*-------------------------------------------------------------------------*/
 
-		if (((*clkp)->flags &CLOCK_IN_OMAP16XX) && cpu_is_omap16xx()) {
-			clk_register(*clkp);
-			continue;
-		}
-
-		if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) {
-			clk_register(*clkp);
-			continue;
-		}
+int __init clk_init(struct clk_functions * custom_clocks)
+{
+	if (!custom_clocks) {
+		printk(KERN_ERR "No custom clock functions registered\n");
+		BUG();
 	}
 
-	info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config);
-	if (info != NULL) {
-		if (!cpu_is_omap1510())
-			crystal_type = info->system_clock_type;
-	}
-
-#if defined(CONFIG_ARCH_OMAP730)
-	ck_ref.rate = 13000000;
-#elif defined(CONFIG_ARCH_OMAP16XX)
-	if (crystal_type == 2)
-		ck_ref.rate = 19200000;
-#endif
-
-	printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n",
-	       omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
-	       omap_readw(ARM_CKCTL));
-
-	/* We want to be in syncronous scalable mode */
-	omap_writew(0x1000, ARM_SYSST);
-
-#ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER
-	/* Use values set by bootloader. Determine PLL rate and recalculate
-	 * dependent clocks as if kernel had changed PLL or divisors.
-	 */
-	{
-		unsigned pll_ctl_val = omap_readw(DPLL_CTL);
-
-		ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */
-		if (pll_ctl_val & 0x10) {
-			/* PLL enabled, apply multiplier and divisor */
-			if (pll_ctl_val & 0xf80)
-				ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7;
-			ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1;
-		} else {
-			/* PLL disabled, apply bypass divisor */
-			switch (pll_ctl_val & 0xc) {
-			case 0:
-				break;
-			case 0x4:
-				ck_dpll1.rate /= 2;
-				break;
-			default:
-				ck_dpll1.rate /= 4;
-				break;
-			}
-		}
-	}
-	propagate_rate(&ck_dpll1);
-#else
-	/* Find the highest supported frequency and enable it */
-	if (select_table_rate(&virtual_ck_mpu, ~0)) {
-		printk(KERN_ERR "System frequencies not set. Check your config.\n");
-		/* Guess sane values (60MHz) */
-		omap_writew(0x2290, DPLL_CTL);
-		omap_writew(0x1005, ARM_CKCTL);
-		ck_dpll1.rate = 60000000;
-		propagate_rate(&ck_dpll1);
-	}
-#endif
-	/* Cache rates for clocks connected to ck_ref (not dpll1) */
-	propagate_rate(&ck_ref);
-	printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): "
-		"%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
-	       ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
-	       ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10,
-	       arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10);
-
-#ifdef CONFIG_MACH_OMAP_PERSEUS2
-	/* Select slicer output as OMAP input clock */
-	omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);
-#endif
-
-	/* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
-	omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL);
-
-	/* Put DSP/MPUI into reset until needed */
-	omap_writew(0, ARM_RSTCT1);
-	omap_writew(1, ARM_RSTCT2);
-	omap_writew(0x400, ARM_IDLECT1);
-
-	/*
-	 * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8)
-	 * of the ARM_IDLECT2 register must be set to zero. The power-on
-	 * default value of this bit is one.
-	 */
-	omap_writew(0x0000, ARM_IDLECT2);	/* Turn LCD clock off also */
-
-	/*
-	 * Only enable those clocks we will need, let the drivers
-	 * enable other clocks as necessary
-	 */
-	clk_use(&armper_ck);
-	clk_use(&armxor_ck);
-	clk_use(&armtim_ck);
-
-	if (cpu_is_omap1510())
-		clk_enable(&arm_gpio_ck);
+	arch_clock = custom_clocks;
 
 	return 0;
 }
-
-
-#ifdef CONFIG_OMAP_RESET_CLOCKS
-
-static int __init omap_late_clk_reset(void)
-{
-	/* Turn off all unused clocks */
-	struct clk *p;
-	__u32 regval32;
-
-	/* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
-	regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4);
-	omap_writew(regval32, SOFT_REQ_REG);
-	omap_writew(0, SOFT_REQ_REG2);
-
-	list_for_each_entry(p, &clocks, node) {
-		if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) ||
-			p->enable_reg == 0)
-			continue;
-
-		/* Assume no DSP clocks have been activated by bootloader */
-		if (p->flags & DSP_DOMAIN_CLOCK)
-			continue;
-
-		/* Is the clock already disabled? */
-		if (p->flags & ENABLE_REG_32BIT) {
-			if (p->flags & VIRTUAL_IO_ADDRESS)
-				regval32 = __raw_readl(p->enable_reg);
-			else
-				regval32 = omap_readl(p->enable_reg);
-		} else {
-			if (p->flags & VIRTUAL_IO_ADDRESS)
-				regval32 = __raw_readw(p->enable_reg);
-			else
-				regval32 = omap_readw(p->enable_reg);
-		}
-
-		if ((regval32 & (1 << p->enable_bit)) == 0)
-			continue;
-
-		/* FIXME: This clock seems to be necessary but no-one
-		 * has asked for its activation. */
-		if (p == &tc2_ck         // FIX: pm.c (SRAM), CCP, Camera
-		    || p == &ck_dpll1out // FIX: SoSSI, SSR
-		    || p == &arm_gpio_ck // FIX: GPIO code for 1510
-		    ) {
-			printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
-			       p->name);
-			continue;
-		}
-
-		printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name);
-		__clk_disable(p);
-		printk(" done\n");
-	}
-
-	return 0;
-}
-
-late_initcall(omap_late_clk_reset);
-
-#endif
diff --git a/arch/arm/plat-omap/clock.h b/arch/arm/plat-omap/clock.h
deleted file mode 100644
index a89e1e8..0000000
--- a/arch/arm/plat-omap/clock.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- *  linux/arch/arm/plat-omap/clock.h
- *
- *  Copyright (C) 2004 Nokia corporation
- *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
- *  Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, 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 __ARCH_ARM_OMAP_CLOCK_H
-#define __ARCH_ARM_OMAP_CLOCK_H
-
-struct module;
-
-struct clk {
-	struct list_head	node;
-	struct module		*owner;
-	const char		*name;
-	struct clk		*parent;
-	unsigned long		rate;
-	__s8			usecount;
-	__u16			flags;
-	__u32			enable_reg;
-	__u8			enable_bit;
-	__u8			rate_offset;
-	void			(*recalc)(struct clk *);
-	int			(*set_rate)(struct clk *, unsigned long);
-	long			(*round_rate)(struct clk *, unsigned long);
-	void			(*init)(struct clk *);
-};
-
-
-struct mpu_rate {
-	unsigned long		rate;
-	unsigned long		xtal;
-	unsigned long		pll_rate;
-	__u16			ckctl_val;
-	__u16			dpllctl_val;
-};
-
-
-/* Clock flags */
-#define RATE_CKCTL		1
-#define RATE_FIXED		2
-#define RATE_PROPAGATES		4
-#define VIRTUAL_CLOCK		8
-#define ALWAYS_ENABLED		16
-#define ENABLE_REG_32BIT	32
-#define CLOCK_IN_OMAP16XX	64
-#define CLOCK_IN_OMAP1510	128
-#define CLOCK_IN_OMAP730	256
-#define DSP_DOMAIN_CLOCK	512
-#define VIRTUAL_IO_ADDRESS	1024
-
-/* ARM_CKCTL bit shifts */
-#define CKCTL_PERDIV_OFFSET	0
-#define CKCTL_LCDDIV_OFFSET	2
-#define CKCTL_ARMDIV_OFFSET	4
-#define CKCTL_DSPDIV_OFFSET	6
-#define CKCTL_TCDIV_OFFSET	8
-#define CKCTL_DSPMMUDIV_OFFSET	10
-/*#define ARM_TIMXO		12*/
-#define EN_DSPCK		13
-/*#define ARM_INTHCK_SEL	14*/ /* Divide-by-2 for mpu inth_ck */
-/* DSP_CKCTL bit shifts */
-#define CKCTL_DSPPERDIV_OFFSET	0
-
-/* ARM_IDLECT1 bit shifts */
-/*#define IDLWDT_ARM	0*/
-/*#define IDLXORP_ARM	1*/
-/*#define IDLPER_ARM	2*/
-/*#define IDLLCD_ARM	3*/
-/*#define IDLLB_ARM	4*/
-/*#define IDLHSAB_ARM	5*/
-/*#define IDLIF_ARM	6*/
-/*#define IDLDPLL_ARM	7*/
-/*#define IDLAPI_ARM	8*/
-/*#define IDLTIM_ARM	9*/
-/*#define SETARM_IDLE	11*/
-
-/* ARM_IDLECT2 bit shifts */
-#define EN_WDTCK	0
-#define EN_XORPCK	1
-#define EN_PERCK	2
-#define EN_LCDCK	3
-#define EN_LBCK		4 /* Not on 1610/1710 */
-/*#define EN_HSABCK	5*/
-#define EN_APICK	6
-#define EN_TIMCK	7
-#define DMACK_REQ	8
-#define EN_GPIOCK	9 /* Not on 1610/1710 */
-/*#define EN_LBFREECK	10*/
-#define EN_CKOUT_ARM	11
-
-/* ARM_IDLECT3 bit shifts */
-#define EN_OCPI_CK	0
-#define EN_TC1_CK	2
-#define EN_TC2_CK	4
-
-/* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */
-#define EN_DSPTIMCK	5
-
-/* Various register defines for clock controls scattered around OMAP chip */
-#define USB_MCLK_EN_BIT		4	/* In ULPD_CLKC_CTRL */
-#define USB_HOST_HHC_UHOST_EN	9	/* In MOD_CONF_CTRL_0 */
-#define SWD_ULPD_PLL_CLK_REQ	1	/* In SWD_CLK_DIV_CTRL_SEL */
-#define COM_ULPD_PLL_CLK_REQ	1	/* In COM_CLK_DIV_CTRL_SEL */
-#define SWD_CLK_DIV_CTRL_SEL	0xfffe0874
-#define COM_CLK_DIV_CTRL_SEL	0xfffe0878
-#define SOFT_REQ_REG		0xfffe0834
-#define SOFT_REQ_REG2		0xfffe0880
-
-int clk_register(struct clk *clk);
-void clk_unregister(struct clk *clk);
-int clk_init(void);
-
-#endif
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index 02bcc6c..ccdb4526 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -31,7 +31,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
 
-#include "clock.h"
+#include <asm/arch/clock.h>
 
 #define NO_LENGTH_CHECK 0xffffffff
 
@@ -117,19 +117,43 @@
 
 static int __init omap_add_serial_console(void)
 {
-	const struct omap_serial_console_config *info;
+	const struct omap_serial_console_config *con_info;
+	const struct omap_uart_config *uart_info;
+	static char speed[11], *opt = NULL;
+	int line, i, uart_idx;
 
-	info = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
-			       struct omap_serial_console_config);
-	if (info != NULL && info->console_uart) {
-		static char speed[11], *opt = NULL;
+	uart_info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
+	con_info = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
+					struct omap_serial_console_config);
+	if (uart_info == NULL || con_info == NULL)
+		return 0;
 
-		if (info->console_speed) {
-			snprintf(speed, sizeof(speed), "%u", info->console_speed);
-			opt = speed;
-		}
-		return add_preferred_console("ttyS", info->console_uart - 1, opt);
+	if (con_info->console_uart == 0)
+		return 0;
+
+	if (con_info->console_speed) {
+		snprintf(speed, sizeof(speed), "%u", con_info->console_speed);
+		opt = speed;
 	}
-	return 0;
+
+	uart_idx = con_info->console_uart - 1;
+	if (uart_idx >= OMAP_MAX_NR_PORTS) {
+		printk(KERN_INFO "Console: external UART#%d. "
+			"Not adding it as console this time.\n",
+			uart_idx + 1);
+		return 0;
+	}
+	if (!(uart_info->enabled_uarts & (1 << uart_idx))) {
+		printk(KERN_ERR "Console: Selected UART#%d is "
+			"not enabled for this platform\n",
+			uart_idx + 1);
+		return -1;
+	}
+	line = 0;
+	for (i = 0; i < uart_idx; i++) {
+		if (uart_info->enabled_uarts & (1 << i))
+			line++;
+	}
+	return add_preferred_console("ttyS", line, opt);
 }
 console_initcall(omap_add_serial_console);
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
new file mode 100644
index 0000000..9dcce90
--- /dev/null
+++ b/arch/arm/plat-omap/devices.c
@@ -0,0 +1,381 @@
+/*
+ * linux/arch/arm/plat-omap/devices.c
+ *
+ * Common platform device setup/initialization for OMAP1 and OMAP2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/tc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+
+
+void omap_nop_release(struct device *dev)
+{
+        /* Nothing */
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if 	defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+
+#define	OMAP1_I2C_BASE		0xfffb3800
+#define OMAP2_I2C_BASE1		0x48070000
+#define OMAP_I2C_SIZE		0x3f
+#define OMAP1_I2C_INT		INT_I2C
+#define OMAP2_I2C_INT1		56
+
+static struct resource i2c_resources1[] = {
+	{
+		.start		= 0,
+		.end		= 0,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= 0,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+/* DMA not used; works around erratum writing to non-empty i2c fifo */
+
+static struct platform_device omap_i2c_device1 = {
+        .name           = "i2c_omap",
+        .id             = 1,
+        .dev = {
+                .release        = omap_nop_release,
+        },
+	.num_resources	= ARRAY_SIZE(i2c_resources1),
+	.resource	= i2c_resources1,
+};
+
+/* See also arch/arm/mach-omap2/devices.c for second I2C on 24xx */
+static void omap_init_i2c(void)
+{
+	if (cpu_is_omap24xx()) {
+		i2c_resources1[0].start = OMAP2_I2C_BASE1;
+		i2c_resources1[0].end = OMAP2_I2C_BASE1 + OMAP_I2C_SIZE;
+		i2c_resources1[1].start = OMAP2_I2C_INT1;
+	} else {
+		i2c_resources1[0].start = OMAP1_I2C_BASE;
+		i2c_resources1[0].end = OMAP1_I2C_BASE + OMAP_I2C_SIZE;
+		i2c_resources1[1].start = OMAP1_I2C_INT;
+	}
+
+	/* FIXME define and use a boot tag, in case of boards that
+	 * either don't wire up I2C, or chips that mux it differently...
+	 * it can include clocking and address info, maybe more.
+	 */
+	if (cpu_is_omap24xx()) {
+		omap_cfg_reg(M19_24XX_I2C1_SCL);
+		omap_cfg_reg(L15_24XX_I2C1_SDA);
+	} else {
+		omap_cfg_reg(I2C_SCL);
+		omap_cfg_reg(I2C_SDA);
+	}
+
+	(void) platform_device_register(&omap_i2c_device1);
+}
+
+#else
+static inline void omap_init_i2c(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define	OMAP_MMC1_BASE		0x4809c000
+#define OMAP_MMC1_INT		83
+#else
+#define	OMAP_MMC1_BASE		0xfffb7800
+#define OMAP_MMC1_INT		INT_MMC
+#endif
+#define	OMAP_MMC2_BASE		0xfffb7c00	/* omap16xx only */
+
+static struct omap_mmc_conf mmc1_conf;
+
+static u64 mmc1_dmamask = 0xffffffff;
+
+static struct resource mmc1_resources[] = {
+	{
+		.start		= IO_ADDRESS(OMAP_MMC1_BASE),
+		.end		= IO_ADDRESS(OMAP_MMC1_BASE) + 0x7f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= OMAP_MMC1_INT,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mmc_omap_device1 = {
+	.name		= "mmci-omap",
+	.id		= 1,
+	.dev = {
+		.release	= omap_nop_release,
+		.dma_mask	= &mmc1_dmamask,
+		.platform_data	= &mmc1_conf,
+	},
+	.num_resources	= ARRAY_SIZE(mmc1_resources),
+	.resource	= mmc1_resources,
+};
+
+#ifdef	CONFIG_ARCH_OMAP16XX
+
+static struct omap_mmc_conf mmc2_conf;
+
+static u64 mmc2_dmamask = 0xffffffff;
+
+static struct resource mmc2_resources[] = {
+	{
+		.start		= IO_ADDRESS(OMAP_MMC2_BASE),
+		.end		= IO_ADDRESS(OMAP_MMC2_BASE) + 0x7f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_1610_MMC2,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mmc_omap_device2 = {
+	.name		= "mmci-omap",
+	.id		= 2,
+	.dev = {
+		.release	= omap_nop_release,
+		.dma_mask	= &mmc2_dmamask,
+		.platform_data	= &mmc2_conf,
+	},
+	.num_resources	= ARRAY_SIZE(mmc2_resources),
+	.resource	= mmc2_resources,
+};
+#endif
+
+static void __init omap_init_mmc(void)
+{
+	const struct omap_mmc_config	*mmc_conf;
+	const struct omap_mmc_conf	*mmc;
+
+	/* NOTE:  assumes MMC was never (wrongly) enabled */
+	mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config);
+	if (!mmc_conf)
+		return;
+
+	/* block 1 is always available and has just one pinout option */
+	mmc = &mmc_conf->mmc[0];
+	if (mmc->enabled) {
+		if (!cpu_is_omap24xx()) {
+			omap_cfg_reg(MMC_CMD);
+			omap_cfg_reg(MMC_CLK);
+			omap_cfg_reg(MMC_DAT0);
+			if (cpu_is_omap1710()) {
+				omap_cfg_reg(M15_1710_MMC_CLKI);
+				omap_cfg_reg(P19_1710_MMC_CMDDIR);
+				omap_cfg_reg(P20_1710_MMC_DATDIR0);
+			}
+		}
+		if (mmc->wire4) {
+			if (!cpu_is_omap24xx()) {
+				omap_cfg_reg(MMC_DAT1);
+				/* NOTE:  DAT2 can be on W10 (here) or M15 */
+				if (!mmc->nomux)
+					omap_cfg_reg(MMC_DAT2);
+				omap_cfg_reg(MMC_DAT3);
+			}
+		}
+		mmc1_conf = *mmc;
+		(void) platform_device_register(&mmc_omap_device1);
+	}
+
+#ifdef	CONFIG_ARCH_OMAP16XX
+	/* block 2 is on newer chips, and has many pinout options */
+	mmc = &mmc_conf->mmc[1];
+	if (mmc->enabled) {
+		if (!mmc->nomux) {
+			omap_cfg_reg(Y8_1610_MMC2_CMD);
+			omap_cfg_reg(Y10_1610_MMC2_CLK);
+			omap_cfg_reg(R18_1610_MMC2_CLKIN);
+			omap_cfg_reg(W8_1610_MMC2_DAT0);
+			if (mmc->wire4) {
+				omap_cfg_reg(V8_1610_MMC2_DAT1);
+				omap_cfg_reg(W15_1610_MMC2_DAT2);
+				omap_cfg_reg(R10_1610_MMC2_DAT3);
+			}
+
+			/* These are needed for the level shifter */
+			omap_cfg_reg(V9_1610_MMC2_CMDDIR);
+			omap_cfg_reg(V5_1610_MMC2_DATDIR0);
+			omap_cfg_reg(W19_1610_MMC2_DATDIR1);
+		}
+
+		/* Feedback clock must be set on OMAP-1710 MMC2 */
+		if (cpu_is_omap1710())
+			omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
+				     MOD_CONF_CTRL_1);
+		mmc2_conf = *mmc;
+		(void) platform_device_register(&mmc_omap_device2);
+	}
+#endif
+	return;
+}
+#else
+static inline void omap_init_mmc(void) {}
+#endif
+
+#if	defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define	OMAP_WDT_BASE		0x48022000
+#else
+#define	OMAP_WDT_BASE		0xfffeb000
+#endif
+
+static struct resource wdt_resources[] = {
+	{
+		.start		= OMAP_WDT_BASE,
+		.end		= OMAP_WDT_BASE + 0x4f,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device omap_wdt_device = {
+	.name	   = "omap_wdt",
+	.id	     = -1,
+	.dev = {
+		.release	= omap_nop_release,
+	},
+	.num_resources	= ARRAY_SIZE(wdt_resources),
+	.resource	= wdt_resources,
+};
+
+static void omap_init_wdt(void)
+{
+	(void) platform_device_register(&omap_wdt_device);
+}
+#else
+static inline void omap_init_wdt(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_OMAP_RNG) || defined(CONFIG_OMAP_RNG_MODULE)
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define	OMAP_RNG_BASE		0x480A0000
+#else
+#define	OMAP_RNG_BASE		0xfffe5000
+#endif
+
+static struct resource rng_resources[] = {
+	{
+		.start		= OMAP_RNG_BASE,
+		.end		= OMAP_RNG_BASE + 0x4f,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device omap_rng_device = {
+	.name	   = "omap_rng",
+	.id	     = -1,
+	.dev = {
+		.release	= omap_nop_release,
+	},
+	.num_resources	= ARRAY_SIZE(rng_resources),
+	.resource	= rng_resources,
+};
+
+static void omap_init_rng(void)
+{
+	(void) platform_device_register(&omap_rng_device);
+}
+#else
+static inline void omap_init_rng(void) {}
+#endif
+
+#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
+
+static struct omap_lcd_config omap_fb_conf;
+
+static u64 omap_fb_dma_mask = ~(u32)0;
+
+static struct platform_device omap_fb_device = {
+	.name		= "omapfb",
+	.id		= -1,
+	.dev = {
+		.release		= omap_nop_release,
+		.dma_mask		= &omap_fb_dma_mask,
+		.coherent_dma_mask	= ~(u32)0,
+		.platform_data		= &omap_fb_conf,
+	},
+	.num_resources = 0,
+};
+
+static inline void omap_init_fb(void)
+{
+	const struct omap_lcd_config *conf;
+
+	conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+	if (conf != NULL)
+		omap_fb_conf = *conf;
+	platform_device_register(&omap_fb_device);
+}
+
+#else
+
+static inline void omap_init_fb(void) {}
+
+#endif
+
+/*
+ * This gets called after board-specific INIT_MACHINE, and initializes most
+ * on-chip peripherals accessible on this board (except for few like USB):
+ *
+ *  (a) Does any "standard config" pin muxing needed.  Board-specific
+ *	code will have muxed GPIO pins and done "nonstandard" setup;
+ *	that code could live in the boot loader.
+ *  (b) Populating board-specific platform_data with the data drivers
+ *	rely on to handle wiring variations.
+ *  (c) Creating platform devices as meaningful on this board and
+ *	with this kernel configuration.
+ *
+ * Claiming GPIOs, and setting their direction and initial values, is the
+ * responsibility of the device drivers.  So is responding to probe().
+ *
+ * Board-specific knowlege like creating devices or pin setup is to be
+ * kept out of drivers as much as possible.  In particular, pin setup
+ * may be handled by the boot loader, and drivers should expect it will
+ * normally have been done by the time they're probed.
+ */
+static int __init omap_init_devices(void)
+{
+	/* please keep these calls, and their implementations above,
+	 * in alphabetical order so they're easier to sort through.
+	 */
+	omap_init_fb();
+	omap_init_i2c();
+	omap_init_mmc();
+	omap_init_wdt();
+	omap_init_rng();
+
+	return 0;
+}
+arch_initcall(omap_init_devices);
+
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index da7b651..f5cc21a 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -6,6 +6,8 @@
  * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>
  * Graphics DMA and LCD DMA graphics tranformations
  * by Imre Deak <imre.deak@nokia.com>
+ * OMAP2 support Copyright (C) 2004-2005 Texas Instruments, Inc.
+ * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com>
  * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
  *
  * Support functions for the OMAP internal DMA channels.
@@ -31,8 +33,15 @@
 
 #include <asm/arch/tc.h>
 
-#define OMAP_DMA_ACTIVE		0x01
+#define DEBUG_PRINTS
+#undef DEBUG_PRINTS
+#ifdef DEBUG_PRINTS
+#define debug_printk(x) printk x
+#else
+#define	debug_printk(x)
+#endif
 
+#define OMAP_DMA_ACTIVE		0x01
 #define OMAP_DMA_CCR_EN		(1 << 7)
 
 #define OMAP_FUNC_MUX_ARM_BASE	(0xfffe1000 + 0xec)
@@ -55,7 +64,7 @@
 static spinlock_t dma_chan_lock;
 static struct omap_dma_lch dma_chan[OMAP_LOGICAL_DMA_CH_COUNT];
 
-const static u8 dma_irq[OMAP_LOGICAL_DMA_CH_COUNT] = {
+const static u8 omap1_dma_irq[OMAP_LOGICAL_DMA_CH_COUNT] = {
 	INT_DMA_CH0_6, INT_DMA_CH1_7, INT_DMA_CH2_8, INT_DMA_CH3,
 	INT_DMA_CH4, INT_DMA_CH5, INT_1610_DMA_CH6, INT_1610_DMA_CH7,
 	INT_1610_DMA_CH8, INT_1610_DMA_CH9, INT_1610_DMA_CH10,
@@ -63,6 +72,20 @@
 	INT_1610_DMA_CH14, INT_1610_DMA_CH15, INT_DMA_LCD
 };
 
+#define REVISIT_24XX()		printk(KERN_ERR "FIXME: no %s on 24xx\n", \
+						__FUNCTION__);
+
+#ifdef CONFIG_ARCH_OMAP15XX
+/* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */
+int omap_dma_in_1510_mode(void)
+{
+	return enable_1510_mode;
+}
+#else
+#define omap_dma_in_1510_mode()		0
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1
 static inline int get_gdma_dev(int req)
 {
 	u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4;
@@ -82,6 +105,9 @@
 	l |= (dev - 1) << shift;
 	omap_writel(l, reg);
 }
+#else
+#define set_gdma_dev(req, dev)	do {} while (0)
+#endif
 
 static void clear_lch_regs(int lch)
 {
@@ -121,38 +147,62 @@
 }
 
 void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
-				  int frame_count, int sync_mode)
+				  int frame_count, int sync_mode,
+				  int dma_trigger, int src_or_dst_synch)
 {
-	u16 w;
+	OMAP_DMA_CSDP_REG(lch) &= ~0x03;
+	OMAP_DMA_CSDP_REG(lch) |= data_type;
 
-	w = omap_readw(OMAP_DMA_CSDP(lch));
-	w &= ~0x03;
-	w |= data_type;
-	omap_writew(w, OMAP_DMA_CSDP(lch));
+	if (cpu_class_is_omap1()) {
+		OMAP_DMA_CCR_REG(lch) &= ~(1 << 5);
+		if (sync_mode == OMAP_DMA_SYNC_FRAME)
+			OMAP_DMA_CCR_REG(lch) |= 1 << 5;
 
-	w = omap_readw(OMAP_DMA_CCR(lch));
-	w &= ~(1 << 5);
-	if (sync_mode == OMAP_DMA_SYNC_FRAME)
-		w |= 1 << 5;
-	omap_writew(w, OMAP_DMA_CCR(lch));
+		OMAP1_DMA_CCR2_REG(lch) &= ~(1 << 2);
+		if (sync_mode == OMAP_DMA_SYNC_BLOCK)
+			OMAP1_DMA_CCR2_REG(lch) |= 1 << 2;
+	}
 
-	w = omap_readw(OMAP_DMA_CCR2(lch));
-	w &= ~(1 << 2);
-	if (sync_mode == OMAP_DMA_SYNC_BLOCK)
-		w |= 1 << 2;
-	omap_writew(w, OMAP_DMA_CCR2(lch));
+	if (cpu_is_omap24xx() && dma_trigger) {
+		u32 val = OMAP_DMA_CCR_REG(lch);
 
-	omap_writew(elem_count, OMAP_DMA_CEN(lch));
-	omap_writew(frame_count, OMAP_DMA_CFN(lch));
+		if (dma_trigger > 63)
+			val |= 1 << 20;
+		if (dma_trigger > 31)
+			val |= 1 << 19;
 
+		val |= (dma_trigger & 0x1f);
+
+		if (sync_mode & OMAP_DMA_SYNC_FRAME)
+			val |= 1 << 5;
+
+		if (sync_mode & OMAP_DMA_SYNC_BLOCK)
+			val |= 1 << 18;
+
+		if (src_or_dst_synch)
+			val |= 1 << 24;		/* source synch */
+		else
+			val &= ~(1 << 24);	/* dest synch */
+
+		OMAP_DMA_CCR_REG(lch) = val;
+	}
+
+	OMAP_DMA_CEN_REG(lch) = elem_count;
+	OMAP_DMA_CFN_REG(lch) = frame_count;
 }
+
 void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
 {
 	u16 w;
 
 	BUG_ON(omap_dma_in_1510_mode());
 
-	w = omap_readw(OMAP_DMA_CCR2(lch)) & ~0x03;
+	if (cpu_is_omap24xx()) {
+		REVISIT_24XX();
+		return;
+	}
+
+	w = OMAP1_DMA_CCR2_REG(lch) & ~0x03;
 	switch (mode) {
 	case OMAP_DMA_CONSTANT_FILL:
 		w |= 0x01;
@@ -165,63 +215,84 @@
 	default:
 		BUG();
 	}
-	omap_writew(w, OMAP_DMA_CCR2(lch));
+	OMAP1_DMA_CCR2_REG(lch) = w;
 
-	w = omap_readw(OMAP_DMA_LCH_CTRL(lch)) & ~0x0f;
+	w = OMAP1_DMA_LCH_CTRL_REG(lch) & ~0x0f;
 	/* Default is channel type 2D */
 	if (mode) {
-		omap_writew((u16)color, OMAP_DMA_COLOR_L(lch));
-		omap_writew((u16)(color >> 16), OMAP_DMA_COLOR_U(lch));
+		OMAP1_DMA_COLOR_L_REG(lch) = (u16)color;
+		OMAP1_DMA_COLOR_U_REG(lch) = (u16)(color >> 16);
 		w |= 1;		/* Channel type G */
 	}
-	omap_writew(w, OMAP_DMA_LCH_CTRL(lch));
+	OMAP1_DMA_LCH_CTRL_REG(lch) = w;
 }
 
-
+/* Note that src_port is only for omap1 */
 void omap_set_dma_src_params(int lch, int src_port, int src_amode,
-			     unsigned long src_start)
+			     unsigned long src_start,
+			     int src_ei, int src_fi)
 {
-	u16 w;
+	if (cpu_class_is_omap1()) {
+		OMAP_DMA_CSDP_REG(lch) &= ~(0x1f << 2);
+		OMAP_DMA_CSDP_REG(lch) |= src_port << 2;
+	}
 
-	w = omap_readw(OMAP_DMA_CSDP(lch));
-	w &= ~(0x1f << 2);
-	w |= src_port << 2;
-	omap_writew(w, OMAP_DMA_CSDP(lch));
+	OMAP_DMA_CCR_REG(lch) &= ~(0x03 << 12);
+	OMAP_DMA_CCR_REG(lch) |= src_amode << 12;
 
-	w = omap_readw(OMAP_DMA_CCR(lch));
-	w &= ~(0x03 << 12);
-	w |= src_amode << 12;
-	omap_writew(w, OMAP_DMA_CCR(lch));
+	if (cpu_class_is_omap1()) {
+		OMAP1_DMA_CSSA_U_REG(lch) = src_start >> 16;
+		OMAP1_DMA_CSSA_L_REG(lch) = src_start;
+	}
 
-	omap_writew(src_start >> 16, OMAP_DMA_CSSA_U(lch));
-	omap_writew(src_start, OMAP_DMA_CSSA_L(lch));
+	if (cpu_is_omap24xx())
+		OMAP2_DMA_CSSA_REG(lch) = src_start;
+
+	OMAP_DMA_CSEI_REG(lch) = src_ei;
+	OMAP_DMA_CSFI_REG(lch) = src_fi;
+}
+
+void omap_set_dma_params(int lch, struct omap_dma_channel_params * params)
+{
+	omap_set_dma_transfer_params(lch, params->data_type,
+				     params->elem_count, params->frame_count,
+				     params->sync_mode, params->trigger,
+				     params->src_or_dst_synch);
+	omap_set_dma_src_params(lch, params->src_port,
+				params->src_amode, params->src_start,
+				params->src_ei, params->src_fi);
+
+	omap_set_dma_dest_params(lch, params->dst_port,
+				 params->dst_amode, params->dst_start,
+				 params->dst_ei, params->dst_fi);
 }
 
 void omap_set_dma_src_index(int lch, int eidx, int fidx)
 {
-	omap_writew(eidx, OMAP_DMA_CSEI(lch));
-	omap_writew(fidx, OMAP_DMA_CSFI(lch));
+	if (cpu_is_omap24xx()) {
+		REVISIT_24XX();
+		return;
+	}
+	OMAP_DMA_CSEI_REG(lch) = eidx;
+	OMAP_DMA_CSFI_REG(lch) = fidx;
 }
 
 void omap_set_dma_src_data_pack(int lch, int enable)
 {
-	u16 w;
-
-	w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 6);
-	w |= enable ? (1 << 6) : 0;
-	omap_writew(w, OMAP_DMA_CSDP(lch));
+	OMAP_DMA_CSDP_REG(lch) &= ~(1 << 6);
+	if (enable)
+		OMAP_DMA_CSDP_REG(lch) |= (1 << 6);
 }
 
 void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 {
-	u16 w;
+	OMAP_DMA_CSDP_REG(lch) &= ~(0x03 << 7);
 
-	w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 7);
 	switch (burst_mode) {
 	case OMAP_DMA_DATA_BURST_DIS:
 		break;
 	case OMAP_DMA_DATA_BURST_4:
-		w |= (0x01 << 7);
+		OMAP_DMA_CSDP_REG(lch) |= (0x02 << 7);
 		break;
 	case OMAP_DMA_DATA_BURST_8:
 		/* not supported by current hardware
@@ -231,175 +302,87 @@
 	default:
 		BUG();
 	}
-	omap_writew(w, OMAP_DMA_CSDP(lch));
 }
 
+/* Note that dest_port is only for OMAP1 */
 void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
-			      unsigned long dest_start)
+			      unsigned long dest_start,
+			      int dst_ei, int dst_fi)
 {
-	u16 w;
+	if (cpu_class_is_omap1()) {
+		OMAP_DMA_CSDP_REG(lch) &= ~(0x1f << 9);
+		OMAP_DMA_CSDP_REG(lch) |= dest_port << 9;
+	}
 
-	w = omap_readw(OMAP_DMA_CSDP(lch));
-	w &= ~(0x1f << 9);
-	w |= dest_port << 9;
-	omap_writew(w, OMAP_DMA_CSDP(lch));
+	OMAP_DMA_CCR_REG(lch) &= ~(0x03 << 14);
+	OMAP_DMA_CCR_REG(lch) |= dest_amode << 14;
 
-	w = omap_readw(OMAP_DMA_CCR(lch));
-	w &= ~(0x03 << 14);
-	w |= dest_amode << 14;
-	omap_writew(w, OMAP_DMA_CCR(lch));
+	if (cpu_class_is_omap1()) {
+		OMAP1_DMA_CDSA_U_REG(lch) = dest_start >> 16;
+		OMAP1_DMA_CDSA_L_REG(lch) = dest_start;
+	}
 
-	omap_writew(dest_start >> 16, OMAP_DMA_CDSA_U(lch));
-	omap_writew(dest_start, OMAP_DMA_CDSA_L(lch));
+	if (cpu_is_omap24xx())
+		OMAP2_DMA_CDSA_REG(lch) = dest_start;
+
+	OMAP_DMA_CDEI_REG(lch) = dst_ei;
+	OMAP_DMA_CDFI_REG(lch) = dst_fi;
 }
 
 void omap_set_dma_dest_index(int lch, int eidx, int fidx)
 {
-	omap_writew(eidx, OMAP_DMA_CDEI(lch));
-	omap_writew(fidx, OMAP_DMA_CDFI(lch));
+	if (cpu_is_omap24xx()) {
+		REVISIT_24XX();
+		return;
+	}
+	OMAP_DMA_CDEI_REG(lch) = eidx;
+	OMAP_DMA_CDFI_REG(lch) = fidx;
 }
 
 void omap_set_dma_dest_data_pack(int lch, int enable)
 {
-	u16 w;
-
-	w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 13);
-	w |= enable ? (1 << 13) : 0;
-	omap_writew(w, OMAP_DMA_CSDP(lch));
+	OMAP_DMA_CSDP_REG(lch) &= ~(1 << 13);
+	if (enable)
+		OMAP_DMA_CSDP_REG(lch) |= 1 << 13;
 }
 
 void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 {
-	u16 w;
+	OMAP_DMA_CSDP_REG(lch) &= ~(0x03 << 14);
 
-	w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 14);
 	switch (burst_mode) {
 	case OMAP_DMA_DATA_BURST_DIS:
 		break;
 	case OMAP_DMA_DATA_BURST_4:
-		w |= (0x01 << 14);
+		OMAP_DMA_CSDP_REG(lch) |= (0x02 << 14);
 		break;
 	case OMAP_DMA_DATA_BURST_8:
-		w |= (0x03 << 14);
+		OMAP_DMA_CSDP_REG(lch) |= (0x03 << 14);
 		break;
 	default:
 		printk(KERN_ERR "Invalid DMA burst mode\n");
 		BUG();
 		return;
 	}
-	omap_writew(w, OMAP_DMA_CSDP(lch));
 }
 
-static inline void init_intr(int lch)
+static inline void omap_enable_channel_irq(int lch)
 {
-	u16 w;
+	u32 status;
 
 	/* Read CSR to make sure it's cleared. */
-	w = omap_readw(OMAP_DMA_CSR(lch));
+	status = OMAP_DMA_CSR_REG(lch);
+
 	/* Enable some nice interrupts. */
-	omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch));
+	OMAP_DMA_CICR_REG(lch) = dma_chan[lch].enabled_irqs;
+
 	dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
 }
 
-static inline void enable_lnk(int lch)
+static void omap_disable_channel_irq(int lch)
 {
-	u16 w;
-
-	/* Clear the STOP_LNK bits */
-	w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
-	w &= ~(1 << 14);
-	omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
-
-	/* And set the ENABLE_LNK bits */
-	if (dma_chan[lch].next_lch != -1)
-		omap_writew(dma_chan[lch].next_lch | (1 << 15),
-			    OMAP_DMA_CLNK_CTRL(lch));
-}
-
-static inline void disable_lnk(int lch)
-{
-	u16 w;
-
-	/* Disable interrupts */
-	omap_writew(0, OMAP_DMA_CICR(lch));
-
-	/* Set the STOP_LNK bit */
-	w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
-	w |= (1 << 14);
-	w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
-
-	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
-}
-
-void omap_start_dma(int lch)
-{
-	u16 w;
-
-	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
-		int next_lch, cur_lch;
-		char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
-
-		dma_chan_link_map[lch] = 1;
-		/* Set the link register of the first channel */
-		enable_lnk(lch);
-
-		memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
-		cur_lch = dma_chan[lch].next_lch;
-		do {
-			next_lch = dma_chan[cur_lch].next_lch;
-
-                        /* The loop case: we've been here already */
-			if (dma_chan_link_map[cur_lch])
-				break;
-			/* Mark the current channel */
-			dma_chan_link_map[cur_lch] = 1;
-
-			enable_lnk(cur_lch);
-			init_intr(cur_lch);
-
-			cur_lch = next_lch;
-		} while (next_lch != -1);
-	}
-
-	init_intr(lch);
-
-	w = omap_readw(OMAP_DMA_CCR(lch));
-	w |= OMAP_DMA_CCR_EN;
-	omap_writew(w, OMAP_DMA_CCR(lch));
-	dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
-}
-
-void omap_stop_dma(int lch)
-{
-	u16 w;
-
-	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
-		int next_lch, cur_lch = lch;
-		char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
-
-		memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
-		do {
-			/* The loop case: we've been here already */
-			if (dma_chan_link_map[cur_lch])
-				break;
-			/* Mark the current channel */
-			dma_chan_link_map[cur_lch] = 1;
-
-			disable_lnk(cur_lch);
-
-			next_lch = dma_chan[cur_lch].next_lch;
-			cur_lch = next_lch;
-		} while (next_lch != -1);
-
-		return;
-	}
-	/* Disable all interrupts on the channel */
-	omap_writew(0, OMAP_DMA_CICR(lch));
-
-	w = omap_readw(OMAP_DMA_CCR(lch));
-	w &= ~OMAP_DMA_CCR_EN;
-	omap_writew(w, OMAP_DMA_CCR(lch));
-	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+	if (cpu_is_omap24xx())
+		OMAP_DMA_CICR_REG(lch) = 0;
 }
 
 void omap_enable_dma_irq(int lch, u16 bits)
@@ -412,55 +395,45 @@
 	dma_chan[lch].enabled_irqs &= ~bits;
 }
 
-static int dma_handle_ch(int ch)
+static inline void enable_lnk(int lch)
 {
-	u16 csr;
+	if (cpu_class_is_omap1())
+		OMAP_DMA_CLNK_CTRL_REG(lch) &= ~(1 << 14);
 
-	if (enable_1510_mode && ch >= 6) {
-		csr = dma_chan[ch].saved_csr;
-		dma_chan[ch].saved_csr = 0;
-	} else
-		csr = omap_readw(OMAP_DMA_CSR(ch));
-	if (enable_1510_mode && ch <= 2 && (csr >> 7) != 0) {
-		dma_chan[ch + 6].saved_csr = csr >> 7;
-		csr &= 0x7f;
-	}
-	if ((csr & 0x3f) == 0)
-		return 0;
-	if (unlikely(dma_chan[ch].dev_id == -1)) {
-		printk(KERN_WARNING "Spurious interrupt from DMA channel %d (CSR %04x)\n",
-		       ch, csr);
-		return 0;
-	}
-	if (unlikely(csr & OMAP_DMA_TOUT_IRQ))
-		printk(KERN_WARNING "DMA timeout with device %d\n", dma_chan[ch].dev_id);
-	if (unlikely(csr & OMAP_DMA_DROP_IRQ))
-		printk(KERN_WARNING "DMA synchronization event drop occurred with device %d\n",
-		       dma_chan[ch].dev_id);
-	if (likely(csr & OMAP_DMA_BLOCK_IRQ))
-		dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE;
-	if (likely(dma_chan[ch].callback != NULL))
-		dma_chan[ch].callback(ch, csr, dma_chan[ch].data);
-	return 1;
+	/* Set the ENABLE_LNK bits */
+	if (dma_chan[lch].next_lch != -1)
+		OMAP_DMA_CLNK_CTRL_REG(lch) =
+			dma_chan[lch].next_lch | (1 << 15);
 }
 
-static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static inline void disable_lnk(int lch)
 {
-	int ch = ((int) dev_id) - 1;
-	int handled = 0;
-
-	for (;;) {
-		int handled_now = 0;
-
-		handled_now += dma_handle_ch(ch);
-		if (enable_1510_mode && dma_chan[ch + 6].saved_csr)
-			handled_now += dma_handle_ch(ch + 6);
-		if (!handled_now)
-			break;
-		handled += handled_now;
+	/* Disable interrupts */
+	if (cpu_class_is_omap1()) {
+		OMAP_DMA_CICR_REG(lch) = 0;
+		/* Set the STOP_LNK bit */
+		OMAP_DMA_CLNK_CTRL_REG(lch) |= 1 << 14;
 	}
 
-	return handled ? IRQ_HANDLED : IRQ_NONE;
+	if (cpu_is_omap24xx()) {
+		omap_disable_channel_irq(lch);
+		/* Clear the ENABLE_LNK bit */
+		OMAP_DMA_CLNK_CTRL_REG(lch) &= ~(1 << 15);
+	}
+
+	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+}
+
+static inline void omap2_enable_irq_lch(int lch)
+{
+	u32 val;
+
+	if (!cpu_is_omap24xx())
+		return;
+
+	val = omap_readl(OMAP_DMA4_IRQENABLE_L0);
+	val |= 1 << lch;
+	omap_writel(val, OMAP_DMA4_IRQENABLE_L0);
 }
 
 int omap_request_dma(int dev_id, const char *dev_name,
@@ -485,14 +458,23 @@
 	}
 	chan = dma_chan + free_ch;
 	chan->dev_id = dev_id;
-	clear_lch_regs(free_ch);
+
+	if (cpu_class_is_omap1())
+		clear_lch_regs(free_ch);
+
+	if (cpu_is_omap24xx())
+		omap_clear_dma(free_ch);
+
 	spin_unlock_irqrestore(&dma_chan_lock, flags);
 
-	chan->dev_id = dev_id;
 	chan->dev_name = dev_name;
 	chan->callback = callback;
 	chan->data = data;
-	chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ;
+	chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ |
+				OMAP_DMA_BLOCK_IRQ;
+
+	if (cpu_is_omap24xx())
+		chan->enabled_irqs |= OMAP2_DMA_TRANS_ERR_IRQ;
 
 	if (cpu_is_omap16xx()) {
 		/* If the sync device is set, configure it dynamically. */
@@ -502,37 +484,242 @@
 		}
 		/* Disable the 1510 compatibility mode and set the sync device
 		 * id. */
-		omap_writew(dev_id | (1 << 10), OMAP_DMA_CCR(free_ch));
-	} else {
-		omap_writew(dev_id, OMAP_DMA_CCR(free_ch));
+		OMAP_DMA_CCR_REG(free_ch) = dev_id | (1 << 10);
+	} else if (cpu_is_omap730() || cpu_is_omap15xx()) {
+		OMAP_DMA_CCR_REG(free_ch) = dev_id;
 	}
+
+	if (cpu_is_omap24xx()) {
+		omap2_enable_irq_lch(free_ch);
+
+		omap_enable_channel_irq(free_ch);
+		/* Clear the CSR register and IRQ status register */
+		OMAP_DMA_CSR_REG(free_ch) = 0x0;
+		omap_writel(~0x0, OMAP_DMA4_IRQSTATUS_L0);
+	}
+
 	*dma_ch_out = free_ch;
 
 	return 0;
 }
 
-void omap_free_dma(int ch)
+void omap_free_dma(int lch)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&dma_chan_lock, flags);
-	if (dma_chan[ch].dev_id == -1) {
-		printk("omap_dma: trying to free nonallocated DMA channel %d\n", ch);
+	if (dma_chan[lch].dev_id == -1) {
+		printk("omap_dma: trying to free nonallocated DMA channel %d\n",
+		       lch);
 		spin_unlock_irqrestore(&dma_chan_lock, flags);
 		return;
 	}
-	dma_chan[ch].dev_id = -1;
+	dma_chan[lch].dev_id = -1;
+	dma_chan[lch].next_lch = -1;
+	dma_chan[lch].callback = NULL;
 	spin_unlock_irqrestore(&dma_chan_lock, flags);
 
-	/* Disable all DMA interrupts for the channel. */
-	omap_writew(0, OMAP_DMA_CICR(ch));
-	/* Make sure the DMA transfer is stopped. */
-	omap_writew(0, OMAP_DMA_CCR(ch));
+	if (cpu_class_is_omap1()) {
+		/* Disable all DMA interrupts for the channel. */
+		OMAP_DMA_CICR_REG(lch) = 0;
+		/* Make sure the DMA transfer is stopped. */
+		OMAP_DMA_CCR_REG(lch) = 0;
+	}
+
+	if (cpu_is_omap24xx()) {
+		u32 val;
+		/* Disable interrupts */
+		val = omap_readl(OMAP_DMA4_IRQENABLE_L0);
+		val &= ~(1 << lch);
+		omap_writel(val, OMAP_DMA4_IRQENABLE_L0);
+
+		/* Clear the CSR register and IRQ status register */
+		OMAP_DMA_CSR_REG(lch) = 0x0;
+
+		val = omap_readl(OMAP_DMA4_IRQSTATUS_L0);
+		val |= 1 << lch;
+		omap_writel(val, OMAP_DMA4_IRQSTATUS_L0);
+
+		/* Disable all DMA interrupts for the channel. */
+		OMAP_DMA_CICR_REG(lch) = 0;
+
+		/* Make sure the DMA transfer is stopped. */
+		OMAP_DMA_CCR_REG(lch) = 0;
+		omap_clear_dma(lch);
+	}
 }
 
-int omap_dma_in_1510_mode(void)
+/*
+ * Clears any DMA state so the DMA engine is ready to restart with new buffers
+ * through omap_start_dma(). Any buffers in flight are discarded.
+ */
+void omap_clear_dma(int lch)
 {
-	return enable_1510_mode;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	if (cpu_class_is_omap1()) {
+		int status;
+		OMAP_DMA_CCR_REG(lch) &= ~OMAP_DMA_CCR_EN;
+
+		/* Clear pending interrupts */
+		status = OMAP_DMA_CSR_REG(lch);
+	}
+
+	if (cpu_is_omap24xx()) {
+		int i;
+		u32 lch_base = OMAP24XX_DMA_BASE + lch * 0x60 + 0x80;
+		for (i = 0; i < 0x44; i += 4)
+			omap_writel(0, lch_base + i);
+	}
+
+	local_irq_restore(flags);
+}
+
+void omap_start_dma(int lch)
+{
+	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+		int next_lch, cur_lch;
+		char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
+
+		dma_chan_link_map[lch] = 1;
+		/* Set the link register of the first channel */
+		enable_lnk(lch);
+
+		memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+		cur_lch = dma_chan[lch].next_lch;
+		do {
+			next_lch = dma_chan[cur_lch].next_lch;
+
+			/* The loop case: we've been here already */
+			if (dma_chan_link_map[cur_lch])
+				break;
+			/* Mark the current channel */
+			dma_chan_link_map[cur_lch] = 1;
+
+			enable_lnk(cur_lch);
+			omap_enable_channel_irq(cur_lch);
+
+			cur_lch = next_lch;
+		} while (next_lch != -1);
+	} else if (cpu_is_omap24xx()) {
+		/* Errata: Need to write lch even if not using chaining */
+		OMAP_DMA_CLNK_CTRL_REG(lch) = lch;
+	}
+
+	omap_enable_channel_irq(lch);
+
+	/* Errata: On ES2.0 BUFFERING disable must be set.
+	 * This will always fail on ES1.0 */
+	if (cpu_is_omap24xx()) {
+		OMAP_DMA_CCR_REG(lch) |= OMAP_DMA_CCR_EN;
+	}
+
+	OMAP_DMA_CCR_REG(lch) |= OMAP_DMA_CCR_EN;
+
+	dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
+}
+
+void omap_stop_dma(int lch)
+{
+	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+		int next_lch, cur_lch = lch;
+		char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
+
+		memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+		do {
+			/* The loop case: we've been here already */
+			if (dma_chan_link_map[cur_lch])
+				break;
+			/* Mark the current channel */
+			dma_chan_link_map[cur_lch] = 1;
+
+			disable_lnk(cur_lch);
+
+			next_lch = dma_chan[cur_lch].next_lch;
+			cur_lch = next_lch;
+		} while (next_lch != -1);
+
+		return;
+	}
+
+	/* Disable all interrupts on the channel */
+	if (cpu_class_is_omap1())
+		OMAP_DMA_CICR_REG(lch) = 0;
+
+	OMAP_DMA_CCR_REG(lch) &= ~OMAP_DMA_CCR_EN;
+	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+}
+
+/*
+ * Returns current physical source address for the given DMA channel.
+ * If the channel is running the caller must disable interrupts prior calling
+ * this function and process the returned value before re-enabling interrupt to
+ * prevent races with the interrupt handler. Note that in continuous mode there
+ * is a chance for CSSA_L register overflow inbetween the two reads resulting
+ * in incorrect return value.
+ */
+dma_addr_t omap_get_dma_src_pos(int lch)
+{
+	dma_addr_t offset;
+
+	if (cpu_class_is_omap1())
+		offset = (dma_addr_t) (OMAP1_DMA_CSSA_L_REG(lch) |
+				       (OMAP1_DMA_CSSA_U_REG(lch) << 16));
+
+	if (cpu_is_omap24xx())
+		offset = OMAP_DMA_CSAC_REG(lch);
+
+	return offset;
+}
+
+/*
+ * Returns current physical destination address for the given DMA channel.
+ * If the channel is running the caller must disable interrupts prior calling
+ * this function and process the returned value before re-enabling interrupt to
+ * prevent races with the interrupt handler. Note that in continuous mode there
+ * is a chance for CDSA_L register overflow inbetween the two reads resulting
+ * in incorrect return value.
+ */
+dma_addr_t omap_get_dma_dst_pos(int lch)
+{
+	dma_addr_t offset;
+
+	if (cpu_class_is_omap1())
+		offset = (dma_addr_t) (OMAP1_DMA_CDSA_L_REG(lch) |
+				       (OMAP1_DMA_CDSA_U_REG(lch) << 16));
+
+	if (cpu_is_omap24xx())
+		offset = OMAP2_DMA_CDSA_REG(lch);
+
+	return offset;
+}
+
+/*
+ * Returns current source transfer counting for the given DMA channel.
+ * Can be used to monitor the progress of a transfer inside a block.
+ * It must be called with disabled interrupts.
+ */
+int omap_get_dma_src_addr_counter(int lch)
+{
+	return (dma_addr_t) OMAP_DMA_CSAC_REG(lch);
+}
+
+int omap_dma_running(void)
+{
+	int lch;
+
+	/* Check if LCD DMA is running */
+	if (cpu_is_omap16xx())
+		if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN)
+			return 1;
+
+	for (lch = 0; lch < dma_chan_count; lch++)
+		if (OMAP_DMA_CCR_REG(lch) & OMAP_DMA_CCR_EN)
+			return 1;
+
+	return 0;
 }
 
 /*
@@ -550,7 +737,8 @@
 
 	if ((dma_chan[lch_head].dev_id == -1) ||
 	    (dma_chan[lch_queue].dev_id == -1)) {
-		printk(KERN_ERR "omap_dma: trying to link non requested channels\n");
+		printk(KERN_ERR "omap_dma: trying to link "
+		       "non requested channels\n");
 		dump_stack();
 	}
 
@@ -570,20 +758,149 @@
 
 	if (dma_chan[lch_head].next_lch != lch_queue ||
 	    dma_chan[lch_head].next_lch == -1) {
-		printk(KERN_ERR "omap_dma: trying to unlink non linked channels\n");
+		printk(KERN_ERR "omap_dma: trying to unlink "
+		       "non linked channels\n");
 		dump_stack();
 	}
 
 
 	if ((dma_chan[lch_head].flags & OMAP_DMA_ACTIVE) ||
 	    (dma_chan[lch_head].flags & OMAP_DMA_ACTIVE)) {
-		printk(KERN_ERR "omap_dma: You need to stop the DMA channels before unlinking\n");
+		printk(KERN_ERR "omap_dma: You need to stop the DMA channels "
+		       "before unlinking\n");
 		dump_stack();
 	}
 
 	dma_chan[lch_head].next_lch = -1;
 }
 
+/*----------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP1
+
+static int omap1_dma_handle_ch(int ch)
+{
+	u16 csr;
+
+	if (enable_1510_mode && ch >= 6) {
+		csr = dma_chan[ch].saved_csr;
+		dma_chan[ch].saved_csr = 0;
+	} else
+		csr = OMAP_DMA_CSR_REG(ch);
+	if (enable_1510_mode && ch <= 2 && (csr >> 7) != 0) {
+		dma_chan[ch + 6].saved_csr = csr >> 7;
+		csr &= 0x7f;
+	}
+	if ((csr & 0x3f) == 0)
+		return 0;
+	if (unlikely(dma_chan[ch].dev_id == -1)) {
+		printk(KERN_WARNING "Spurious interrupt from DMA channel "
+		       "%d (CSR %04x)\n", ch, csr);
+		return 0;
+	}
+	if (unlikely(csr & OMAP_DMA_TOUT_IRQ))
+		printk(KERN_WARNING "DMA timeout with device %d\n",
+		       dma_chan[ch].dev_id);
+	if (unlikely(csr & OMAP_DMA_DROP_IRQ))
+		printk(KERN_WARNING "DMA synchronization event drop occurred "
+		       "with device %d\n", dma_chan[ch].dev_id);
+	if (likely(csr & OMAP_DMA_BLOCK_IRQ))
+		dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE;
+	if (likely(dma_chan[ch].callback != NULL))
+		dma_chan[ch].callback(ch, csr, dma_chan[ch].data);
+	return 1;
+}
+
+static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id,
+					 struct pt_regs *regs)
+{
+	int ch = ((int) dev_id) - 1;
+	int handled = 0;
+
+	for (;;) {
+		int handled_now = 0;
+
+		handled_now += omap1_dma_handle_ch(ch);
+		if (enable_1510_mode && dma_chan[ch + 6].saved_csr)
+			handled_now += omap1_dma_handle_ch(ch + 6);
+		if (!handled_now)
+			break;
+		handled += handled_now;
+	}
+
+	return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+#else
+#define omap1_dma_irq_handler	NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+
+static int omap2_dma_handle_ch(int ch)
+{
+	u32 status = OMAP_DMA_CSR_REG(ch);
+	u32 val;
+
+	if (!status)
+		return 0;
+	if (unlikely(dma_chan[ch].dev_id == -1))
+		return 0;
+	/* REVISIT: According to 24xx TRM, there's no TOUT_IE */
+	if (unlikely(status & OMAP_DMA_TOUT_IRQ))
+		printk(KERN_INFO "DMA timeout with device %d\n",
+		       dma_chan[ch].dev_id);
+	if (unlikely(status & OMAP_DMA_DROP_IRQ))
+		printk(KERN_INFO
+		       "DMA synchronization event drop occurred with device "
+		       "%d\n", dma_chan[ch].dev_id);
+
+	if (unlikely(status & OMAP2_DMA_TRANS_ERR_IRQ))
+		printk(KERN_INFO "DMA transaction error with device %d\n",
+		       dma_chan[ch].dev_id);
+
+	OMAP_DMA_CSR_REG(ch) = 0x20;
+
+	val = omap_readl(OMAP_DMA4_IRQSTATUS_L0);
+	/* ch in this function is from 0-31 while in register it is 1-32 */
+	val = 1 << (ch);
+	omap_writel(val, OMAP_DMA4_IRQSTATUS_L0);
+
+	if (likely(dma_chan[ch].callback != NULL))
+		dma_chan[ch].callback(ch, status, dma_chan[ch].data);
+
+	return 0;
+}
+
+/* STATUS register count is from 1-32 while our is 0-31 */
+static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id,
+					 struct pt_regs *regs)
+{
+	u32 val;
+	int i;
+
+	val = omap_readl(OMAP_DMA4_IRQSTATUS_L0);
+
+	for (i = 1; i <= OMAP_LOGICAL_DMA_CH_COUNT; i++) {
+		int active = val & (1 << (i - 1));
+		if (active)
+			omap2_dma_handle_ch(i - 1);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction omap24xx_dma_irq = {
+	.name = "DMA",
+	.handler = omap2_dma_irq_handler,
+	.flags = SA_INTERRUPT
+};
+
+#else
+static struct irqaction omap24xx_dma_irq;
+#endif
+
+/*----------------------------------------------------------------------------*/
 
 static struct lcd_dma_info {
 	spinlock_t lock;
@@ -795,7 +1112,7 @@
 	/* Always set the source port as SDRAM for now*/
 	w &= ~(0x03 << 6);
 	if (lcd_dma.callback != NULL)
-		w |= 1 << 1;            /* Block interrupt enable */
+		w |= 1 << 1;		/* Block interrupt enable */
 	else
 		w &= ~(1 << 1);
 	omap_writew(w, OMAP1610_DMA_LCD_CTRL);
@@ -814,7 +1131,8 @@
 	omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L);
 }
 
-static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id,
+				       struct pt_regs *regs)
 {
 	u16 w;
 
@@ -870,7 +1188,8 @@
 		return;
 	}
 	if (!enable_1510_mode)
-		omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1, OMAP1610_DMA_LCD_CCR);
+		omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1,
+			    OMAP1610_DMA_LCD_CCR);
 	lcd_dma.reserved = 0;
 	spin_unlock(&lcd_dma.lock);
 }
@@ -939,93 +1258,24 @@
 	omap_writew(w, OMAP1610_DMA_LCD_CTRL);
 }
 
-/*
- * Clears any DMA state so the DMA engine is ready to restart with new buffers
- * through omap_start_dma(). Any buffers in flight are discarded.
- */
-void omap_clear_dma(int lch)
-{
-	unsigned long flags;
-	int status;
-
-	local_irq_save(flags);
-	omap_writew(omap_readw(OMAP_DMA_CCR(lch)) & ~OMAP_DMA_CCR_EN,
-		    OMAP_DMA_CCR(lch));
-	status = OMAP_DMA_CSR(lch);	/* clear pending interrupts */
-	local_irq_restore(flags);
-}
-
-/*
- * Returns current physical source address for the given DMA channel.
- * If the channel is running the caller must disable interrupts prior calling
- * this function and process the returned value before re-enabling interrupt to
- * prevent races with the interrupt handler. Note that in continuous mode there
- * is a chance for CSSA_L register overflow inbetween the two reads resulting
- * in incorrect return value.
- */
-dma_addr_t omap_get_dma_src_pos(int lch)
-{
-	return (dma_addr_t) (omap_readw(OMAP_DMA_CSSA_L(lch)) |
-	(omap_readw(OMAP_DMA_CSSA_U(lch)) << 16));
-}
-
-/*
- * Returns current physical destination address for the given DMA channel.
- * If the channel is running the caller must disable interrupts prior calling
- * this function and process the returned value before re-enabling interrupt to
- * prevent races with the interrupt handler. Note that in continuous mode there
- * is a chance for CDSA_L register overflow inbetween the two reads resulting
- * in incorrect return value.
- */
-dma_addr_t omap_get_dma_dst_pos(int lch)
-{
-	return (dma_addr_t) (omap_readw(OMAP_DMA_CDSA_L(lch)) |
-	(omap_readw(OMAP_DMA_CDSA_U(lch)) << 16));
-}
-
-/*
- * Returns current source transfer counting for the given DMA channel.
- * Can be used to monitor the progress of a transfer inside a  block.
- * It must be called with disabled interrupts.
- */
-int omap_get_dma_src_addr_counter(int lch)
-{
-	return (dma_addr_t) omap_readw(OMAP_DMA_CSAC(lch));
-}
-
-int omap_dma_running(void)
-{
-	int lch;
-
-	/* Check if LCD DMA is running */
-	if (cpu_is_omap16xx())
-		if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN)
-			return 1;
-
-	for (lch = 0; lch < dma_chan_count; lch++) {
-		u16 w;
-
-		w = omap_readw(OMAP_DMA_CCR(lch));
-		if (w & OMAP_DMA_CCR_EN)
-			return 1;
-	}
-	return 0;
-}
+/*----------------------------------------------------------------------------*/
 
 static int __init omap_init_dma(void)
 {
 	int ch, r;
 
-	if (cpu_is_omap1510()) {
-		printk(KERN_INFO "DMA support for OMAP1510 initialized\n");
+	if (cpu_is_omap15xx()) {
+		printk(KERN_INFO "DMA support for OMAP15xx initialized\n");
 		dma_chan_count = 9;
 		enable_1510_mode = 1;
 	} else if (cpu_is_omap16xx() || cpu_is_omap730()) {
 		printk(KERN_INFO "OMAP DMA hardware version %d\n",
 		       omap_readw(OMAP_DMA_HW_ID));
 		printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n",
-		       (omap_readw(OMAP_DMA_CAPS_0_U) << 16) | omap_readw(OMAP_DMA_CAPS_0_L),
-		       (omap_readw(OMAP_DMA_CAPS_1_U) << 16) | omap_readw(OMAP_DMA_CAPS_1_L),
+		       (omap_readw(OMAP_DMA_CAPS_0_U) << 16) |
+		       omap_readw(OMAP_DMA_CAPS_0_L),
+		       (omap_readw(OMAP_DMA_CAPS_1_U) << 16) |
+		       omap_readw(OMAP_DMA_CAPS_1_L),
 		       omap_readw(OMAP_DMA_CAPS_2), omap_readw(OMAP_DMA_CAPS_3),
 		       omap_readw(OMAP_DMA_CAPS_4));
 		if (!enable_1510_mode) {
@@ -1038,6 +1288,11 @@
 			dma_chan_count = 16;
 		} else
 			dma_chan_count = 9;
+	} else if (cpu_is_omap24xx()) {
+		u8 revision = omap_readb(OMAP_DMA4_REVISION);
+		printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n",
+		       revision >> 4, revision & 0xf);
+		dma_chan_count = OMAP_LOGICAL_DMA_CH_COUNT;
 	} else {
 		dma_chan_count = 0;
 		return 0;
@@ -1049,41 +1304,56 @@
 	memset(&dma_chan, 0, sizeof(dma_chan));
 
 	for (ch = 0; ch < dma_chan_count; ch++) {
+		omap_clear_dma(ch);
 		dma_chan[ch].dev_id = -1;
 		dma_chan[ch].next_lch = -1;
 
 		if (ch >= 6 && enable_1510_mode)
 			continue;
 
-		/* request_irq() doesn't like dev_id (ie. ch) being zero,
-		 * so we have to kludge around this. */
-		r = request_irq(dma_irq[ch], dma_irq_handler, 0, "DMA",
-				(void *) (ch + 1));
+		if (cpu_class_is_omap1()) {
+			/* request_irq() doesn't like dev_id (ie. ch) being
+			 * zero, so we have to kludge around this. */
+			r = request_irq(omap1_dma_irq[ch],
+					omap1_dma_irq_handler, 0, "DMA",
+					(void *) (ch + 1));
+			if (r != 0) {
+				int i;
+
+				printk(KERN_ERR "unable to request IRQ %d "
+				       "for DMA (error %d)\n",
+				       omap1_dma_irq[ch], r);
+				for (i = 0; i < ch; i++)
+					free_irq(omap1_dma_irq[i],
+						 (void *) (i + 1));
+				return r;
+			}
+		}
+	}
+
+	if (cpu_is_omap24xx())
+		setup_irq(INT_24XX_SDMA_IRQ0, &omap24xx_dma_irq);
+
+	/* FIXME: Update LCD DMA to work on 24xx */
+	if (cpu_class_is_omap1()) {
+		r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,
+				"LCD DMA", NULL);
 		if (r != 0) {
 			int i;
 
-			printk(KERN_ERR "unable to request IRQ %d for DMA (error %d)\n",
-			       dma_irq[ch], r);
-			for (i = 0; i < ch; i++)
-				free_irq(dma_irq[i], (void *) (i + 1));
+			printk(KERN_ERR "unable to request IRQ for LCD DMA "
+			       "(error %d)\n", r);
+			for (i = 0; i < dma_chan_count; i++)
+				free_irq(omap1_dma_irq[i], (void *) (i + 1));
 			return r;
 		}
 	}
-	r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0, "LCD DMA", NULL);
-	if (r != 0) {
-		int i;
 
-		printk(KERN_ERR "unable to request IRQ for LCD DMA (error %d)\n", r);
-		for (i = 0; i < dma_chan_count; i++)
-			free_irq(dma_irq[i], (void *) (i + 1));
-		return r;
-	}
 	return 0;
 }
 
 arch_initcall(omap_init_dma);
 
-
 EXPORT_SYMBOL(omap_get_dma_src_pos);
 EXPORT_SYMBOL(omap_get_dma_dst_pos);
 EXPORT_SYMBOL(omap_get_dma_src_addr_counter);
@@ -1109,6 +1379,8 @@
 EXPORT_SYMBOL(omap_set_dma_dest_data_pack);
 EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);
 
+EXPORT_SYMBOL(omap_set_dma_params);
+
 EXPORT_SYMBOL(omap_dma_link_lch);
 EXPORT_SYMBOL(omap_dma_unlink_lch);
 
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 55059a2..76f721d 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -140,7 +140,7 @@
 };
 #endif
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 static struct gpio_bank gpio_bank_1510[2] = {
 	{ OMAP_MPUIO_BASE,    INT_MPUIO,      IH_MPUIO_BASE, METHOD_MPUIO },
 	{ OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE,  METHOD_GPIO_1510 }
@@ -173,7 +173,7 @@
 
 static inline struct gpio_bank *get_gpio_bank(int gpio)
 {
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		if (OMAP_GPIO_IS_MPUIO(gpio))
 			return &gpio_bank[0];
@@ -222,7 +222,7 @@
 			return -1;
 		return 0;
 	}
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510() && gpio < 16)
 		return 0;
 #endif
@@ -654,7 +654,7 @@
 	/* Set trigger to none. You need to enable the trigger after request_irq */
 	_set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (bank->method == METHOD_GPIO_1510) {
 		void __iomem *reg;
 
@@ -739,7 +739,7 @@
 	bank = (struct gpio_bank *) desc->data;
 	if (bank->method == METHOD_MPUIO)
 		isr_reg = bank->base + OMAP_MPUIO_GPIO_INT;
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (bank->method == METHOD_GPIO_1510)
 		isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS;
 #endif
@@ -774,7 +774,7 @@
 			d = irq_desc + gpio_irq;
 			desc_handle_irq(gpio_irq, d, regs);
 		}
-        }
+	}
 }
 
 static void gpio_ack_irq(unsigned int irq)
@@ -837,8 +837,9 @@
 	.unmask = mpuio_unmask_irq
 };
 
-static int initialized = 0;
-static struct clk * gpio_ck = NULL;
+static int initialized;
+static struct clk * gpio_ick;
+static struct clk * gpio_fck;
 
 static int __init _omap_gpio_init(void)
 {
@@ -848,14 +849,26 @@
 	initialized = 1;
 
 	if (cpu_is_omap1510()) {
-		gpio_ck = clk_get(NULL, "arm_gpio_ck");
-		if (IS_ERR(gpio_ck))
+		gpio_ick = clk_get(NULL, "arm_gpio_ck");
+		if (IS_ERR(gpio_ick))
 			printk("Could not get arm_gpio_ck\n");
 		else
-			clk_use(gpio_ck);
+			clk_use(gpio_ick);
+	}
+	if (cpu_is_omap24xx()) {
+		gpio_ick = clk_get(NULL, "gpios_ick");
+		if (IS_ERR(gpio_ick))
+			printk("Could not get gpios_ick\n");
+		else
+			clk_use(gpio_ick);
+		gpio_fck = clk_get(NULL, "gpios_fck");
+		if (IS_ERR(gpio_ick))
+			printk("Could not get gpios_fck\n");
+		else
+			clk_use(gpio_fck);
 	}
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		printk(KERN_INFO "OMAP1510 GPIO hardware\n");
 		gpio_bank_count = 2;
@@ -901,7 +914,7 @@
 		if (bank->method == METHOD_MPUIO) {
 			omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT);
 		}
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 		if (bank->method == METHOD_GPIO_1510) {
 			__raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK);
 			__raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS);
@@ -1038,6 +1051,7 @@
 
 /*
  * This may get called early from board specific init
+ * for boards that have interrupts routed via FPGA.
  */
 int omap_gpio_init(void)
 {
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 9c9b7df..ea9475c 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -491,17 +491,20 @@
 	omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
 				     OMAP_DMA_DATA_TYPE_S16,
 				     length >> 1, 1,
-				     OMAP_DMA_SYNC_ELEMENT);
+				     OMAP_DMA_SYNC_ELEMENT,
+				     0, 0);
 
 	omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
 				 OMAP_DMA_PORT_TIPB,
 				 OMAP_DMA_AMODE_CONSTANT,
-				 mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1);
+				 mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1,
+				 0, 0);
 
 	omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
 				OMAP_DMA_PORT_EMIFF,
 				OMAP_DMA_AMODE_POST_INC,
-				buffer);
+				buffer,
+				0, 0);
 
 	omap_start_dma(mcbsp[id].dma_tx_lch);
 	wait_for_completion(&(mcbsp[id].tx_dma_completion));
@@ -531,17 +534,20 @@
 	omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
 				     OMAP_DMA_DATA_TYPE_S16,
 				     length >> 1, 1,
-				     OMAP_DMA_SYNC_ELEMENT);
+				     OMAP_DMA_SYNC_ELEMENT,
+				     0, 0);
 
 	omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
 				OMAP_DMA_PORT_TIPB,
 				OMAP_DMA_AMODE_CONSTANT,
-				mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1);
+				mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1,
+				0, 0);
 
 	omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
 				 OMAP_DMA_PORT_EMIFF,
 				 OMAP_DMA_AMODE_POST_INC,
-				 buffer);
+				 buffer,
+				 0, 0);
 
 	omap_start_dma(mcbsp[id].dma_rx_lch);
 	wait_for_completion(&(mcbsp[id].rx_dma_completion));
@@ -643,7 +649,7 @@
 };
 #endif
 
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 static const struct omap_mcbsp_info mcbsp_1510[] = {
 	[0] = { .virt_base = OMAP1510_MCBSP1_BASE,
 		.dma_rx_sync = OMAP_DMA_MCBSP1_RX,
@@ -712,7 +718,7 @@
 		mcbsp_count = ARRAY_SIZE(mcbsp_730);
 	}
 #endif
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap1510()) {
 		mcbsp_info = mcbsp_1510;
 		mcbsp_count = ARRAY_SIZE(mcbsp_1510);
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
index 6448204..8c1c016 100644
--- a/arch/arm/plat-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -3,7 +3,7 @@
  *
  * Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h
  *
- * Copyright (C) 2003 Nokia Corporation
+ * Copyright (C) 2003 - 2005 Nokia Corporation
  *
  * Written by Tony Lindgren <tony.lindgren@nokia.com>
  *
@@ -25,38 +25,74 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <linux/spinlock.h>
-
-#define __MUX_C__
 #include <asm/arch/mux.h>
 
 #ifdef CONFIG_OMAP_MUX
 
+#define OMAP24XX_L4_BASE	0x48000000
+#define OMAP24XX_PULL_ENA	(1 << 3)
+#define OMAP24XX_PULL_UP	(1 << 4)
+
+static struct pin_config * pin_table;
+static unsigned long pin_table_sz;
+
+extern struct pin_config * omap730_pins;
+extern struct pin_config * omap1xxx_pins;
+extern struct pin_config * omap24xx_pins;
+
+int __init omap_mux_register(struct pin_config * pins, unsigned long size)
+{
+	pin_table = pins;
+	pin_table_sz = size;
+
+	return 0;
+}
+
 /*
  * Sets the Omap MUX and PULL_DWN registers based on the table
  */
-int __init_or_module
-omap_cfg_reg(const reg_cfg_t reg_cfg)
+int __init_or_module omap_cfg_reg(const unsigned long index)
 {
 	static DEFINE_SPINLOCK(mux_spin_lock);
 
 	unsigned long flags;
-	reg_cfg_set *cfg;
+	struct pin_config *cfg;
 	unsigned int reg_orig = 0, reg = 0, pu_pd_orig = 0, pu_pd = 0,
 		pull_orig = 0, pull = 0;
 	unsigned int mask, warn = 0;
 
-	if (cpu_is_omap7xx())
-		return 0;
+	if (!pin_table)
+		BUG();
 
-	if (reg_cfg > ARRAY_SIZE(reg_cfg_table)) {
-		printk(KERN_ERR "MUX: reg_cfg %d\n", reg_cfg);
-		return -EINVAL;
+	if (index >= pin_table_sz) {
+		printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n",
+		       index, pin_table_sz);
+		dump_stack();
+		return -ENODEV;
 	}
 
-	cfg = (reg_cfg_set *)&reg_cfg_table[reg_cfg];
+	cfg = (struct pin_config *)&pin_table[index];
+	if (cpu_is_omap24xx()) {
+		u8 reg = 0;
+
+		reg |= cfg->mask & 0x7;
+		if (cfg->pull_val)
+			reg |= OMAP24XX_PULL_ENA;
+		if(cfg->pu_pd_val)
+			reg |= OMAP24XX_PULL_UP;
+#ifdef CONFIG_OMAP_MUX_DEBUG
+		printk("Muxing %s (0x%08x): 0x%02x -> 0x%02x\n",
+		       cfg->name, OMAP24XX_L4_BASE + cfg->mux_reg,
+		       omap_readb(OMAP24XX_L4_BASE + cfg->mux_reg), reg);
+#endif
+		omap_writeb(reg, OMAP24XX_L4_BASE + cfg->mux_reg);
+
+		return 0;
+	}
 
 	/* Check the mux register in question */
 	if (cfg->mux_reg) {
@@ -157,7 +193,8 @@
 	return 0;
 #endif
 }
-
 EXPORT_SYMBOL(omap_cfg_reg);
-
+#else
+#define omap_mux_init() do {} while(0)
+#define omap_cfg_reg(x)	do {} while(0)
 #endif	/* CONFIG_OMAP_MUX */
diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c
index 1fb16f9..2ede2ee 100644
--- a/arch/arm/plat-omap/ocpi.c
+++ b/arch/arm/plat-omap/ocpi.c
@@ -25,7 +25,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
diff --git a/arch/arm/plat-omap/pm.c b/arch/arm/plat-omap/pm.c
index e15c6c1..966cca03 100644
--- a/arch/arm/plat-omap/pm.c
+++ b/arch/arm/plat-omap/pm.c
@@ -54,11 +54,12 @@
 #include <asm/arch/tps65010.h>
 #include <asm/arch/dsp_common.h>
 
-#include "clock.h"
-#include "sram.h"
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
 
 static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
 static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
+static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE];
 static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
 static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
 
@@ -120,8 +121,8 @@
  */
 static void omap_pm_wakeup_setup(void)
 {
-	u32 level1_wake = OMAP_IRQ_BIT(INT_IH2_IRQ);
-	u32 level2_wake = OMAP_IRQ_BIT(INT_UART2) | OMAP_IRQ_BIT(INT_KEYBOARD);
+	u32 level1_wake = 0;
+	u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);
 
 	/*
 	 * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
@@ -129,19 +130,29 @@
 	 * drivers must still separately call omap_set_gpio_wakeup() to
 	 * wake up to a GPIO interrupt.
 	 */
-	if (cpu_is_omap1510() || cpu_is_omap16xx())
-		level1_wake |= OMAP_IRQ_BIT(INT_GPIO_BANK1);
-	else if (cpu_is_omap730())
-		level1_wake |= OMAP_IRQ_BIT(INT_730_GPIO_BANK1);
+	if (cpu_is_omap730())
+		level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) |
+			OMAP_IRQ_BIT(INT_730_IH2_IRQ);
+	else if (cpu_is_omap1510())
+		level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+			OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
+	else if (cpu_is_omap16xx())
+		level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+			OMAP_IRQ_BIT(INT_1610_IH2_IRQ);
 
 	omap_writel(~level1_wake, OMAP_IH1_MIR);
 
-	if (cpu_is_omap1510())
-		omap_writel(~level2_wake,  OMAP_IH2_MIR);
-
-	/* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
-	if (cpu_is_omap16xx()) {
+	if (cpu_is_omap730()) {
 		omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+		omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) | OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)), OMAP_IH2_1_MIR);
+	} else if (cpu_is_omap1510()) {
+		level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+		omap_writel(~level2_wake,  OMAP_IH2_MIR);
+	} else if (cpu_is_omap16xx()) {
+		level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+		omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+
+		/* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
 		omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR);
 		omap_writel(~0x0, OMAP_IH2_2_MIR);
 		omap_writel(~0x0, OMAP_IH2_3_MIR);
@@ -185,7 +196,17 @@
  	 * Save interrupt, MPUI, ARM and UPLD control registers.
 	 */
 
-	if (cpu_is_omap1510()) {
+	if (cpu_is_omap730()) {
+		MPUI730_SAVE(OMAP_IH1_MIR);
+		MPUI730_SAVE(OMAP_IH2_0_MIR);
+		MPUI730_SAVE(OMAP_IH2_1_MIR);
+		MPUI730_SAVE(MPUI_CTRL);
+		MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
+		MPUI730_SAVE(MPUI_DSP_API_CONFIG);
+		MPUI730_SAVE(EMIFS_CONFIG);
+		MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+
+	} else if (cpu_is_omap1510()) {
 		MPUI1510_SAVE(OMAP_IH1_MIR);
 		MPUI1510_SAVE(OMAP_IH2_MIR);
 		MPUI1510_SAVE(MPUI_CTRL);
@@ -280,7 +301,13 @@
 	ULPD_RESTORE(ULPD_CLOCK_CTRL);
 	ULPD_RESTORE(ULPD_STATUS_REQ);
 
-	if (cpu_is_omap1510()) {
+	if (cpu_is_omap730()) {
+		MPUI730_RESTORE(EMIFS_CONFIG);
+		MPUI730_RESTORE(EMIFF_SDRAM_CONFIG);
+		MPUI730_RESTORE(OMAP_IH1_MIR);
+		MPUI730_RESTORE(OMAP_IH2_0_MIR);
+		MPUI730_RESTORE(OMAP_IH2_1_MIR);
+	} else if (cpu_is_omap1510()) {
 		MPUI1510_RESTORE(MPUI_CTRL);
 		MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
 		MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
@@ -355,7 +382,14 @@
 	ULPD_SAVE(ULPD_DPLL_CTRL);
 	ULPD_SAVE(ULPD_POWER_CTRL);
 
-	if (cpu_is_omap1510()) {
+	if (cpu_is_omap730()) {
+		MPUI730_SAVE(MPUI_CTRL);
+		MPUI730_SAVE(MPUI_DSP_STATUS);
+		MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
+		MPUI730_SAVE(MPUI_DSP_API_CONFIG);
+		MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+		MPUI730_SAVE(EMIFS_CONFIG);
+	} else if (cpu_is_omap1510()) {
 		MPUI1510_SAVE(MPUI_CTRL);
 		MPUI1510_SAVE(MPUI_DSP_STATUS);
 		MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
@@ -404,7 +438,21 @@
 		   ULPD_SHOW(ULPD_STATUS_REQ),
 		   ULPD_SHOW(ULPD_POWER_CTRL));
 
-		if (cpu_is_omap1510()) {
+		if (cpu_is_omap730()) {
+			my_buffer_offset += sprintf(my_base + my_buffer_offset,
+			   "MPUI730_CTRL_REG	     0x%-8x \n"
+			   "MPUI730_DSP_STATUS_REG:      0x%-8x \n"
+			   "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+	 "MPUI730_DSP_API_CONFIG_REG:  0x%-8x \n"
+	 "MPUI730_SDRAM_CONFIG_REG:    0x%-8x \n"
+	 "MPUI730_EMIFS_CONFIG_REG:    0x%-8x \n",
+	 MPUI730_SHOW(MPUI_CTRL),
+	 MPUI730_SHOW(MPUI_DSP_STATUS),
+	 MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
+	 MPUI730_SHOW(MPUI_DSP_API_CONFIG),
+	 MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
+	 MPUI730_SHOW(EMIFS_CONFIG));
+		} else if (cpu_is_omap1510()) {
 			my_buffer_offset += sprintf(my_base + my_buffer_offset,
 			   "MPUI1510_CTRL_REG             0x%-8x \n"
 			   "MPUI1510_DSP_STATUS_REG:      0x%-8x \n"
@@ -553,7 +601,12 @@
 	 * These routines need to be in SRAM as that's the only
 	 * memory the MPU can see when it wakes up.
 	 */
-	if (cpu_is_omap1510()) {
+	if (cpu_is_omap730()) {
+		omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend,
+						omap730_idle_loop_suspend_sz);
+		omap_sram_suspend = omap_sram_push(omap730_cpu_suspend,
+	 omap730_cpu_suspend_sz);
+	} else if (cpu_is_omap1510()) {
 		omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
 						omap1510_idle_loop_suspend_sz);
 		omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
@@ -572,7 +625,11 @@
 
 	pm_idle = omap_pm_idle;
 
-	setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
+	if (cpu_is_omap730())
+		setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
+	else if (cpu_is_omap16xx())
+		setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
+
 #if 0
 	/* --- BEGIN BOARD-DEPENDENT CODE --- */
 	/* Sleepx mask direction */
@@ -591,7 +648,9 @@
 	omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
 
 	/* Configure IDLECT3 */
-	if (cpu_is_omap16xx())
+	if (cpu_is_omap730())
+		omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3);
+	else if (cpu_is_omap16xx())
 		omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
 
 	pm_set_ops(&omap_pm_ops);
@@ -600,8 +659,10 @@
 	omap_pm_init_proc();
 #endif
 
-	/* configure LOW_PWR pin */
-	omap_cfg_reg(T20_1610_LOW_PWR);
+	if (cpu_is_omap16xx()) {
+		/* configure LOW_PWR pin */
+		omap_cfg_reg(T20_1610_LOW_PWR);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/plat-omap/sleep.S b/arch/arm/plat-omap/sleep.S
index 9f74583..4cd7d29 100644
--- a/arch/arm/plat-omap/sleep.S
+++ b/arch/arm/plat-omap/sleep.S
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/plat-omap/sleep.S
  *
- * Low-level OMAP1510/1610 sleep/wakeUp support
+ * Low-level OMAP730/1510/1610 sleep/wakeUp support
  *
  * Initial SA1110 code:
  * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
@@ -52,7 +52,57 @@
  *       processor specific functions here.
  */
 
-#ifdef CONFIG_ARCH_OMAP1510
+#if defined(CONFIG_ARCH_OMAP730)
+ENTRY(omap730_idle_loop_suspend)
+
+	stmfd	sp!, {r0 - r12, lr}		@ save registers on stack
+
+	@ load base address of ARM_IDLECT1 and ARM_IDLECT2
+	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+	@ turn off clock domains
+	@ get ARM_IDLECT2 into r2
+	ldrh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+	mov	r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff
+	orr	r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00
+	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+	@ request ARM idle
+	@ get ARM_IDLECT1 into r1
+	ldrh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+	orr	r3, r1, #OMAP730_IDLE_LOOP_REQUEST & 0xffff
+	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	mov	r5, #IDLE_WAIT_CYCLES & 0xff
+	orr	r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_730:	subs	r5, r5, #1
+	bne	l_730
+/*
+ * Let's wait for the next clock tick to wake us up.
+ */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c0, 4		@ wait for interrupt
+/*
+ * omap730_idle_loop_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+
+	@ restore ARM_IDLECT1 and ARM_IDLECT2 and return
+	@ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
+	strh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+	strh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	ldmfd	sp!, {r0 - r12, pc}		@ restore regs and return
+
+ENTRY(omap730_idle_loop_suspend_sz)
+	.word	. - omap730_idle_loop_suspend
+#endif /* CONFIG_ARCH_OMAP730 */
+
+#ifdef CONFIG_ARCH_OMAP15XX
 ENTRY(omap1510_idle_loop_suspend)
 
 	stmfd	sp!, {r0 - r12, lr}		@ save registers on stack
@@ -100,7 +150,7 @@
 
 ENTRY(omap1510_idle_loop_suspend_sz)
 	.word	. - omap1510_idle_loop_suspend
-#endif /* CONFIG_ARCH_OMAP1510 */
+#endif /* CONFIG_ARCH_OMAP15XX */
 
 #if defined(CONFIG_ARCH_OMAP16XX)
 ENTRY(omap1610_idle_loop_suspend)
@@ -169,7 +219,86 @@
  *
  */
 
-#ifdef CONFIG_ARCH_OMAP1510
+#if defined(CONFIG_ARCH_OMAP730)
+ENTRY(omap730_cpu_suspend)
+
+	@ save registers on stack
+	stmfd	sp!, {r0 - r12, lr}
+
+	@ Drain write cache
+	mov	r4, #0
+	mcr	p15, 0, r0, c7, c10, 4
+	nop
+
+	@ load base address of Traffic Controller
+	mov	r6, #TCMIF_ASM_BASE & 0xff000000
+	orr	r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
+	orr	r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
+
+	@ prepare to put SDRAM into self-refresh manually
+	ldr	r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+	orr	r9, r7, #SELF_REFRESH_MODE & 0xff000000
+	orr	r9, r9, #SELF_REFRESH_MODE & 0x000000ff
+	str	r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+
+	@ prepare to put EMIFS to Sleep
+	ldr	r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+	orr	r9, r8, #IDLE_EMIFS_REQUEST & 0xff
+	str	r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+	@ load base address of ARM_IDLECT1 and ARM_IDLECT2
+	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+	@ turn off clock domains
+	@ do not disable PERCK (0x04)
+	mov	r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff
+	orr	r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00
+	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+	@ request ARM idle
+	mov	r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff
+	orr	r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00
+	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	@ disable instruction cache
+	mrc	p15, 0, r9, c1, c0, 0
+	bic	r2, r9, #0x1000
+	mcr	p15, 0, r2, c1, c0, 0
+	nop
+
+/*
+ * Let's wait for the next wake up event to wake us up. r0 can't be
+ * used here because r0 holds ARM_IDLECT1
+ */
+	mov	r2, #0
+	mcr	p15, 0, r2, c7, c0, 4		@ wait for interrupt
+/*
+ * omap730_cpu_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack.
+ */
+	@ re-enable Icache
+	mcr	p15, 0, r9, c1, c0, 0
+
+	@ reset the ARM_IDLECT1 and ARM_IDLECT2.
+	strh	r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+	strh	r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	@ Restore EMIFF controls
+	str	r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+	str	r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+	@ restore regs and return
+	ldmfd	sp!, {r0 - r12, pc}
+
+ENTRY(omap730_cpu_suspend_sz)
+	.word	. - omap730_cpu_suspend
+#endif /* CONFIG_ARCH_OMAP730 */
+
+#ifdef CONFIG_ARCH_OMAP15XX
 ENTRY(omap1510_cpu_suspend)
 
 	@ save registers on stack
@@ -241,7 +370,7 @@
 
 ENTRY(omap1510_cpu_suspend_sz)
 	.word	. - omap1510_cpu_suspend
-#endif /* CONFIG_ARCH_OMAP1510 */
+#endif /* CONFIG_ARCH_OMAP15XX */
 
 #if defined(CONFIG_ARCH_OMAP16XX)
 ENTRY(omap1610_cpu_suspend)
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 7ad69f1..792f663 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -20,10 +20,13 @@
 #include <asm/io.h>
 #include <asm/cacheflush.h>
 
-#include "sram.h"
+#include <asm/arch/sram.h>
 
-#define OMAP1_SRAM_BASE		0xd0000000
-#define OMAP1_SRAM_START	0x20000000
+#define OMAP1_SRAM_PA		0x20000000
+#define OMAP1_SRAM_VA		0xd0000000
+#define OMAP2_SRAM_PA		0x40200000
+#define OMAP2_SRAM_VA		0xd0000000
+
 #define SRAM_BOOTLOADER_SZ	0x80
 
 static unsigned long omap_sram_base;
@@ -31,37 +34,40 @@
 static unsigned long omap_sram_ceil;
 
 /*
- * The amount of SRAM depends on the core type:
- * 730 = 200K, 1510 = 512K, 5912 = 256K, 1610 = 16K, 1710 = 16K
+ * The amount of SRAM depends on the core type.
  * Note that we cannot try to test for SRAM here because writes
  * to secure SRAM will hang the system. Also the SRAM is not
  * yet mapped at this point.
  */
 void __init omap_detect_sram(void)
 {
-	omap_sram_base = OMAP1_SRAM_BASE;
+	if (!cpu_is_omap24xx())
+		omap_sram_base = OMAP1_SRAM_VA;
+	else
+		omap_sram_base = OMAP2_SRAM_VA;
 
 	if (cpu_is_omap730())
-		omap_sram_size = 0x32000;
-	else if (cpu_is_omap1510())
-		omap_sram_size = 0x80000;
+		omap_sram_size = 0x32000;	/* 200K */
+	else if (cpu_is_omap15xx())
+		omap_sram_size = 0x30000;	/* 192K */
 	else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710())
-		omap_sram_size = 0x4000;
+		omap_sram_size = 0x4000;	/* 16K */
 	else if (cpu_is_omap1611())
-		omap_sram_size = 0x3e800;
+		omap_sram_size = 0x3e800;	/* 250K */
+	else if (cpu_is_omap2420())
+		omap_sram_size = 0xa0014;	/* 640K */
 	else {
 		printk(KERN_ERR "Could not detect SRAM size\n");
 		omap_sram_size = 0x4000;
 	}
 
-	printk(KERN_INFO "SRAM size: 0x%lx\n", omap_sram_size);
 	omap_sram_ceil = omap_sram_base + omap_sram_size;
 }
 
 static struct map_desc omap_sram_io_desc[] __initdata = {
 	{	/* .length gets filled in at runtime */
-		.virtual	= OMAP1_SRAM_BASE,
-		.pfn		= __phys_to_pfn(OMAP1_SRAM_START),
+		.virtual	= OMAP1_SRAM_VA,
+		.pfn		= __phys_to_pfn(OMAP1_SRAM_PA),
 		.type		= MT_DEVICE
 	}
 };
@@ -76,10 +82,19 @@
 	if (omap_sram_size == 0)
 		return;
 
+	if (cpu_is_omap24xx()) {
+		omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA;
+		omap_sram_io_desc[0].pfn = __phys_to_pfn(OMAP2_SRAM_PA);
+	}
+
 	omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE;
 	omap_sram_io_desc[0].length *= PAGE_SIZE;
 	iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
 
+	printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n",
+	       omap_sram_io_desc[0].pfn, omap_sram_io_desc[0].virtual,
+	       omap_sram_io_desc[0].length);
+
 	/*
 	 * Looks like we need to preserve some bootloader code at the
 	 * beginning of SRAM for jumping to flash for reboot to work...
@@ -88,16 +103,6 @@
 	       omap_sram_size - SRAM_BOOTLOADER_SZ);
 }
 
-static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl) = NULL;
-
-void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl)
-{
-	if (_omap_sram_reprogram_clock == NULL)
-		panic("Cannot use SRAM");
-
-	return _omap_sram_reprogram_clock(dpllctl, ckctl);
-}
-
 void * omap_sram_push(void * start, unsigned long size)
 {
 	if (size > (omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ))) {
@@ -111,10 +116,94 @@
 	return (void *)omap_sram_ceil;
 }
 
-void __init omap_sram_init(void)
+static void omap_sram_error(void)
+{
+	panic("Uninitialized SRAM function\n");
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+
+static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl);
+
+void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl)
+{
+	if (!_omap_sram_reprogram_clock)
+		omap_sram_error();
+
+	return _omap_sram_reprogram_clock(dpllctl, ckctl);
+}
+
+int __init omap1_sram_init(void)
+{
+	_omap_sram_reprogram_clock = omap_sram_push(sram_reprogram_clock,
+						    sram_reprogram_clock_sz);
+
+	return 0;
+}
+
+#else
+#define omap1_sram_init()	do {} while (0)
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+
+static void (*_omap2_sram_ddr_init)(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
+			      u32 base_cs, u32 force_unlock);
+
+void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
+		   u32 base_cs, u32 force_unlock)
+{
+	if (!_omap2_sram_ddr_init)
+		omap_sram_error();
+
+	return _omap2_sram_ddr_init(slow_dll_ctrl, fast_dll_ctrl,
+				    base_cs, force_unlock);
+}
+
+static void (*_omap2_sram_reprogram_sdrc)(u32 perf_level, u32 dll_val,
+					  u32 mem_type);
+
+void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val, u32 mem_type)
+{
+	if (!_omap2_sram_reprogram_sdrc)
+		omap_sram_error();
+
+	return _omap2_sram_reprogram_sdrc(perf_level, dll_val, mem_type);
+}
+
+static u32 (*_omap2_set_prcm)(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
+
+u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass)
+{
+	if (!_omap2_set_prcm)
+		omap_sram_error();
+
+	return _omap2_set_prcm(dpll_ctrl_val, sdrc_rfr_val, bypass);
+}
+
+int __init omap2_sram_init(void)
+{
+	_omap2_sram_ddr_init = omap_sram_push(sram_ddr_init, sram_ddr_init_sz);
+
+	_omap2_sram_reprogram_sdrc = omap_sram_push(sram_reprogram_sdrc,
+						    sram_reprogram_sdrc_sz);
+	_omap2_set_prcm = omap_sram_push(sram_set_prcm, sram_set_prcm_sz);
+
+	return 0;
+}
+#else
+#define omap2_sram_init()	do {} while (0)
+#endif
+
+int __init omap_sram_init(void)
 {
 	omap_detect_sram();
 	omap_map_sram();
-	_omap_sram_reprogram_clock = omap_sram_push(sram_reprogram_clock,
-						    sram_reprogram_clock_sz);
+
+	if (!cpu_is_omap24xx())
+		omap1_sram_init();
+	else
+		omap2_sram_init();
+
+	return 0;
 }
diff --git a/arch/arm/plat-omap/sram.h b/arch/arm/plat-omap/sram.h
deleted file mode 100644
index 71984ef..0000000
--- a/arch/arm/plat-omap/sram.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * linux/arch/arm/plat-omap/sram.h
- *
- * Interface for functions that need to be run in internal SRAM
- *
- * 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 __ARCH_ARM_OMAP_SRAM_H
-#define __ARCH_ARM_OMAP_SRAM_H
-
-extern void * omap_sram_push(void * start, unsigned long size);
-extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
-
-/* Do not use these */
-extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
-extern unsigned long sram_reprogram_clock_sz;
-
-#endif
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index 205e2d0..00afc7a 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -91,6 +91,8 @@
 
 /*-------------------------------------------------------------------------*/
 
+#if defined(CONFIG_ARCH_OMAP_OTG) || defined(CONFIG_ARCH_OMAP15XX)
+
 static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
 {
 	u32	syscon1 = 0;
@@ -271,6 +273,8 @@
 	return syscon1 << 24;
 }
 
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 #if	defined(CONFIG_USB_GADGET_OMAP) || \
@@ -494,7 +498,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef	CONFIG_ARCH_OMAP1510
+#ifdef	CONFIG_ARCH_OMAP15XX
 
 #define ULPD_DPLL_CTRL_REG	__REG16(ULPD_DPLL_CTRL)
 #define DPLL_IOB		(1 << 13)
@@ -507,7 +511,6 @@
 
 static void __init omap_1510_usb_init(struct omap_usb_config *config)
 {
-	int status;
 	unsigned int val;
 
 	omap_usb0_init(config->pins[0], is_usb0_device(config));
@@ -539,6 +542,8 @@
 
 #ifdef	CONFIG_USB_GADGET_OMAP
 	if (config->register_dev) {
+		int status;
+
 		udc_device.dev.platform_data = config;
 		status = platform_device_register(&udc_device);
 		if (status)
@@ -549,6 +554,8 @@
 
 #if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
 	if (config->register_host) {
+		int status;
+
 		ohci_device.dev.platform_data = config;
 		status = platform_device_register(&ohci_device);
 		if (status)
diff --git a/arch/arm26/kernel/process.c b/arch/arm26/kernel/process.c
index 9eb9964..15833a0 100644
--- a/arch/arm26/kernel/process.c
+++ b/arch/arm26/kernel/process.c
@@ -74,15 +74,13 @@
 void cpu_idle(void)
 {
 	/* endless idle loop with no priority at all */
-	preempt_disable();
 	while (1) {
-		while (!need_resched()) {
-			local_irq_disable();
-			if (!need_resched() && !hlt_counter)
-				local_irq_enable();
-		}
+		while (!need_resched())
+			cpu_relax();
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
 	}
-	schedule();
 }
 
 static char reboot_mode = 'h';
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c
index 201f4c9..f2c5574 100644
--- a/arch/cris/arch-v10/drivers/pcf8563.c
+++ b/arch/cris/arch-v10/drivers/pcf8563.c
@@ -19,7 +19,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c
index 094ff45..cac05a5 100644
--- a/arch/cris/arch-v10/kernel/fasttimer.c
+++ b/arch/cris/arch-v10/kernel/fasttimer.c
@@ -112,7 +112,6 @@
 #include <asm/rtc.h>
 
 #include <linux/config.h>
-#include <linux/version.h>
 
 #include <asm/arch/svinto.h>
 #include <asm/fasttimer.h>
diff --git a/arch/cris/arch-v32/drivers/nandflash.c b/arch/cris/arch-v32/drivers/nandflash.c
index fc2a619..93ddea4d 100644
--- a/arch/cris/arch-v32/drivers/nandflash.c
+++ b/arch/cris/arch-v32/drivers/nandflash.c
@@ -14,7 +14,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c
index f894580..d788bda 100644
--- a/arch/cris/arch-v32/drivers/pcf8563.c
+++ b/arch/cris/arch-v32/drivers/pcf8563.c
@@ -18,7 +18,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
index 957f551..13867f4 100644
--- a/arch/cris/arch-v32/kernel/smp.c
+++ b/arch/cris/arch-v32/kernel/smp.c
@@ -161,6 +161,7 @@
 	REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask);
 	unmask_irq(IPI_INTR_VECT);
 	unmask_irq(TIMER_INTR_VECT);
+	preempt_disable();
 	local_irq_enable();
 
 	cpu_set(cpu, cpu_online_map);
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
index 949a0e4..7c80afb 100644
--- a/arch/cris/kernel/process.c
+++ b/arch/cris/kernel/process.c
@@ -218,7 +218,9 @@
 				idle = default_idle;
 			idle();
 		}
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index 3001b82..54a4521 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -77,16 +77,20 @@
  */
 void cpu_idle(void)
 {
+	int cpu = smp_processor_id();
+
 	/* endless idle loop with no priority at all */
 	while (1) {
 		while (!need_resched()) {
-			irq_stat[smp_processor_id()].idle_timestamp = jiffies;
+			irq_stat[cpu].idle_timestamp = jiffies;
 
 			if (!frv_dma_inprogress && idle)
 				idle();
 		}
 
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index 27f1fce..fe21adf 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -53,22 +53,18 @@
 #if !defined(CONFIG_H8300H_SIM) && !defined(CONFIG_H8S_SIM)
 void default_idle(void)
 {
-	while(1) {
-		if (!need_resched()) {
-			local_irq_enable();
-			__asm__("sleep");
-			local_irq_disable();
-		}
-		schedule();
-	}
+	local_irq_disable();
+	if (!need_resched()) {
+		local_irq_enable();
+		/* XXX: race here! What if need_resched() gets set now? */
+		__asm__("sleep");
+	} else
+		local_irq_enable();
 }
 #else
 void default_idle(void)
 {
-	while(1) {
-		if (need_resched())
-			schedule();
-	}
+	cpu_relax();
 }
 #endif
 void (*idle)(void) = default_idle;
@@ -81,7 +77,13 @@
  */
 void cpu_idle(void)
 {
-	idle();
+	while (1) {
+		while (!need_resched())
+			idle();
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+	}
 }
 
 void machine_restart(char * __unused)
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 86e80c5..003548b 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -769,8 +769,26 @@
 static int apm_do_idle(void)
 {
 	u32	eax;
+	u8	ret = 0;
+	int	idled = 0;
+	int	polling;
 
-	if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax)) {
+	polling = test_thread_flag(TIF_POLLING_NRFLAG);
+	if (polling) {
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+		smp_mb__after_clear_bit();
+	}
+	if (!need_resched()) {
+		idled = 1;
+		ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax);
+	}
+	if (polling)
+		set_thread_flag(TIF_POLLING_NRFLAG);
+
+	if (!idled)
+		return 0;
+
+	if (ret) {
 		static unsigned long t;
 
 		/* This always fails on some SMP boards running UP kernels.
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 7a14fdf..1cb261f 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -99,14 +99,22 @@
  */
 void default_idle(void)
 {
+	local_irq_enable();
+
 	if (!hlt_counter && boot_cpu_data.hlt_works_ok) {
-		local_irq_disable();
-		if (!need_resched())
-			safe_halt();
-		else
-			local_irq_enable();
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+		smp_mb__after_clear_bit();
+		while (!need_resched()) {
+			local_irq_disable();
+			if (!need_resched())
+				safe_halt();
+			else
+				local_irq_enable();
+		}
+		set_thread_flag(TIF_POLLING_NRFLAG);
 	} else {
-		cpu_relax();
+		while (!need_resched())
+			cpu_relax();
 	}
 }
 #ifdef CONFIG_APM_MODULE
@@ -120,29 +128,14 @@
  */
 static void poll_idle (void)
 {
-	int oldval;
-
 	local_irq_enable();
 
-	/*
-	 * Deal with another CPU just having chosen a thread to
-	 * run here:
-	 */
-	oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
-	if (!oldval) {
-		set_thread_flag(TIF_POLLING_NRFLAG);
-		asm volatile(
-			"2:"
-			"testl %0, %1;"
-			"rep; nop;"
-			"je 2b;"
-			: : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));
-
-		clear_thread_flag(TIF_POLLING_NRFLAG);
-	} else {
-		set_need_resched();
-	}
+	asm volatile(
+		"2:"
+		"testl %0, %1;"
+		"rep; nop;"
+		"je 2b;"
+		: : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -179,7 +172,9 @@
  */
 void cpu_idle(void)
 {
-	int cpu = raw_smp_processor_id();
+	int cpu = smp_processor_id();
+
+	set_thread_flag(TIF_POLLING_NRFLAG);
 
 	/* endless idle loop with no priority at all */
 	while (1) {
@@ -201,7 +196,9 @@
 			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
 			idle();
 		}
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
@@ -244,15 +241,12 @@
 {
 	local_irq_enable();
 
-	if (!need_resched()) {
-		set_thread_flag(TIF_POLLING_NRFLAG);
-		do {
-			__monitor((void *)&current_thread_info()->flags, 0, 0);
-			if (need_resched())
-				break;
-			__mwait(0, 0);
-		} while (!need_resched());
-		clear_thread_flag(TIF_POLLING_NRFLAG);
+	while (!need_resched()) {
+		__monitor((void *)&current_thread_info()->flags, 0, 0);
+		smp_mb();
+		if (need_resched())
+			break;
+		__mwait(0, 0);
 	}
 }
 
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index b48ac635..fdfcb0c 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -129,9 +129,7 @@
 EXPORT_SYMBOL(drive_info);
 #endif
 struct screen_info screen_info;
-#ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
-#endif
 struct apm_info apm_info;
 EXPORT_SYMBOL(apm_info);
 struct sys_desc_table_struct {
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 47ec76794..bc5a9d9 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -485,6 +485,7 @@
 	 * things done here to the most necessary things.
 	 */
 	cpu_init();
+	preempt_disable();
 	smp_callin();
 	while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
 		rep_nop();
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
index 3984226..eeb1b1f2d 100644
--- a/arch/i386/pci/fixup.c
+++ b/arch/i386/pci/fixup.c
@@ -433,9 +433,8 @@
 		return; /* only applies to certain Toshibas (so far) */
 
 	/* Restore config space on Toshiba laptops */
-	mdelay(10);
 	pci_write_config_word(dev, PCI_CACHE_LINE_SIZE, toshiba_line_size);
-	pci_write_config_word(dev, PCI_INTERRUPT_LINE, dev->irq);
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, (u8 *)&dev->irq);
 	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
 			       pci_resource_start(dev, 0));
 	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1,
diff --git a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c
index 164b211..8873939 100644
--- a/arch/ia64/ia32/ia32_ioctl.c
+++ b/arch/ia64/ia32/ia32_ioctl.c
@@ -29,10 +29,8 @@
 #define CODE
 #include "compat_ioctl.c"
 
-typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
-
 #define COMPATIBLE_IOCTL(cmd)		HANDLE_IOCTL((cmd),sys_ioctl)
-#define HANDLE_IOCTL(cmd,handler)	{ (cmd), (ioctl32_handler_t)(handler), NULL },
+#define HANDLE_IOCTL(cmd,handler)	{ (cmd), (ioctl_trans_handler_t)(handler), NULL },
 #define IOCTL_TABLE_START \
 	struct ioctl_trans ioctl_start[] = {
 #define IOCTL_TABLE_END \
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index f72ea6a..a3aa45c 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -987,7 +987,7 @@
 				break;
 		}
 
-		if ((res = kcalloc(1, sizeof(struct resource), GFP_KERNEL)) == NULL) {
+		if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {
 			printk(KERN_ERR "failed to alocate resource for iomem\n");
 			return;
 		}
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 96736a1..801eeae 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -347,7 +347,7 @@
 		((struct fnptr *)kretprobe_trampoline)->ip;
 
 	spin_lock_irqsave(&kretprobe_lock, flags);
-        head = kretprobe_inst_table_head(current);
+	head = kretprobe_inst_table_head(current);
 
 	/*
 	 * It is possible to have multiple instances associated with a given
@@ -363,9 +363,9 @@
 	 *       kretprobe_trampoline
 	 */
 	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
-                if (ri->task != current)
+		if (ri->task != current)
 			/* another task is sharing our hash bucket */
-                        continue;
+			continue;
 
 		if (ri->rp && ri->rp->handler)
 			ri->rp->handler(ri, regs);
@@ -394,7 +394,7 @@
 	 * kprobe_handler() that we don't want the post_handler
 	 * to run (and have re-enabled preemption)
 	 */
-        return 1;
+	return 1;
 }
 
 /* Called with kretprobe_lock held */
@@ -739,12 +739,16 @@
 
 	switch(val) {
 	case DIE_BREAK:
-		if (pre_kprobes_handler(args))
-			ret = NOTIFY_STOP;
+		/* err is break number from ia64_bad_break() */
+		if (args->err == 0x80200 || args->err == 0x80300)
+			if (pre_kprobes_handler(args))
+				ret = NOTIFY_STOP;
 		break;
-	case DIE_SS:
-		if (post_kprobes_handler(args->regs))
-			ret = NOTIFY_STOP;
+	case DIE_FAULT:
+		/* err is vector number from ia64_fault() */
+		if (args->err == 36)
+			if (post_kprobes_handler(args->regs))
+				ret = NOTIFY_STOP;
 		break;
 	case DIE_PAGE_FAULT:
 		/* kprobe_running() needs smp_processor_id() */
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 52c47da..355af15 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -51,6 +51,9 @@
  *
  * 2005-08-12 Keith Owens <kaos@sgi.com>
  *	      Convert MCA/INIT handlers to use per event stacks and SAL/OS state.
+ *
+ * 2005-10-07 Keith Owens <kaos@sgi.com>
+ *	      Add notify_die() hooks.
  */
 #include <linux/config.h>
 #include <linux/types.h>
@@ -58,7 +61,6 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/kallsyms.h>
 #include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
@@ -69,6 +71,7 @@
 #include <linux/workqueue.h>
 
 #include <asm/delay.h>
+#include <asm/kdebug.h>
 #include <asm/machvec.h>
 #include <asm/meminit.h>
 #include <asm/page.h>
@@ -132,6 +135,14 @@
 
 static int mca_init;
 
+
+static void inline
+ia64_mca_spin(const char *func)
+{
+	printk(KERN_EMERG "%s: spinning here, not returning to SAL\n", func);
+	while (1)
+		cpu_relax();
+}
 /*
  * IA64_MCA log support
  */
@@ -526,13 +537,16 @@
  *  Outputs :   None
  */
 static irqreturn_t
-ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
+ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs)
 {
 	unsigned long flags;
 	int cpu = smp_processor_id();
 
 	/* Mask all interrupts */
 	local_irq_save(flags);
+	if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, 0, 0, 0)
+			== NOTIFY_STOP)
+		ia64_mca_spin(__FUNCTION__);
 
 	ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE;
 	/* Register with the SAL monarch that the slave has
@@ -540,10 +554,18 @@
 	 */
 	ia64_sal_mc_rendez();
 
+	if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, 0, 0, 0)
+			== NOTIFY_STOP)
+		ia64_mca_spin(__FUNCTION__);
+
 	/* Wait for the monarch cpu to exit. */
 	while (monarch_cpu != -1)
 	       cpu_relax();	/* spin until monarch leaves */
 
+	if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, 0, 0, 0)
+			== NOTIFY_STOP)
+		ia64_mca_spin(__FUNCTION__);
+
 	/* Enable all interrupts */
 	local_irq_restore(flags);
 	return IRQ_HANDLED;
@@ -933,6 +955,9 @@
 	oops_in_progress = 1;	/* FIXME: make printk NMI/MCA/INIT safe */
 	previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA");
 	monarch_cpu = cpu;
+	if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0)
+			== NOTIFY_STOP)
+		ia64_mca_spin(__FUNCTION__);
 	ia64_wait_for_slaves(cpu);
 
 	/* Wakeup all the processors which are spinning in the rendezvous loop.
@@ -942,6 +967,9 @@
 	 * spinning in SAL does not work.
 	 */
 	ia64_mca_wakeup_all();
+	if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, 0, 0, 0)
+			== NOTIFY_STOP)
+		ia64_mca_spin(__FUNCTION__);
 
 	/* Get the MCA error record and log it */
 	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
@@ -960,6 +988,9 @@
 		ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA);
 		sos->os_status = IA64_MCA_CORRECTED;
 	}
+	if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, 0, 0, recover)
+			== NOTIFY_STOP)
+		ia64_mca_spin(__FUNCTION__);
 
 	set_curr_task(cpu, previous_current);
 	monarch_cpu = -1;
@@ -1188,6 +1219,37 @@
 
 #endif /* CONFIG_ACPI */
 
+static int
+default_monarch_init_process(struct notifier_block *self, unsigned long val, void *data)
+{
+	int c;
+	struct task_struct *g, *t;
+	if (val != DIE_INIT_MONARCH_PROCESS)
+		return NOTIFY_DONE;
+	printk(KERN_ERR "Processes interrupted by INIT -");
+	for_each_online_cpu(c) {
+		struct ia64_sal_os_state *s;
+		t = __va(__per_cpu_mca[c] + IA64_MCA_CPU_INIT_STACK_OFFSET);
+		s = (struct ia64_sal_os_state *)((char *)t + MCA_SOS_OFFSET);
+		g = s->prev_task;
+		if (g) {
+			if (g->pid)
+				printk(" %d", g->pid);
+			else
+				printk(" %d (cpu %d task 0x%p)", g->pid, task_cpu(g), g);
+		}
+	}
+	printk("\n\n");
+	if (read_trylock(&tasklist_lock)) {
+		do_each_thread (g, t) {
+			printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm);
+			show_stack(t, NULL);
+		} while_each_thread (g, t);
+		read_unlock(&tasklist_lock);
+	}
+	return NOTIFY_DONE;
+}
+
 /*
  * C portion of the OS INIT handler
  *
@@ -1212,8 +1274,7 @@
 	static atomic_t slaves;
 	static atomic_t monarchs;
 	task_t *previous_current;
-	int cpu = smp_processor_id(), c;
-	struct task_struct *g, *t;
+	int cpu = smp_processor_id();
 
 	oops_in_progress = 1;	/* FIXME: make printk NMI/MCA/INIT safe */
 	console_loglevel = 15;	/* make sure printks make it to console */
@@ -1253,8 +1314,17 @@
 		ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT;
 		while (monarch_cpu == -1)
 		       cpu_relax();	/* spin until monarch enters */
+		if (notify_die(DIE_INIT_SLAVE_ENTER, "INIT", regs, 0, 0, 0)
+				== NOTIFY_STOP)
+			ia64_mca_spin(__FUNCTION__);
+		if (notify_die(DIE_INIT_SLAVE_PROCESS, "INIT", regs, 0, 0, 0)
+				== NOTIFY_STOP)
+			ia64_mca_spin(__FUNCTION__);
 		while (monarch_cpu != -1)
 		       cpu_relax();	/* spin until monarch leaves */
+		if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, 0, 0, 0)
+				== NOTIFY_STOP)
+			ia64_mca_spin(__FUNCTION__);
 		printk("Slave on cpu %d returning to normal service.\n", cpu);
 		set_curr_task(cpu, previous_current);
 		ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
@@ -1263,6 +1333,9 @@
 	}
 
 	monarch_cpu = cpu;
+	if (notify_die(DIE_INIT_MONARCH_ENTER, "INIT", regs, 0, 0, 0)
+			== NOTIFY_STOP)
+		ia64_mca_spin(__FUNCTION__);
 
 	/*
 	 * Wait for a bit.  On some machines (e.g., HP's zx2000 and zx6000, INIT can be
@@ -1273,27 +1346,16 @@
 	printk("Delaying for 5 seconds...\n");
 	udelay(5*1000000);
 	ia64_wait_for_slaves(cpu);
-	printk(KERN_ERR "Processes interrupted by INIT -");
-	for_each_online_cpu(c) {
-		struct ia64_sal_os_state *s;
-		t = __va(__per_cpu_mca[c] + IA64_MCA_CPU_INIT_STACK_OFFSET);
-		s = (struct ia64_sal_os_state *)((char *)t + MCA_SOS_OFFSET);
-		g = s->prev_task;
-		if (g) {
-			if (g->pid)
-				printk(" %d", g->pid);
-			else
-				printk(" %d (cpu %d task 0x%p)", g->pid, task_cpu(g), g);
-		}
-	}
-	printk("\n\n");
-	if (read_trylock(&tasklist_lock)) {
-		do_each_thread (g, t) {
-			printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm);
-			show_stack(t, NULL);
-		} while_each_thread (g, t);
-		read_unlock(&tasklist_lock);
-	}
+	/* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through
+	 * to default_monarch_init_process() above and just print all the
+	 * tasks.
+	 */
+	if (notify_die(DIE_INIT_MONARCH_PROCESS, "INIT", regs, 0, 0, 0)
+			== NOTIFY_STOP)
+		ia64_mca_spin(__FUNCTION__);
+	if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, 0, 0, 0)
+			== NOTIFY_STOP)
+		ia64_mca_spin(__FUNCTION__);
 	printk("\nINIT dump complete.  Monarch on cpu %d returning to normal service.\n", cpu);
 	atomic_dec(&monarchs);
 	set_curr_task(cpu, previous_current);
@@ -1462,6 +1524,10 @@
 	s64 rc;
 	struct ia64_sal_retval isrv;
 	u64 timeout = IA64_MCA_RENDEZ_TIMEOUT;	/* platform specific */
+	static struct notifier_block default_init_monarch_nb = {
+		.notifier_call = default_monarch_init_process,
+		.priority = 0/* we need to notified last */
+	};
 
 	IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__);
 
@@ -1555,6 +1621,10 @@
 		       "(status %ld)\n", rc);
 		return;
 	}
+	if (register_die_notifier(&default_init_monarch_nb)) {
+		printk(KERN_ERR "Failed to register default monarch INIT process\n");
+		return;
+	}
 
 	IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__);
 
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index f081c60..3492e32 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -88,7 +88,7 @@
 	if (!ia64_phys_addr_valid(paddr))
 		return ISOLATE_NONE;
 
-	if (!pfn_valid(paddr))
+	if (!pfn_valid(paddr >> PAGE_SHIFT))
 		return ISOLATE_NONE;
 
 	/* convert physical address to physical page number */
@@ -108,6 +108,7 @@
 		return ISOLATE_NG;
 
 	/* add attribute 'Reserved' and register the page */
+	get_page(p);
 	SetPageReserved(p);
 	page_isolate[num_page_isolate++] = p;
 
@@ -546,9 +547,20 @@
 		(pal_processor_state_info_t*)peidx_psp(peidx);
 
 	/*
-	 * We cannot recover errors with other than bus_check.
+	 * Processor recovery status must key off of the PAL recovery
+	 * status in the Processor State Parameter.
 	 */
-	if (psp->cc || psp->rc || psp->uc)
+
+	/*
+	 * The machine check is corrected.
+	 */
+	if (psp->cm == 1)
+		return 1;
+
+	/*
+	 * The error was not contained.  Software must be reset.
+	 */
+	if (psp->us || psp->ci == 0)
 		return 0;
 
 	/*
@@ -569,8 +581,6 @@
 		return 0;
 	if (pbci->eb && pbci->bsi > 0)
 		return 0;
-	if (psp->ci == 0)
-		return 0;
 
 	/*
 	 * This is a local MCA and estimated as recoverble external bus error.
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 051e050..e92ea64 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -4,6 +4,9 @@
  * Copyright (C) 1998-2003 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  * 04/11/17 Ashok Raj	<ashok.raj@intel.com> Added CPU Hotplug Support
+ *
+ * 2005-10-07 Keith Owens <kaos@sgi.com>
+ *	      Add notify_die() hooks.
  */
 #define __KERNEL_SYSCALLS__	/* see <asm/unistd.h> */
 #include <linux/config.h>
@@ -34,6 +37,7 @@
 #include <asm/elf.h>
 #include <asm/ia32.h>
 #include <asm/irq.h>
+#include <asm/kdebug.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/sal.h>
@@ -197,11 +201,15 @@
 default_idle (void)
 {
 	local_irq_enable();
-	while (!need_resched())
-		if (can_do_pal_halt)
-			safe_halt();
-		else
+	while (!need_resched()) {
+		if (can_do_pal_halt) {
+			local_irq_disable();
+			if (!need_resched())
+				safe_halt();
+			local_irq_enable();
+		} else
 			cpu_relax();
+	}
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -263,16 +271,16 @@
 cpu_idle (void)
 {
 	void (*mark_idle)(int) = ia64_mark_idle;
+  	int cpu = smp_processor_id();
+	set_thread_flag(TIF_POLLING_NRFLAG);
 
 	/* endless idle loop with no priority at all */
 	while (1) {
+		if (!need_resched()) {
+			void (*idle)(void);
 #ifdef CONFIG_SMP
-		if (!need_resched())
 			min_xtp();
 #endif
-		while (!need_resched()) {
-			void (*idle)(void);
-
 			if (__get_cpu_var(cpu_idle_state))
 				__get_cpu_var(cpu_idle_state) = 0;
 
@@ -284,17 +292,17 @@
 			if (!idle)
 				idle = default_idle;
 			(*idle)();
-		}
-
-		if (mark_idle)
-			(*mark_idle)(0);
-
+			if (mark_idle)
+				(*mark_idle)(0);
 #ifdef CONFIG_SMP
-		normal_xtp();
+			normal_xtp();
 #endif
+		}
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 		check_pgt_cache();
-		if (cpu_is_offline(smp_processor_id()))
+		if (cpu_is_offline(cpu))
 			play_dead();
 	}
 }
@@ -804,12 +812,14 @@
 void
 machine_restart (char *restart_cmd)
 {
+	(void) notify_die(DIE_MACHINE_RESTART, restart_cmd, NULL, 0, 0, 0);
 	(*efi.reset_system)(EFI_RESET_WARM, 0, 0, NULL);
 }
 
 void
 machine_halt (void)
 {
+	(void) notify_die(DIE_MACHINE_HALT, "", NULL, 0, 0, 0);
 	cpu_halt();
 }
 
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 3af6de3..5add0bc 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -461,6 +461,7 @@
 #endif
 
 	cpu_init();	/* initialize the bootstrap CPU */
+	mmu_context_init();	/* initialize context_id bitmap */
 
 #ifdef CONFIG_ACPI
 	acpi_boot_init();
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 774f34b..58ce07e 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -387,15 +387,14 @@
 	     struct sigscratch *scr)
 {
 	extern char __kernel_sigtramp[];
-	unsigned long tramp_addr, new_rbs = 0;
+	unsigned long tramp_addr, new_rbs = 0, new_sp;
 	struct sigframe __user *frame;
 	long err;
 
-	frame = (void __user *) scr->pt.r12;
+	new_sp = scr->pt.r12;
 	tramp_addr = (unsigned long) __kernel_sigtramp;
-	if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) {
-		frame = (void __user *) ((current->sas_ss_sp + current->sas_ss_size)
-					 & ~(STACK_ALIGN - 1));
+	if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(new_sp) == 0) {
+		new_sp = current->sas_ss_sp + current->sas_ss_size;
 		/*
 		 * We need to check for the register stack being on the signal stack
 		 * separately, because it's switched separately (memory stack is switched
@@ -404,7 +403,7 @@
 		if (!rbs_on_sig_stack(scr->pt.ar_bspstore))
 			new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
 	}
-	frame = (void __user *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1));
+	frame = (void __user *) ((new_sp - sizeof(*frame)) & -STACK_ALIGN);
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		return force_sigsegv_info(sig, frame);
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 400a489..8f44e7d 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -399,6 +399,7 @@
 	Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id());
 	efi_map_pal_code();
 	cpu_init();
+	preempt_disable();
 	smp_callin();
 
 	cpu_idle();
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index f970359..fba5fdd 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -30,17 +30,20 @@
 EXPORT_SYMBOL(fpswa_interface);
 
 struct notifier_block *ia64die_chain;
-static DEFINE_SPINLOCK(die_notifier_lock);
 
-int register_die_notifier(struct notifier_block *nb)
+int
+register_die_notifier(struct notifier_block *nb)
 {
-	int err = 0;
-	unsigned long flags;
-	spin_lock_irqsave(&die_notifier_lock, flags);
-	err = notifier_chain_register(&ia64die_chain, nb);
-	spin_unlock_irqrestore(&die_notifier_lock, flags);
-	return err;
+	return notifier_chain_register(&ia64die_chain, nb);
 }
+EXPORT_SYMBOL_GPL(register_die_notifier);
+
+int
+unregister_die_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&ia64die_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_die_notifier);
 
 void __init
 trap_init (void)
@@ -105,6 +108,7 @@
 	if (++die.lock_owner_depth < 3) {
 		printk("%s[%d]: %s %ld [%d]\n",
 			current->comm, current->pid, str, err, ++die_counter);
+		(void) notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
 		show_regs(regs);
   	} else
 		printk(KERN_ERR "Recursive die() failure, output suppressed\n");
@@ -155,9 +159,8 @@
 	switch (break_num) {
 	      case 0: /* unknown error (used by GCC for __builtin_abort()) */
 		if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP)
-			       	== NOTIFY_STOP) {
+			       	== NOTIFY_STOP)
 			return;
-		}
 		die_if_kernel("bugcheck!", regs, break_num);
 		sig = SIGILL; code = ILL_ILLOPC;
 		break;
@@ -210,15 +213,6 @@
 		sig = SIGILL; code = __ILL_BNDMOD;
 		break;
 
-	      case 0x80200:
-	      case 0x80300:
-		if (notify_die(DIE_BREAK, "kprobe", regs, break_num, TRAP_BRKPT, SIGTRAP)
-			       	== NOTIFY_STOP) {
-			return;
-		}
-		sig = SIGTRAP; code = TRAP_BRKPT;
-		break;
-
 	      default:
 		if (break_num < 0x40000 || break_num > 0x100000)
 			die_if_kernel("Bad break", regs, break_num);
@@ -226,6 +220,9 @@
 		if (break_num < 0x80000) {
 			sig = SIGILL; code = __ILL_BREAK;
 		} else {
+			if (notify_die(DIE_BREAK, "bad break", regs, break_num, TRAP_BRKPT, SIGTRAP)
+					== NOTIFY_STOP)
+				return;
 			sig = SIGTRAP; code = TRAP_BRKPT;
 		}
 	}
@@ -578,12 +575,11 @@
 #endif
 			break;
 		      case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
-		      case 36:
-			      if (notify_die(DIE_SS, "ss", &regs, vector,
-					     vector, SIGTRAP) == NOTIFY_STOP)
-				      return;
-			      siginfo.si_code = TRAP_TRACE; ifa = 0; break;
+		      case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
 		}
+		if (notify_die(DIE_FAULT, "ia64_fault", &regs, vector, siginfo.si_code, SIGTRAP)
+			       	== NOTIFY_STOP)
+			return;
 		siginfo.si_signo = SIGTRAP;
 		siginfo.si_errno = 0;
 		siginfo.si_addr  = (void __user *) ifa;
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index a88cdb7..0f776b0 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -350,14 +350,12 @@
  *	for best.
  * @nid: node id
  * @pernodesize: size of this node's pernode data
- * @align: alignment to use for this node's pernode data
  */
-static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize,
-	unsigned long align)
+static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize)
 {
 	void *ptr = NULL;
 	u8 best = 0xff;
-	int bestnode = -1, node;
+	int bestnode = -1, node, anynode = 0;
 
 	for_each_online_node(node) {
 		if (node_isset(node, memory_less_mask))
@@ -366,13 +364,15 @@
 			best = node_distance(nid, node);
 			bestnode = node;
 		}
+		anynode = node;
 	}
 
-	ptr = __alloc_bootmem_node(mem_data[bestnode].pgdat,
-		pernodesize, align, __pa(MAX_DMA_ADDRESS));
+	if (bestnode == -1)
+		bestnode = anynode;
 
-	if (!ptr)
-		panic("NO memory for memory less node\n");
+	ptr = __alloc_bootmem_node(mem_data[bestnode].pgdat, pernodesize,
+		PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
+
 	return ptr;
 }
 
@@ -413,8 +413,7 @@
 
 	for_each_node_mask(node, memory_less_mask) {
 		pernodesize = compute_pernodesize(node);
-		pernode = memory_less_node_alloc(node, pernodesize,
-			(node) ? (node * PERCPU_PAGE_SIZE) : (1024*1024));
+		pernode = memory_less_node_alloc(node, pernodesize);
 		fill_pernode(node, __pa(pernode), pernodesize);
 	}
 
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
index c79a9b9..41105d4 100644
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -8,6 +8,8 @@
  *		Modified RID allocation for SMP
  *          Goutham Rao <goutham.rao@intel.com>
  *              IPI based ptc implementation and A-step IPI implementation.
+ * Rohit Seth <rohit.seth@intel.com>
+ * Ken Chen <kenneth.w.chen@intel.com>
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -16,78 +18,75 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
+#include <linux/bootmem.h>
 
 #include <asm/delay.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 #include <asm/pal.h>
 #include <asm/tlbflush.h>
+#include <asm/dma.h>
 
 static struct {
 	unsigned long mask;	/* mask of supported purge page-sizes */
-	unsigned long max_bits;	/* log2() of largest supported purge page-size */
+	unsigned long max_bits;	/* log2 of largest supported purge page-size */
 } purge;
 
 struct ia64_ctx ia64_ctx = {
 	.lock =		SPIN_LOCK_UNLOCKED,
 	.next =		1,
-	.limit =	(1 << 15) - 1,		/* start out with the safe (architected) limit */
 	.max_ctx =	~0U
 };
 
 DEFINE_PER_CPU(u8, ia64_need_tlb_flush);
 
 /*
+ * Initializes the ia64_ctx.bitmap array based on max_ctx+1.
+ * Called after cpu_init() has setup ia64_ctx.max_ctx based on
+ * maximum RID that is supported by boot CPU.
+ */
+void __init
+mmu_context_init (void)
+{
+	ia64_ctx.bitmap = alloc_bootmem((ia64_ctx.max_ctx+1)>>3);
+	ia64_ctx.flushmap = alloc_bootmem((ia64_ctx.max_ctx+1)>>3);
+}
+
+/*
  * Acquire the ia64_ctx.lock before calling this function!
  */
 void
 wrap_mmu_context (struct mm_struct *mm)
 {
-	unsigned long tsk_context, max_ctx = ia64_ctx.max_ctx;
-	struct task_struct *tsk;
-	int i;
+	int i, cpu;
+	unsigned long flush_bit;
 
-	if (ia64_ctx.next > max_ctx)
-		ia64_ctx.next = 300;	/* skip daemons */
-	ia64_ctx.limit = max_ctx + 1;
+	for (i=0; i <= ia64_ctx.max_ctx / BITS_PER_LONG; i++) {
+		flush_bit = xchg(&ia64_ctx.flushmap[i], 0);
+		ia64_ctx.bitmap[i] ^= flush_bit;
+	}
+ 
+	/* use offset at 300 to skip daemons */
+	ia64_ctx.next = find_next_zero_bit(ia64_ctx.bitmap,
+				ia64_ctx.max_ctx, 300);
+	ia64_ctx.limit = find_next_bit(ia64_ctx.bitmap,
+				ia64_ctx.max_ctx, ia64_ctx.next);
 
 	/*
-	 * Scan all the task's mm->context and set proper safe range
+	 * can't call flush_tlb_all() here because of race condition
+	 * with O(1) scheduler [EF]
 	 */
-
-	read_lock(&tasklist_lock);
-  repeat:
-	for_each_process(tsk) {
-		if (!tsk->mm)
-			continue;
-		tsk_context = tsk->mm->context;
-		if (tsk_context == ia64_ctx.next) {
-			if (++ia64_ctx.next >= ia64_ctx.limit) {
-				/* empty range: reset the range limit and start over */
-				if (ia64_ctx.next > max_ctx)
-					ia64_ctx.next = 300;
-				ia64_ctx.limit = max_ctx + 1;
-				goto repeat;
-			}
-		}
-		if ((tsk_context > ia64_ctx.next) && (tsk_context < ia64_ctx.limit))
-			ia64_ctx.limit = tsk_context;
-	}
-	read_unlock(&tasklist_lock);
-	/* can't call flush_tlb_all() here because of race condition with O(1) scheduler [EF] */
-	{
-		int cpu = get_cpu(); /* prevent preemption/migration */
-		for_each_online_cpu(i) {
-			if (i != cpu)
-				per_cpu(ia64_need_tlb_flush, i) = 1;
-		}
-		put_cpu();
-	}
+	cpu = get_cpu(); /* prevent preemption/migration */
+	for_each_online_cpu(i)
+		if (i != cpu)
+			per_cpu(ia64_need_tlb_flush, i) = 1;
+	put_cpu();
 	local_flush_tlb_all();
 }
 
 void
-ia64_global_tlb_purge (struct mm_struct *mm, unsigned long start, unsigned long end, unsigned long nbits)
+ia64_global_tlb_purge (struct mm_struct *mm, unsigned long start,
+		       unsigned long end, unsigned long nbits)
 {
 	static DEFINE_SPINLOCK(ptcg_lock);
 
@@ -135,7 +134,8 @@
 }
 
 void
-flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long end)
+flush_tlb_range (struct vm_area_struct *vma, unsigned long start,
+		 unsigned long end)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	unsigned long size = end - start;
@@ -149,7 +149,8 @@
 #endif
 
 	nbits = ia64_fls(size + 0xfff);
-	while (unlikely (((1UL << nbits) & purge.mask) == 0) && (nbits < purge.max_bits))
+	while (unlikely (((1UL << nbits) & purge.mask) == 0) &&
+			(nbits < purge.max_bits))
 		++nbits;
 	if (nbits > purge.max_bits)
 		nbits = purge.max_bits;
@@ -191,5 +192,5 @@
 	local_cpu_data->ptce_stride[0] = ptce_info.stride[0];
 	local_cpu_data->ptce_stride[1] = ptce_info.stride[1];
 
-	local_flush_tlb_all();		/* nuke left overs from bootstrapping... */
+	local_flush_tlb_all();	/* nuke left overs from bootstrapping... */
 }
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 017cfc3..20d76fa 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -95,7 +95,7 @@
 }
 
 static struct pci_raw_ops pci_sal_ops = {
-	.read = 	pci_sal_read,
+	.read =		pci_sal_read,
 	.write =	pci_sal_write
 };
 
@@ -137,35 +137,98 @@
 	return controller;
 }
 
-static u64 __devinit
-add_io_space (struct acpi_resource_address64 *addr)
+struct pci_root_info {
+	struct pci_controller *controller;
+	char *name;
+};
+
+static unsigned int
+new_space (u64 phys_base, int sparse)
 {
-	u64 offset;
-	int sparse = 0;
+	u64 mmio_base;
 	int i;
 
-	if (addr->address_translation_offset == 0)
-		return IO_SPACE_BASE(0);	/* part of legacy IO space */
+	if (phys_base == 0)
+		return 0;	/* legacy I/O port space */
 
-	if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION)
-		sparse = 1;
-
-	offset = (u64) ioremap(addr->address_translation_offset, 0);
+	mmio_base = (u64) ioremap(phys_base, 0);
 	for (i = 0; i < num_io_spaces; i++)
-		if (io_space[i].mmio_base == offset &&
+		if (io_space[i].mmio_base == mmio_base &&
 		    io_space[i].sparse == sparse)
-			return IO_SPACE_BASE(i);
+			return i;
 
 	if (num_io_spaces == MAX_IO_SPACES) {
-		printk("Too many IO port spaces\n");
+		printk(KERN_ERR "PCI: Too many IO port spaces "
+			"(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES);
 		return ~0;
 	}
 
 	i = num_io_spaces++;
-	io_space[i].mmio_base = offset;
+	io_space[i].mmio_base = mmio_base;
 	io_space[i].sparse = sparse;
 
-	return IO_SPACE_BASE(i);
+	return i;
+}
+
+static u64 __devinit
+add_io_space (struct pci_root_info *info, struct acpi_resource_address64 *addr)
+{
+	struct resource *resource;
+	char *name;
+	u64 base, min, max, base_port;
+	unsigned int sparse = 0, space_nr, len;
+
+	resource = kzalloc(sizeof(*resource), GFP_KERNEL);
+	if (!resource) {
+		printk(KERN_ERR "PCI: No memory for %s I/O port space\n",
+			info->name);
+		goto out;
+	}
+
+	len = strlen(info->name) + 32;
+	name = kzalloc(len, GFP_KERNEL);
+	if (!name) {
+		printk(KERN_ERR "PCI: No memory for %s I/O port space name\n",
+			info->name);
+		goto free_resource;
+	}
+
+	min = addr->min_address_range;
+	max = min + addr->address_length - 1;
+	if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION)
+		sparse = 1;
+
+	space_nr = new_space(addr->address_translation_offset, sparse);
+	if (space_nr == ~0)
+		goto free_name;
+
+	base = __pa(io_space[space_nr].mmio_base);
+	base_port = IO_SPACE_BASE(space_nr);
+	snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name,
+		base_port + min, base_port + max);
+
+	/*
+	 * The SDM guarantees the legacy 0-64K space is sparse, but if the
+	 * mapping is done by the processor (not the bridge), ACPI may not
+	 * mark it as sparse.
+	 */
+	if (space_nr == 0)
+		sparse = 1;
+
+	resource->name  = name;
+	resource->flags = IORESOURCE_MEM;
+	resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
+	resource->end   = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max);
+	insert_resource(&iomem_resource, resource);
+
+	return base_port;
+
+free_name:
+	kfree(name);
+free_resource:
+	kfree(resource);
+out:
+	return ~0;
 }
 
 static acpi_status __devinit resource_to_window(struct acpi_resource *resource,
@@ -205,11 +268,6 @@
 	return AE_OK;
 }
 
-struct pci_root_info {
-	struct pci_controller *controller;
-	char *name;
-};
-
 static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
 {
 	struct pci_root_info *info = data;
@@ -231,7 +289,7 @@
 	} else if (addr.resource_type == ACPI_IO_RANGE) {
 		flags = IORESOURCE_IO;
 		root = &ioport_resource;
-		offset = add_io_space(&addr);
+		offset = add_io_space(info, &addr);
 		if (offset == ~0)
 			return AE_OK;
 	} else
@@ -241,7 +299,7 @@
 	window->resource.name = info->name;
 	window->resource.flags = flags;
 	window->resource.start = addr.min_address_range + offset;
-	window->resource.end = addr.max_address_range + offset;
+	window->resource.end = window->resource.start + addr.address_length - 1;
 	window->resource.child = NULL;
 	window->offset = offset;
 
@@ -739,7 +797,7 @@
 {
 	int count = nr_released;
 
- 	count += (IA64_LAST_DEVICE_VECTOR - last);
+	count += (IA64_LAST_DEVICE_VECTOR - last);
 
 	return count;
 }
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index b4f5053..05e4ea8 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -349,7 +349,7 @@
 		return;		/*bus # does not exist */
 	prom_bussoft_ptr = __va(prom_bussoft_ptr);
 
- 	controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
+ 	controller = kzalloc(sizeof(struct pci_controller), GFP_KERNEL);
 	controller->segment = segment;
  	if (!controller)
  		BUG();
diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h
index fbcedc7..5483a9f 100644
--- a/arch/ia64/sn/kernel/xpc.h
+++ b/arch/ia64/sn/kernel/xpc.h
@@ -163,7 +163,7 @@
 	u8 version;
 	u64 heartbeat;
 	u64 heartbeating_to_mask;
-	u64 kdb_status;		/* 0 = machine running */
+	u64 heartbeat_offline;	/* if 0, heartbeat should be changing */
 	int act_nasid;
 	int act_phys_cpuid;
 	u64 vars_part_pa;
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
index cece3c7..b617236 100644
--- a/arch/ia64/sn/kernel/xpc_main.c
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -57,6 +57,7 @@
 #include <linux/reboot.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/sn_sal.h>
+#include <asm/kdebug.h>
 #include <asm/uaccess.h>
 #include "xpc.h"
 
@@ -188,6 +189,11 @@
 	.notifier_call = xpc_system_reboot,
 };
 
+static int xpc_system_die(struct notifier_block *, unsigned long, void *);
+static struct notifier_block xpc_die_notifier = {
+	.notifier_call = xpc_system_die,
+};
+
 
 /*
  * Timer function to enforce the timelimit on the partition disengage request.
@@ -997,6 +1003,9 @@
 	/* take ourselves off of the reboot_notifier_list */
 	(void) unregister_reboot_notifier(&xpc_reboot_notifier);
 
+	/* take ourselves off of the die_notifier list */
+	(void) unregister_die_notifier(&xpc_die_notifier);
+
 	/* close down protections for IPI operations */
 	xpc_restrict_IPI_ops();
 
@@ -1011,6 +1020,63 @@
 
 
 /*
+ * Called when the system is about to be either restarted or halted.
+ */
+static void
+xpc_die_disengage(void)
+{
+	struct xpc_partition *part;
+	partid_t partid;
+	unsigned long engaged;
+	long time, print_time, disengage_request_timeout;
+
+
+	/* keep xpc_hb_checker thread from doing anything (just in case) */
+	xpc_exiting = 1;
+
+	xpc_vars->heartbeating_to_mask = 0;  /* indicate we're deactivated */
+
+	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+		part = &xpc_partitions[partid];
+
+		if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->
+							remote_vars_version)) {
+
+			/* just in case it was left set by an earlier XPC */
+			xpc_clear_partition_engaged(1UL << partid);
+			continue;
+		}
+
+		if (xpc_partition_engaged(1UL << partid) ||
+					part->act_state != XPC_P_INACTIVE) {
+			xpc_request_partition_disengage(part);
+			xpc_mark_partition_disengaged(part);
+			xpc_IPI_send_disengage(part);
+		}
+	}
+
+	print_time = rtc_time();
+	disengage_request_timeout = print_time +
+		(xpc_disengage_request_timelimit * sn_rtc_cycles_per_second);
+
+	/* wait for all other partitions to disengage from us */
+
+	while ((engaged = xpc_partition_engaged(-1UL)) &&
+			(time = rtc_time()) < disengage_request_timeout) {
+
+		if (time >= print_time) {
+			dev_info(xpc_part, "waiting for remote partitions to "
+				"disengage, engaged=0x%lx\n", engaged);
+			print_time = time + (XPC_DISENGAGE_PRINTMSG_INTERVAL *
+						sn_rtc_cycles_per_second);
+		}
+	}
+	dev_info(xpc_part, "finished waiting for remote partitions to "
+				"disengage, engaged=0x%lx\n", engaged);
+}
+
+
+/*
  * This function is called when the system is being rebooted.
  */
 static int
@@ -1038,6 +1104,33 @@
 }
 
 
+/*
+ * This function is called when the system is being rebooted.
+ */
+static int
+xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
+{
+	switch (event) {
+	case DIE_MACHINE_RESTART:
+	case DIE_MACHINE_HALT:
+		xpc_die_disengage();
+		break;
+	case DIE_MCA_MONARCH_ENTER:
+	case DIE_INIT_MONARCH_ENTER:
+		xpc_vars->heartbeat++;
+		xpc_vars->heartbeat_offline = 1;
+		break;
+	case DIE_MCA_MONARCH_LEAVE:
+	case DIE_INIT_MONARCH_LEAVE:
+		xpc_vars->heartbeat++;
+		xpc_vars->heartbeat_offline = 0;
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+
 int __init
 xpc_init(void)
 {
@@ -1154,6 +1247,12 @@
 		dev_warn(xpc_part, "can't register reboot notifier\n");
 	}
 
+	/* add ourselves to the die_notifier list (i.e., ia64die_chain) */
+	ret = register_die_notifier(&xpc_die_notifier);
+	if (ret != 0) {
+		dev_warn(xpc_part, "can't register die notifier\n");
+	}
+
 
 	/*
 	 * Set the beating to other partitions into motion.  This is
@@ -1179,6 +1278,9 @@
 		/* take ourselves off of the reboot_notifier_list */
 		(void) unregister_reboot_notifier(&xpc_reboot_notifier);
 
+		/* take ourselves off of the die_notifier list */
+		(void) unregister_die_notifier(&xpc_die_notifier);
+
 		del_timer_sync(&xpc_hb_timer);
 		free_irq(SGI_XPC_ACTIVATE, NULL);
 		xpc_restrict_IPI_ops();
diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c
index 581e113..cdd6431 100644
--- a/arch/ia64/sn/kernel/xpc_partition.c
+++ b/arch/ia64/sn/kernel/xpc_partition.c
@@ -436,13 +436,13 @@
 		}
 
 		dev_dbg(xpc_part, "partid = %d, heartbeat = %ld, last_heartbeat"
-			" = %ld, kdb_status = %ld, HB_mask = 0x%lx\n", partid,
-			remote_vars->heartbeat, part->last_heartbeat,
-			remote_vars->kdb_status,
+			" = %ld, heartbeat_offline = %ld, HB_mask = 0x%lx\n",
+			partid, remote_vars->heartbeat, part->last_heartbeat,
+			remote_vars->heartbeat_offline,
 			remote_vars->heartbeating_to_mask);
 
 		if (((remote_vars->heartbeat == part->last_heartbeat) &&
-			(remote_vars->kdb_status == 0)) ||
+			(remote_vars->heartbeat_offline == 0)) ||
 			     !xpc_hb_allowed(sn_partition_id, remote_vars)) {
 
 			XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 7b03b80..1f500c8 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -212,13 +212,13 @@
 		    pdi_pcibus_info;
 
 		/* Disable the device's IRQ   */
-		pcireg_intr_enable_bit_clr(pcibus_info, bit);
+		pcireg_intr_enable_bit_clr(pcibus_info, (1 << bit));
 
 		/* Change the device's IRQ    */
 		pcireg_intr_addr_addr_set(pcibus_info, bit, xtalk_addr);
 
 		/* Re-enable the device's IRQ */
-		pcireg_intr_enable_bit_set(pcibus_info, bit);
+		pcireg_intr_enable_bit_set(pcibus_info, (1 << bit));
 
 		pcibr_force_interrupt(sn_irq_info);
 	}
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c
index 4f718c3..5d53409 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_reg.c
@@ -131,7 +131,7 @@
 			__sn_clrq_relaxed(&ptr->tio.cp_int_enable, bits);
 			break;
 		case PCIBR_BRIDGETYPE_PIC:
-			__sn_clrq_relaxed(&ptr->pic.p_int_enable, ~bits);
+			__sn_clrq_relaxed(&ptr->pic.p_int_enable, bits);
 			break;
 		default:
 			panic
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c
index 9f03d4e..dda196c 100644
--- a/arch/ia64/sn/pci/tioce_provider.c
+++ b/arch/ia64/sn/pci/tioce_provider.c
@@ -218,7 +218,7 @@
 	if (i > last)
 		return 0;
 
-	map = kcalloc(1, sizeof(struct tioce_dmamap), GFP_ATOMIC);
+	map = kzalloc(sizeof(struct tioce_dmamap), GFP_ATOMIC);
 	if (!map)
 		return 0;
 
@@ -555,7 +555,7 @@
 	struct tioce *tioce_mmr;
 	struct tioce_kernel *tioce_kern;
 
-	tioce_kern = kcalloc(1, sizeof(struct tioce_kernel), GFP_KERNEL);
+	tioce_kern = kzalloc(sizeof(struct tioce_kernel), GFP_KERNEL);
 	if (!tioce_kern) {
 		return NULL;
 	}
@@ -727,7 +727,7 @@
 	 * Allocate kernel bus soft and copy from prom.
 	 */
 
-	tioce_common = kcalloc(1, sizeof(struct tioce_common), GFP_KERNEL);
+	tioce_common = kzalloc(sizeof(struct tioce_common), GFP_KERNEL);
 	if (!tioce_common)
 		return NULL;
 
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index ea13a8f..cc4b571 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -104,7 +104,9 @@
 
 			idle();
 		}
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
index 640d592..b90c541 100644
--- a/arch/m32r/kernel/smpboot.c
+++ b/arch/m32r/kernel/smpboot.c
@@ -426,6 +426,7 @@
 int __init start_secondary(void *unused)
 {
 	cpu_init();
+	preempt_disable();
 	smp_callin();
 	while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
 		cpu_relax();
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 11b1b90..13d10932 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -102,7 +102,9 @@
 	while (1) {
 		while (!need_resched())
 			idle();
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 1ef15d5..4f21f42 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -111,17 +111,6 @@
     }
 #endif
 
-#ifdef CONFIG_FB_E1356
-	if ((argptr = strstr(argptr, "video=")) == NULL) {
-		argptr = prom_getcmdline();
-#ifdef CONFIG_MIPS_PB1000
-		strcat(argptr, " video=e1356fb:system:pb1000,mmunalign:1");
-#else
-		strcat(argptr, " video=e1356fb:system:pb1500");
-#endif
-	}
-#endif
-
 #ifdef CONFIG_FB_XPERT98
 	if ((argptr = strstr(argptr, "video=")) == NULL) {
 		argptr = prom_getcmdline();
diff --git a/arch/mips/configs/ddb5476_defconfig b/arch/mips/configs/ddb5476_defconfig
index b260e51..326f3aa 100644
--- a/arch/mips/configs/ddb5476_defconfig
+++ b/arch/mips/configs/ddb5476_defconfig
@@ -658,7 +658,6 @@
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig
index 9a728c2..6390a75 100644
--- a/arch/mips/configs/jmr3927_defconfig
+++ b/arch/mips/configs/jmr3927_defconfig
@@ -628,7 +628,6 @@
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig
index ffb23fc..f18d05c 100644
--- a/arch/mips/configs/ocelot_3_defconfig
+++ b/arch/mips/configs/ocelot_3_defconfig
@@ -758,7 +758,6 @@
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig
index 05e6520..37bd8d5 100644
--- a/arch/mips/configs/pnx8550-v2pci_defconfig
+++ b/arch/mips/configs/pnx8550-v2pci_defconfig
@@ -897,7 +897,6 @@
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig
index 2bc61ca..897420d 100644
--- a/arch/mips/configs/rbhma4500_defconfig
+++ b/arch/mips/configs/rbhma4500_defconfig
@@ -876,7 +876,6 @@
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
diff --git a/arch/mips/kernel/ioctl32.c b/arch/mips/kernel/ioctl32.c
index ed9b2da..9ea1fc7 100644
--- a/arch/mips/kernel/ioctl32.c
+++ b/arch/mips/kernel/ioctl32.c
@@ -26,10 +26,8 @@
 #define CODE
 #include "compat_ioctl.c"
 
-typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
-
 #define COMPATIBLE_IOCTL(cmd)		HANDLE_IOCTL((cmd),sys_ioctl)
-#define HANDLE_IOCTL(cmd,handler)	{ (cmd), (ioctl32_handler_t)(handler), NULL },
+#define HANDLE_IOCTL(cmd,handler)	{ (cmd), (ioctl_trans_handler_t)(handler), NULL },
 #define IOCTL_TABLE_START \
 	struct ioctl_trans ioctl_start[] = {
 #define IOCTL_TABLE_END \
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 4fe3d57..dd72577 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -52,7 +52,9 @@
 		while (!need_resched())
 			if (cpu_wait)
 				(*cpu_wait)();
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index fcacf1a..25472fc 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -82,7 +82,7 @@
  */
 asmlinkage void start_secondary(void)
 {
-	unsigned int cpu = smp_processor_id();
+	unsigned int cpu;
 
 	cpu_probe();
 	cpu_report();
@@ -95,6 +95,8 @@
 	 */
 
 	calibrate_delay();
+	preempt_disable();
+	cpu = smp_processor_id();
 	cpu_data[cpu].udelay_val = loops_per_jiffy;
 
 	prom_smp_finish();
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
index 230f5a9..9cd9c0f 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
@@ -84,7 +84,6 @@
 #include <asm/ptrace.h>
 #include <asm/reboot.h>
 #include <asm/time.h>
-#include <linux/version.h>
 #include <linux/bootmem.h>
 #include <asm/tx4938/rbtx4938.h>
 
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index 1ad44f9..e23c4e1 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -30,7 +30,6 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/thread_info.h>
-#include <linux/version.h>
 #include <linux/ptrace.h>
 #include <linux/hardirq.h>
 
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 7fdca87..fee4f1f 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -88,11 +88,15 @@
  */
 void cpu_idle(void)
 {
+	set_thread_flag(TIF_POLLING_NRFLAG);
+
 	/* endless idle loop with no priority at all */
 	while (1) {
 		while (!need_resched())
 			barrier();
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 		check_pgt_cache();
 	}
 }
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 5db3be4..a9ecf64 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -463,6 +463,7 @@
 #endif
 
 	smp_cpu_init(slave_id);
+	preempt_disable();
 
 #if 0	/* NOT WORKING YET - see entry.S */
 	istack = (void *)__get_free_pages(GFP_KERNEL,ISTACK_ORDER);
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 1493c78..c523029 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -581,17 +581,12 @@
        def_bool y
        depends on PPC64 && !NUMA
 
-config ARCH_DISCONTIGMEM_ENABLE
-	def_bool y
-	depends on SMP && PPC_PSERIES
-
-config ARCH_DISCONTIGMEM_DEFAULT
-	def_bool y
-	depends on ARCH_DISCONTIGMEM_ENABLE
-
 config ARCH_SPARSEMEM_ENABLE
 	def_bool y
-	depends on ARCH_DISCONTIGMEM_ENABLE
+
+config ARCH_SPARSEMEM_DEFAULT
+	def_bool y
+	depends on SMP && PPC_PSERIES
 
 source "mm/Kconfig"
 
@@ -599,6 +594,10 @@
 	def_bool y
 	depends on NEED_MULTIPLE_NODES
 
+config ARCH_MEMORY_PROBE
+	def_bool y
+	depends on MEMORY_HOTPLUG
+
 # Some NUMA nodes have memory ranges that span
 # other nodes.  Even though a pfn is valid and
 # between a node's start and end pfns, it may not
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index b3ae299..9a74b7a 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -4,6 +4,7 @@
 
 ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS	+= -mno-minimal-toc
+CFLAGS_ioctl32.o += -Ifs/
 endif
 ifeq ($(CONFIG_PPC32),y)
 CFLAGS_prom_init.o      += -fPIC
@@ -11,17 +12,29 @@
 endif
 
 obj-y				:= semaphore.o cputable.o ptrace.o syscalls.o \
-				   signal_32.o pmc.o
+				   irq.o signal_32.o pmc.o vdso.o
+obj-y				+= vdso32/
 obj-$(CONFIG_PPC64)		+= setup_64.o binfmt_elf32.o sys_ppc32.o \
-				   signal_64.o ptrace32.o systbl.o
+				   signal_64.o ptrace32.o systbl.o \
+				   paca.o ioctl32.o cpu_setup_power4.o \
+				   firmware.o sysfs.o udbg.o
+obj-$(CONFIG_PPC64)		+= vdso64/
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
 obj-$(CONFIG_POWER4)		+= idle_power4.o
 obj-$(CONFIG_PPC_OF)		+= of_device.o
-obj-$(CONFIG_PPC_RTAS)		+= rtas.o
+procfs-$(CONFIG_PPC64)		:= proc_ppc64.o
+obj-$(CONFIG_PROC_FS)		+= $(procfs-y)
+rtaspci-$(CONFIG_PPC64)		:= rtas_pci.o
+obj-$(CONFIG_PPC_RTAS)		+= rtas.o $(rtaspci-y)
 obj-$(CONFIG_RTAS_FLASH)	+= rtas_flash.o
 obj-$(CONFIG_RTAS_PROC)		+= rtas-proc.o
+obj-$(CONFIG_LPARCFG)		+= lparcfg.o
 obj-$(CONFIG_IBMVIO)		+= vio.o
 obj-$(CONFIG_GENERIC_TBSYNC)	+= smp-tbsync.o
+obj-$(CONFIG_PPC_PSERIES)	+= udbg_16550.o
+obj-$(CONFIG_PPC_MAPLE)		+= udbg_16550.o
+udbgscc-$(CONFIG_PPC64)		:= udbg_scc.o
+obj-$(CONFIG_PPC_PMAC)		+= $(udbgscc-y)
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index b757572..4550eb4 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -37,12 +37,12 @@
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
 #include <asm/rtas.h>
+#include <asm/vdso_datapage.h>
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 #include <asm/lppaca.h>
 #include <asm/iseries/hv_lp_event.h>
 #include <asm/cache.h>
-#include <asm/systemcfg.h>
 #include <asm/compat.h>
 #endif
 
@@ -106,7 +106,6 @@
 	DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size));
 	DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size));
 	DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page));
-	DEFINE(PLATFORM, offsetof(struct systemcfg, platform));
 	DEFINE(PLATFORM_LPAR, PLATFORM_LPAR);
 
 	/* paca */
@@ -252,25 +251,42 @@
 
 	DEFINE(TASK_SIZE, TASK_SIZE);
 	DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
-#else /* CONFIG_PPC64 */
-	/* systemcfg offsets for use by vdso */
-	DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct systemcfg, tb_orig_stamp));
-	DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct systemcfg, tb_ticks_per_sec));
-	DEFINE(CFG_TB_TO_XS, offsetof(struct systemcfg, tb_to_xs));
-	DEFINE(CFG_STAMP_XSEC, offsetof(struct systemcfg, stamp_xsec));
-	DEFINE(CFG_TB_UPDATE_COUNT, offsetof(struct systemcfg, tb_update_count));
-	DEFINE(CFG_TZ_MINUTEWEST, offsetof(struct systemcfg, tz_minuteswest));
-	DEFINE(CFG_TZ_DSTTIME, offsetof(struct systemcfg, tz_dsttime));
-	DEFINE(CFG_SYSCALL_MAP32, offsetof(struct systemcfg, syscall_map_32));
-	DEFINE(CFG_SYSCALL_MAP64, offsetof(struct systemcfg, syscall_map_64));
+#endif /* ! CONFIG_PPC64 */
 
-	/* timeval/timezone offsets for use by vdso */
+	/* datapage offsets for use by vdso */
+	DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct vdso_data, tb_orig_stamp));
+	DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct vdso_data, tb_ticks_per_sec));
+	DEFINE(CFG_TB_TO_XS, offsetof(struct vdso_data, tb_to_xs));
+	DEFINE(CFG_STAMP_XSEC, offsetof(struct vdso_data, stamp_xsec));
+	DEFINE(CFG_TB_UPDATE_COUNT, offsetof(struct vdso_data, tb_update_count));
+	DEFINE(CFG_TZ_MINUTEWEST, offsetof(struct vdso_data, tz_minuteswest));
+	DEFINE(CFG_TZ_DSTTIME, offsetof(struct vdso_data, tz_dsttime));
+	DEFINE(CFG_SYSCALL_MAP32, offsetof(struct vdso_data, syscall_map_32));
+	DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec));
+	DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
+#ifdef CONFIG_PPC64
+	DEFINE(CFG_SYSCALL_MAP64, offsetof(struct vdso_data, syscall_map_64));
 	DEFINE(TVAL64_TV_SEC, offsetof(struct timeval, tv_sec));
 	DEFINE(TVAL64_TV_USEC, offsetof(struct timeval, tv_usec));
 	DEFINE(TVAL32_TV_SEC, offsetof(struct compat_timeval, tv_sec));
 	DEFINE(TVAL32_TV_USEC, offsetof(struct compat_timeval, tv_usec));
+	DEFINE(TSPC32_TV_SEC, offsetof(struct compat_timespec, tv_sec));
+	DEFINE(TSPC32_TV_NSEC, offsetof(struct compat_timespec, tv_nsec));
+#else
+	DEFINE(TVAL32_TV_SEC, offsetof(struct timeval, tv_sec));
+	DEFINE(TVAL32_TV_USEC, offsetof(struct timeval, tv_usec));
+	DEFINE(TSPEC32_TV_SEC, offsetof(struct timespec, tv_sec));
+	DEFINE(TSPEC32_TV_NSEC, offsetof(struct timespec, tv_nsec));
+#endif
+	/* timeval/timezone offsets for use by vdso */
 	DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest));
 	DEFINE(TZONE_TZ_DSTTIME, offsetof(struct timezone, tz_dsttime));
-#endif /* CONFIG_PPC64 */
+
+	/* Other bits used by the vdso */
+	DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
+	DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
+	DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
+	DEFINE(CLOCK_REALTIME_RES, TICK_NSEC);
+
 	return 0;
 }
diff --git a/arch/ppc64/kernel/cpu_setup_power4.S b/arch/powerpc/kernel/cpu_setup_power4.S
similarity index 99%
rename from arch/ppc64/kernel/cpu_setup_power4.S
rename to arch/powerpc/kernel/cpu_setup_power4.S
index 1fb673c5..cca942f 100644
--- a/arch/ppc64/kernel/cpu_setup_power4.S
+++ b/arch/powerpc/kernel/cpu_setup_power4.S
@@ -114,11 +114,11 @@
 
 	.data
 	.balign	L1_CACHE_BYTES,0
-cpu_state_storage:	
+cpu_state_storage:
 	.space	CS_SIZE
 	.balign	L1_CACHE_BYTES,0
 	.text
-	
+
 /* Called in normal context to backup CPU 0 state. This
  * does not include cache settings. This function is also
  * called for machine sleep. This does not include the MMU
@@ -151,7 +151,7 @@
 	std	r3,CS_HID4(r5)
 	mfspr	r3,SPRN_HID5
 	std	r3,CS_HID5(r5)
-	
+
 2:
 	mtcr	r7
 	blr
@@ -213,7 +213,7 @@
 	mtspr	SPRN_HID1,r3
 	sync
 	isync
-	
+
 	/* Restore HID4 */
 	ld	r3,CS_HID4(r5)
 	sync
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index cc4e9eb..1d85ced 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -52,6 +52,9 @@
 #define COMMON_USER		(PPC_FEATURE_32 | PPC_FEATURE_HAS_FPU | \
 				 PPC_FEATURE_HAS_MMU)
 #define COMMON_USER_PPC64	(COMMON_USER | PPC_FEATURE_64)
+#define COMMON_USER_POWER4	(COMMON_USER_PPC64 | PPC_FEATURE_POWER4)
+#define COMMON_USER_POWER5	(COMMON_USER_PPC64 | PPC_FEATURE_POWER5)
+#define COMMON_USER_POWER5_PLUS	(COMMON_USER_PPC64 | PPC_FEATURE_POWER5_PLUS)
 
 
 /* We only set the spe features if the kernel was compiled with
@@ -160,7 +163,7 @@
 		.pvr_value		= 0x00350000,
 		.cpu_name		= "POWER4 (gp)",
 		.cpu_features		= CPU_FTRS_POWER4,
-		.cpu_user_features	= COMMON_USER_PPC64,
+		.cpu_user_features	= COMMON_USER_POWER4,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -175,7 +178,7 @@
 		.pvr_value		= 0x00380000,
 		.cpu_name		= "POWER4+ (gq)",
 		.cpu_features		= CPU_FTRS_POWER4,
-		.cpu_user_features	= COMMON_USER_PPC64,
+		.cpu_user_features	= COMMON_USER_POWER4,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -190,7 +193,7 @@
 		.pvr_value		= 0x00390000,
 		.cpu_name		= "PPC970",
 		.cpu_features		= CPU_FTRS_PPC970,
-		.cpu_user_features	= COMMON_USER_PPC64 |
+		.cpu_user_features	= COMMON_USER_POWER4 |
 			PPC_FEATURE_HAS_ALTIVEC_COMP,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
@@ -212,7 +215,7 @@
 #else
 		.cpu_features		= CPU_FTRS_PPC970,
 #endif
-		.cpu_user_features	= COMMON_USER_PPC64 |
+		.cpu_user_features	= COMMON_USER_POWER4 |
 			PPC_FEATURE_HAS_ALTIVEC_COMP,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
@@ -230,7 +233,7 @@
 		.pvr_value		= 0x00440000,
 		.cpu_name		= "PPC970MP",
 		.cpu_features		= CPU_FTRS_PPC970,
-		.cpu_user_features	= COMMON_USER_PPC64 |
+		.cpu_user_features	= COMMON_USER_POWER4 |
 			PPC_FEATURE_HAS_ALTIVEC_COMP,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
@@ -245,7 +248,7 @@
 		.pvr_value		= 0x003a0000,
 		.cpu_name		= "POWER5 (gr)",
 		.cpu_features		= CPU_FTRS_POWER5,
-		.cpu_user_features	= COMMON_USER_PPC64,
+		.cpu_user_features	= COMMON_USER_POWER5,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
@@ -260,7 +263,7 @@
 		.pvr_value		= 0x003b0000,
 		.cpu_name		= "POWER5 (gs)",
 		.cpu_features		= CPU_FTRS_POWER5,
-		.cpu_user_features	= COMMON_USER_PPC64,
+		.cpu_user_features	= COMMON_USER_POWER5_PLUS,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
@@ -276,7 +279,7 @@
 		.cpu_name		= "Cell Broadband Engine",
 		.cpu_features		= CPU_FTRS_CELL,
 		.cpu_user_features	= COMMON_USER_PPC64 |
-			PPC_FEATURE_HAS_ALTIVEC_COMP,
+			PPC_FEATURE_CELL | PPC_FEATURE_HAS_ALTIVEC_COMP,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.cpu_setup		= __setup_cpu_be,
diff --git a/arch/ppc64/kernel/firmware.c b/arch/powerpc/kernel/firmware.c
similarity index 97%
rename from arch/ppc64/kernel/firmware.c
rename to arch/powerpc/kernel/firmware.c
index d8432c0..65eae75 100644
--- a/arch/ppc64/kernel/firmware.c
+++ b/arch/powerpc/kernel/firmware.c
@@ -1,6 +1,4 @@
 /*
- *  arch/ppc64/kernel/firmware.c
- *
  *  Extracted from cputable.c
  *
  *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index 4d6001f..b780b42 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -41,20 +41,20 @@
 #ifndef CONFIG_SMP
 	LOADBASE(r3, last_task_used_math)
 	toreal(r3)
-	LDL	r4,OFF(last_task_used_math)(r3)
-	CMPI	0,r4,0
+	PPC_LL	r4,OFF(last_task_used_math)(r3)
+	PPC_LCMPI	0,r4,0
 	beq	1f
 	toreal(r4)
 	addi	r4,r4,THREAD		/* want last_task_used_math->thread */
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
 	stfd	fr0,THREAD_FPSCR(r4)
-	LDL	r5,PT_REGS(r4)
+	PPC_LL	r5,PT_REGS(r4)
 	toreal(r5)
-	LDL	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	PPC_LL	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r10,MSR_FP|MSR_FE0|MSR_FE1
 	andc	r4,r4,r10		/* disable FP for previous task */
-	STL	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	PPC_STL	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
@@ -77,7 +77,7 @@
 #ifndef CONFIG_SMP
 	subi	r4,r5,THREAD
 	fromreal(r4)
-	STL	r4,OFF(last_task_used_math)(r3)
+	PPC_STL	r4,OFF(last_task_used_math)(r3)
 #endif /* CONFIG_SMP */
 	/* restore registers and return */
 	/* we haven't used ctr or xer or lr */
@@ -97,24 +97,24 @@
 	MTMSRD(r5)			/* enable use of fpu now */
 	SYNC_601
 	isync
-	CMPI	0,r3,0
+	PPC_LCMPI	0,r3,0
 	beqlr-				/* if no previous owner, done */
 	addi	r3,r3,THREAD	        /* want THREAD of task */
-	LDL	r5,PT_REGS(r3)
-	CMPI	0,r5,0
+	PPC_LL	r5,PT_REGS(r3)
+	PPC_LCMPI	0,r5,0
 	SAVE_32FPRS(0, r3)
 	mffs	fr0
 	stfd	fr0,THREAD_FPSCR(r3)
 	beq	1f
-	LDL	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	PPC_LL	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r3,MSR_FP|MSR_FE0|MSR_FE1
 	andc	r4,r4,r3		/* disable FP for previous task */
-	STL	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	PPC_STL	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
 #ifndef CONFIG_SMP
 	li	r5,0
 	LOADBASE(r4,last_task_used_math)
-	STL	r5,OFF(last_task_used_math)(r4)
+	PPC_STL	r5,OFF(last_task_used_math)(r4)
 #endif /* CONFIG_SMP */
 	blr
 
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index b102e3a..ccdf947 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -1100,6 +1100,7 @@
 	mr	r3,r31
 	mr	r4,r30
 	bl	machine_init
+	bl	__save_cpu_setup
 	bl	MMU_init
 
 #ifdef CONFIG_APUS
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 16ab40d..8a8bf79 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -28,7 +28,6 @@
 #include <asm/reg.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
-#include <asm/systemcfg.h>
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/bug.h>
@@ -1697,25 +1696,14 @@
  *   SPRG3 = paca virtual address
  */
 _GLOBAL(__secondary_start)
+	/* Set thread priority to MEDIUM */
+	HMT_MEDIUM
 
-	HMT_MEDIUM			/* Set thread priority to MEDIUM */
-
+	/* Load TOC */
 	ld	r2,PACATOC(r13)
-	li	r6,0
-	stb	r6,PACAPROCENABLED(r13)
 
-#ifndef CONFIG_PPC_ISERIES
-	/* Initialize the page table pointer register. */
-	LOADADDR(r6,_SDR1)
-	ld	r6,0(r6)		/* get the value of _SDR1	 */
-	mtspr	SPRN_SDR1,r6			/* set the htab location	 */
-#endif
-	/* Initialize the first segment table (or SLB) entry		 */
-	ld	r3,PACASTABVIRT(r13)	/* get addr of segment table	 */
-BEGIN_FTR_SECTION
-	bl	.stab_initialize
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
-	bl	.slb_initialize
+	/* Do early setup for that CPU (stab, slb, hash table pointer) */
+	bl	.early_setup_secondary
 
 	/* Initialize the kernel stack.  Just a repeat for iSeries.	 */
 	LOADADDR(r3,current_set)
@@ -1724,37 +1712,7 @@
 	addi	r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
 	std	r1,PACAKSAVE(r13)
 
-	ld	r3,PACASTABREAL(r13)	/* get raddr of segment table	 */
-	ori	r4,r3,1			/* turn on valid bit		 */
-
-#ifdef CONFIG_PPC_ISERIES
-	li	r0,-1			/* hypervisor call */
-	li	r3,1
-	sldi	r3,r3,63		/* 0x8000000000000000 */
-	ori	r3,r3,4			/* 0x8000000000000004 */
-	sc				/* HvCall_setASR */
-#else
-	/* set the ASR */
-	ld	r3,systemcfg@got(r2)	/* r3 = ptr to systemcfg	 */
-	ld	r3,0(r3)
-	lwz	r3,PLATFORM(r3)		/* r3 = platform flags		 */
-	andi.	r3,r3,PLATFORM_LPAR	/* Test if bit 0 is set (LPAR bit) */
-	beq	98f			/* branch if result is 0  */
-	mfspr	r3,SPRN_PVR
-	srwi	r3,r3,16
-	cmpwi	r3,0x37			/* SStar  */
-	beq	97f
-	cmpwi	r3,0x36			/* IStar  */
-	beq	97f
-	cmpwi	r3,0x34			/* Pulsar */
-	bne	98f
-97:	li	r3,H_SET_ASR		/* hcall = H_SET_ASR */
-	HVSC				/* Invoking hcall */
-	b	99f
-98:					/* !(rpa hypervisor) || !(star)  */
-	mtasr	r4			/* set the stab location	 */
-99:
-#endif
+	/* Clear backchain so we get nice backtraces */
 	li	r7,0
 	mtlr	r7
 
@@ -1777,6 +1735,7 @@
 	li	r3,0
 	std	r3,0(r1)		/* Zero the stack frame pointer	*/
 	bl	.start_secondary
+	b	.
 #endif
 
 /*
@@ -1896,40 +1855,6 @@
 	mr	r3,r31
  	bl	.early_setup
 
-	/* set the ASR */
-	ld	r3,PACASTABREAL(r13)
-	ori	r4,r3,1			/* turn on valid bit		 */
-	ld	r3,systemcfg@got(r2)	/* r3 = ptr to systemcfg */
-	ld	r3,0(r3)
-	lwz	r3,PLATFORM(r3)		/* r3 = platform flags */
-	andi.	r3,r3,PLATFORM_LPAR	/* Test if bit 0 is set (LPAR bit) */
-	beq	98f			/* branch if result is 0  */
-	mfspr	r3,SPRN_PVR
-	srwi	r3,r3,16
-	cmpwi	r3,0x37			/* SStar */
-	beq	97f
-	cmpwi	r3,0x36			/* IStar  */
-	beq	97f
-	cmpwi	r3,0x34			/* Pulsar */
-	bne	98f
-97:	li	r3,H_SET_ASR		/* hcall = H_SET_ASR */
-	HVSC				/* Invoking hcall */
-	b	99f
-98:					/* !(rpa hypervisor) || !(star) */
-	mtasr	r4			/* set the stab location	*/
-99:
-	/* Set SDR1 (hash table pointer) */
-	ld	r3,systemcfg@got(r2)	/* r3 = ptr to systemcfg */
-	ld	r3,0(r3)
-	lwz	r3,PLATFORM(r3)		/* r3 = platform flags */
-	/* Test if bit 0 is set (LPAR bit) */
-	andi.	r3,r3,PLATFORM_LPAR
-	bne	98f			/* branch if result is !0  */
-	LOADADDR(r6,_SDR1)		/* Only if NOT LPAR */
-	add	r6,r6,r26
-	ld	r6,0(r6)		/* get the value of _SDR1 */
-	mtspr	SPRN_SDR1,r6			/* set the htab location  */
-98: 
 	LOADADDR(r3,.start_here_common)
 	SET_REG_TO_CONST(r4, MSR_KERNEL)
 	mtspr	SPRN_SRR0,r3
diff --git a/arch/ppc64/kernel/ioctl32.c b/arch/powerpc/kernel/ioctl32.c
similarity index 99%
rename from arch/ppc64/kernel/ioctl32.c
rename to arch/powerpc/kernel/ioctl32.c
index ba4a899..3fa6a93 100644
--- a/arch/ppc64/kernel/ioctl32.c
+++ b/arch/powerpc/kernel/ioctl32.c
@@ -1,6 +1,6 @@
-/* 
+/*
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
- * 
+ *
  * Based on sparc64 ioctl32.c by:
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
diff --git a/arch/ppc64/kernel/irq.c b/arch/powerpc/kernel/irq.c
similarity index 70%
rename from arch/ppc64/kernel/irq.c
rename to arch/powerpc/kernel/irq.c
index 8747458..4b79406 100644
--- a/arch/ppc64/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -5,12 +5,12 @@
  *    Copyright (C) 1992 Linus Torvalds
  *  Adapted from arch/i386 by Gary Thomas
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *  Updated and modified by Cort Dougan (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Cort Dougan
+ *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
+ *    Copyright (C) 1996-2001 Cort Dougan
  *  Adapted for Power Macintosh by Paul Mackerras
  *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
  *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- * 
+ *
  * 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
@@ -21,6 +21,14 @@
  * instead of just grabbing them. Thus setups with different IRQ numbers
  * shouldn't result in any weird surprises, and installing new handlers
  * should be easier.
+ *
+ * The MPC8xx has an interrupt mask in the SIU.  If a bit is set, the
+ * interrupt is _enabled_.  As expected, IRQ0 is bit 0 in the 32-bit
+ * mask register (of which only 16 are defined), hence the weird shifting
+ * and complement of the cached_irq_mask.  I want to be able to stuff
+ * this right into the SIU SMASK register.
+ * Many of the prep/chrp functions are conditional compiled on CONFIG_8xx
+ * to reduce code space and undefined function references.
  */
 
 #include <linux/errno.h>
@@ -29,6 +37,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
@@ -40,9 +49,13 @@
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
 #include <linux/random.h>
-#include <linux/kallsyms.h>
+#include <linux/seq_file.h>
+#include <linux/cpumask.h>
 #include <linux/profile.h>
 #include <linux/bitops.h>
+#ifdef CONFIG_PPC64
+#include <linux/kallsyms.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -52,35 +65,54 @@
 #include <asm/cache.h>
 #include <asm/prom.h>
 #include <asm/ptrace.h>
-#include <asm/iseries/it_lp_queue.h>
 #include <asm/machdep.h>
+#ifdef CONFIG_PPC64
+#include <asm/iseries/it_lp_queue.h>
 #include <asm/paca.h>
-
-#ifdef CONFIG_SMP
-extern void iSeries_smp_message_recv( struct pt_regs * );
 #endif
 
-extern irq_desc_t irq_desc[NR_IRQS];
+static int ppc_spurious_interrupts;
+
+#if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP)
+extern void iSeries_smp_message_recv(struct pt_regs *);
+#endif
+
+#ifdef CONFIG_PPC32
+#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
+
+unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
+atomic_t ppc_n_lost_interrupts;
+
+#ifdef CONFIG_TAU_INT
+extern int tau_initialized;
+extern int tau_interrupts(int);
+#endif
+
+#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
+extern atomic_t ipi_recv;
+extern atomic_t ipi_sent;
+#endif
+#endif /* CONFIG_PPC32 */
+
+#ifdef CONFIG_PPC64
 EXPORT_SYMBOL(irq_desc);
 
 int distribute_irqs = 1;
 int __irq_offset_value;
-int ppc_spurious_interrupts;
 u64 ppc64_interrupt_controller;
+#endif /* CONFIG_PPC64 */
 
 int show_interrupts(struct seq_file *p, void *v)
 {
-	int i = *(loff_t *) v, j;
-	struct irqaction * action;
+	int i = *(loff_t *)v, j;
+	struct irqaction *action;
 	irq_desc_t *desc;
 	unsigned long flags;
 
 	if (i == 0) {
-		seq_printf(p, "           ");
-		for (j=0; j<NR_CPUS; j++) {
-			if (cpu_online(j))
-				seq_printf(p, "CPU%d       ",j);
-		}
+		seq_puts(p, "           ");
+		for_each_online_cpu(j)
+			seq_printf(p, "CPU%d       ", j);
 		seq_putc(p, '\n');
 	}
 
@@ -92,26 +124,41 @@
 			goto skip;
 		seq_printf(p, "%3d: ", i);
 #ifdef CONFIG_SMP
-		for (j = 0; j < NR_CPUS; j++) {
-			if (cpu_online(j))
-				seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
-		}
+		for_each_online_cpu(j)
+			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #else
 		seq_printf(p, "%10u ", kstat_irqs(i));
 #endif /* CONFIG_SMP */
 		if (desc->handler)
-			seq_printf(p, " %s ", desc->handler->typename );
+			seq_printf(p, " %s ", desc->handler->typename);
 		else
-			seq_printf(p, "  None      ");
+			seq_puts(p, "  None      ");
 		seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge  ");
-		seq_printf(p, "    %s",action->name);
-		for (action=action->next; action; action = action->next)
+		seq_printf(p, "    %s", action->name);
+		for (action = action->next; action; action = action->next)
 			seq_printf(p, ", %s", action->name);
 		seq_putc(p, '\n');
 skip:
 		spin_unlock_irqrestore(&desc->lock, flags);
-	} else if (i == NR_IRQS)
+	} else if (i == NR_IRQS) {
+#ifdef CONFIG_PPC32
+#ifdef CONFIG_TAU_INT
+		if (tau_initialized){
+			seq_puts(p, "TAU: ");
+			for (j = 0; j < NR_CPUS; j++)
+				if (cpu_online(j))
+					seq_printf(p, "%10u ", tau_interrupts(j));
+			seq_puts(p, "  PowerPC             Thermal Assist (cpu temp)\n");
+		}
+#endif
+#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
+		/* should this be per processor send/receive? */
+		seq_printf(p, "IPI (recv/sent): %10u/%u\n",
+				atomic_read(&ipi_recv), atomic_read(&ipi_sent));
+#endif
+#endif /* CONFIG_PPC32 */
 		seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts);
+	}
 	return 0;
 }
 
@@ -144,126 +191,6 @@
 }
 #endif
 
-extern int noirqdebug;
-
-/*
- * Eventually, this should take an array of interrupts and an array size
- * so it can dispatch multiple interrupts.
- */
-void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
-{
-	int status;
-	struct irqaction *action;
-	int cpu = smp_processor_id();
-	irq_desc_t *desc = get_irq_desc(irq);
-	irqreturn_t action_ret;
-#ifdef CONFIG_IRQSTACKS
-	struct thread_info *curtp, *irqtp;
-#endif
-
-	kstat_cpu(cpu).irqs[irq]++;
-
-	if (desc->status & IRQ_PER_CPU) {
-		/* no locking required for CPU-local interrupts: */
-		ack_irq(irq);
-		action_ret = handle_IRQ_event(irq, regs, desc->action);
-		desc->handler->end(irq);
-		return;
-	}
-
-	spin_lock(&desc->lock);
-	ack_irq(irq);	
-	/*
-	   REPLAY is when Linux resends an IRQ that was dropped earlier
-	   WAITING is used by probe to mark irqs that are being tested
-	   */
-	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
-	status |= IRQ_PENDING; /* we _want_ to handle it */
-
-	/*
-	 * If the IRQ is disabled for whatever reason, we cannot
-	 * use the action we have.
-	 */
-	action = NULL;
-	if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
-		action = desc->action;
-		if (!action || !action->handler) {
-			ppc_spurious_interrupts++;
-			printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq);
-			/* We can't call disable_irq here, it would deadlock */
-			if (!desc->depth)
-				desc->depth = 1;
-			desc->status |= IRQ_DISABLED;
-			/* This is not a real spurrious interrupt, we
-			 * have to eoi it, so we jump to out
-			 */
-			mask_irq(irq);
-			goto out;
-		}
-		status &= ~IRQ_PENDING; /* we commit to handling */
-		status |= IRQ_INPROGRESS; /* we are handling it */
-	}
-	desc->status = status;
-
-	/*
-	 * If there is no IRQ handler or it was disabled, exit early.
-	   Since we set PENDING, if another processor is handling
-	   a different instance of this same irq, the other processor
-	   will take care of it.
-	 */
-	if (unlikely(!action))
-		goto out;
-
-	/*
-	 * Edge triggered interrupts need to remember
-	 * pending events.
-	 * This applies to any hw interrupts that allow a second
-	 * instance of the same irq to arrive while we are in do_IRQ
-	 * or in the handler. But the code here only handles the _second_
-	 * instance of the irq, not the third or fourth. So it is mostly
-	 * useful for irq hardware that does not mask cleanly in an
-	 * SMP environment.
-	 */
-	for (;;) {
-		spin_unlock(&desc->lock);
-
-#ifdef CONFIG_IRQSTACKS
-		/* Switch to the irq stack to handle this */
-		curtp = current_thread_info();
-		irqtp = hardirq_ctx[smp_processor_id()];
-		if (curtp != irqtp) {
-			irqtp->task = curtp->task;
-			irqtp->flags = 0;
-			action_ret = call_handle_IRQ_event(irq, regs, action, irqtp);
-			irqtp->task = NULL;
-			if (irqtp->flags)
-				set_bits(irqtp->flags, &curtp->flags);
-		} else
-#endif
-			action_ret = handle_IRQ_event(irq, regs, action);
-
-		spin_lock(&desc->lock);
-		if (!noirqdebug)
-			note_interrupt(irq, desc, action_ret, regs);
-		if (likely(!(desc->status & IRQ_PENDING)))
-			break;
-		desc->status &= ~IRQ_PENDING;
-	}
-out:
-	desc->status &= ~IRQ_INPROGRESS;
-	/*
-	 * The ->end() handler has to deal with interrupts which got
-	 * disabled while the handler was running.
-	 */
-	if (desc->handler) {
-		if (desc->handler->end)
-			desc->handler->end(irq);
-		else if (desc->handler->enable)
-			desc->handler->enable(irq);
-	}
-	spin_unlock(&desc->lock);
-}
-
 #ifdef CONFIG_PPC_ISERIES
 void do_IRQ(struct pt_regs *regs)
 {
@@ -310,8 +237,11 @@
 void do_IRQ(struct pt_regs *regs)
 {
 	int irq;
+#ifdef CONFIG_IRQSTACKS
+	struct thread_info *curtp, *irqtp;
+#endif
 
-	irq_enter();
+        irq_enter();
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
 	/* Debugging check for stack overflow: is there less than 2KB free? */
@@ -328,20 +258,44 @@
 	}
 #endif
 
+	/*
+	 * Every platform is required to implement ppc_md.get_irq.
+	 * This function will either return an irq number or -1 to
+	 * indicate there are no more pending.
+	 * The value -2 is for buggy hardware and means that this IRQ
+	 * has already been handled. -- Tom
+	 */
 	irq = ppc_md.get_irq(regs);
 
-	if (irq >= 0)
-		ppc_irq_dispatch_handler(regs, irq);
-	else
-		/* That's not SMP safe ... but who cares ? */
-		ppc_spurious_interrupts++;
-
-	irq_exit();
+	if (irq >= 0) {
+#ifdef CONFIG_IRQSTACKS
+		/* Switch to the irq stack to handle this */
+		curtp = current_thread_info();
+		irqtp = hardirq_ctx[smp_processor_id()];
+		if (curtp != irqtp) {
+			irqtp->task = curtp->task;
+			irqtp->flags = 0;
+			call___do_IRQ(irq, regs, irqtp);
+			irqtp->task = NULL;
+			if (irqtp->flags)
+				set_bits(irqtp->flags, &curtp->flags);
+		} else
+#endif
+			__do_IRQ(irq, regs);
+	} else
+#ifdef CONFIG_PPC32
+		if (irq != -2)
+#endif
+			/* That's not SMP safe ... but who cares ? */
+			ppc_spurious_interrupts++;
+        irq_exit();
 }
+
 #endif	/* CONFIG_PPC_ISERIES */
 
 void __init init_IRQ(void)
 {
+#ifdef CONFIG_PPC64
 	static int once = 0;
 
 	if (once)
@@ -349,10 +303,14 @@
 
 	once++;
 
+#endif
 	ppc_md.init_IRQ();
+#ifdef CONFIG_PPC64
 	irq_ctx_init();
+#endif
 }
 
+#ifdef CONFIG_PPC64
 #ifndef CONFIG_PPC_ISERIES
 /*
  * Virtual IRQ mapping code, used on systems with XICS interrupt controllers.
@@ -517,3 +475,4 @@
 }
 
 __setup("noirqdistrib", setup_noirqdistrib);
+#endif /* CONFIG_PPC64 */
diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
similarity index 96%
rename from arch/ppc64/kernel/lparcfg.c
rename to arch/powerpc/kernel/lparcfg.c
index 3e7b2f2..1b3ba8a 100644
--- a/arch/ppc64/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -35,6 +35,7 @@
 #include <asm/time.h>
 #include <asm/iseries/it_exp_vpd_panel.h>
 #include <asm/prom.h>
+#include <asm/vdso_datapage.h>
 
 #define MODULE_VERS "1.6"
 #define MODULE_NAME "lparcfg"
@@ -42,7 +43,7 @@
 /* #define LPARCFG_DEBUG */
 
 /* find a better place for this function... */
-void log_plpar_hcall_return(unsigned long rc, char *tag)
+static void log_plpar_hcall_return(unsigned long rc, char *tag)
 {
 	if (rc == 0)		/* success, return */
 		return;
@@ -96,7 +97,7 @@
 
 #define lparcfg_write NULL
 
-/* 
+/*
  * Methods used to fetch LPAR data when running on an iSeries platform.
  */
 static int lparcfg_data(struct seq_file *m, void *v)
@@ -168,7 +169,7 @@
 #endif				/* CONFIG_PPC_ISERIES */
 
 #ifdef CONFIG_PPC_PSERIES
-/* 
+/*
  * Methods used to fetch LPAR data when running on a pSeries platform.
  */
 
@@ -177,7 +178,7 @@
  *  entitled_capacity,unallocated_capacity,
  *  aggregation, resource_capability).
  *
- *  R4 = Entitled Processor Capacity Percentage. 
+ *  R4 = Entitled Processor Capacity Percentage.
  *  R5 = Unallocated Processor Capacity Percentage.
  *  R6 (AABBCCDDEEFFGGHH).
  *      XXXX - reserved (0)
@@ -190,7 +191,7 @@
  *          XX - variable processor Capacity Weight
  *            XX - Unallocated Variable Processor Capacity Weight.
  *              XXXX - Active processors in Physical Processor Pool.
- *                  XXXX  - Processors active on platform. 
+ *                  XXXX  - Processors active on platform.
  */
 static unsigned int h_get_ppp(unsigned long *entitled,
 			      unsigned long *unallocated,
@@ -212,11 +213,10 @@
 	unsigned long dummy;
 	rc = plpar_hcall(H_PIC, 0, 0, 0, 0, pool_idle_time, num_procs, &dummy);
 
-	log_plpar_hcall_return(rc, "H_PIC");
+	if (rc != H_Authority)
+		log_plpar_hcall_return(rc, "H_PIC");
 }
 
-static unsigned long get_purr(void);
-
 /* Track sum of all purrs across all processors. This is used to further */
 /* calculate usage values by different applications                       */
 
@@ -273,7 +273,7 @@
 		if (!workbuffer) {
 			printk(KERN_ERR "%s %s kmalloc failure at line %d \n",
 			       __FILE__, __FUNCTION__, __LINE__);
-			kfree(local_buffer);			
+			kfree(local_buffer);
 			return;
 		}
 #ifdef LPARCFG_DEBUG
@@ -318,8 +318,6 @@
 	kfree(local_buffer);
 }
 
-static int lparcfg_count_active_processors(void);
-
 /* Return the number of processors in the system.
  * This function reads through the device tree and counts
  * the virtual processors, this does not include threads.
@@ -371,7 +369,7 @@
 	lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity", NULL);
 
 	if (lrdrp == NULL) {
-		partition_potential_processors = systemcfg->processorCount;
+		partition_potential_processors = vdso_data->processorCount;
 	} else {
 		partition_potential_processors = *(lrdrp + 4);
 	}
@@ -547,7 +545,7 @@
 		retval = -EIO;
 	}
 
-      out:
+out:
 	kfree(kbuf);
 	return retval;
 }
@@ -560,10 +558,10 @@
 }
 
 struct file_operations lparcfg_fops = {
-      .owner	= THIS_MODULE,
-      .read	= seq_read,
-      .open	= lparcfg_open,
-      .release	= single_release,
+	.owner		= THIS_MODULE,
+	.read		= seq_read,
+	.open		= lparcfg_open,
+	.release	= single_release,
 };
 
 int __init lparcfg_init(void)
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 3bedb53..f6d84a7 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -519,7 +519,7 @@
  *
  * flush_icache_range(unsigned long start, unsigned long stop)
  */
-_GLOBAL(flush_icache_range)
+_GLOBAL(__flush_icache_range)
 BEGIN_FTR_SECTION
 	blr				/* for 601, do nothing */
 END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
@@ -607,27 +607,6 @@
 	sync				/* wait for dcbi's to get to ram */
 	blr
 
-#ifdef CONFIG_NOT_COHERENT_CACHE
-/*
- * 40x cores have 8K or 16K dcache and 32 byte line size.
- * 44x has a 32K dcache and 32 byte line size.
- * 8xx has 1, 2, 4, 8K variants.
- * For now, cover the worst case of the 44x.
- * Must be called with external interrupts disabled.
- */
-#define CACHE_NWAYS	64
-#define CACHE_NLINES	16
-
-_GLOBAL(flush_dcache_all)
-	li	r4, (2 * CACHE_NWAYS * CACHE_NLINES)
-	mtctr	r4
-	lis     r5, KERNELBASE@h
-1:	lwz	r3, 0(r5)		/* Load one word from every line */
-	addi	r5, r5, L1_CACHE_BYTES
-	bdnz    1b
-	blr
-#endif /* CONFIG_NOT_COHERENT_CACHE */
-
 /*
  * Flush a particular page from the data cache to RAM.
  * Note: this is necessary because the instruction cache does *not*
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index ae1433d..ae48a00 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -89,12 +89,12 @@
 	mtlr	r0
 	blr
 
-_GLOBAL(call_handle_IRQ_event)
+_GLOBAL(call___do_IRQ)
 	mflr	r0
 	std	r0,16(r1)
-	stdu	r1,THREAD_SIZE-112(r6)
-	mr	r1,r6
-	bl	.handle_IRQ_event
+	stdu	r1,THREAD_SIZE-112(r5)
+	mr	r1,r5
+	bl	.__do_IRQ
 	ld	r1,0(r1)
 	ld	r0,16(r1)
 	mtlr	r0
diff --git a/arch/ppc64/kernel/pacaData.c b/arch/powerpc/kernel/paca.c
similarity index 95%
rename from arch/ppc64/kernel/pacaData.c
rename to arch/powerpc/kernel/paca.c
index 3133c72..a7b68f9 100644
--- a/arch/ppc64/kernel/pacaData.c
+++ b/arch/powerpc/kernel/paca.c
@@ -15,24 +15,16 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/page.h>
-
 #include <asm/lppaca.h>
 #include <asm/iseries/it_lp_queue.h>
 #include <asm/paca.h>
 
-static union {
-	struct systemcfg	data;
-	u8			page[PAGE_SIZE];
-} systemcfg_store __attribute__((__section__(".data.page.aligned")));
-struct systemcfg *systemcfg = &systemcfg_store.data;
-EXPORT_SYMBOL(systemcfg);
-
 
 /* This symbol is provided by the linker - let it fill in the paca
  * field correctly */
 extern unsigned long __toc_start;
 
-/* The Paca is an array with one entry per processor.  Each contains an 
+/* The Paca is an array with one entry per processor.  Each contains an
  * lppaca, which contains the information shared between the
  * hypervisor and Linux.  Each also contains an ItLpRegSave area which
  * is used by the hypervisor to save registers.
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 47d6f7e..5dcf4ba 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -44,6 +44,7 @@
 #include <asm/cputable.h>
 #include <asm/btext.h>
 #include <asm/div64.h>
+#include <asm/signal.h>
 
 #ifdef  CONFIG_8xx
 #include <asm/commproc.h>
@@ -56,7 +57,6 @@
 extern void alignment_exception(struct pt_regs *regs);
 extern void program_check_exception(struct pt_regs *regs);
 extern void single_step_exception(struct pt_regs *regs);
-extern int do_signal(sigset_t *, struct pt_regs *);
 extern int pmac_newworld;
 extern int sys_sigreturn(struct pt_regs *regs);
 
@@ -188,9 +188,6 @@
 EXPORT_SYMBOL(cuda_request);
 EXPORT_SYMBOL(cuda_poll);
 #endif /* CONFIG_ADB_CUDA */
-#if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_PPC32)
-EXPORT_SYMBOL(_machine);
-#endif
 #ifdef CONFIG_PPC_PMAC
 EXPORT_SYMBOL(sys_ctrler);
 #endif
diff --git a/arch/ppc64/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
similarity index 94%
rename from arch/ppc64/kernel/proc_ppc64.c
rename to arch/powerpc/kernel/proc_ppc64.c
index 24e955ee..7ba42a4 100644
--- a/arch/ppc64/kernel/proc_ppc64.c
+++ b/arch/powerpc/kernel/proc_ppc64.c
@@ -1,18 +1,16 @@
 /*
- * arch/ppc64/kernel/proc_ppc64.c
- *
  * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
@@ -25,7 +23,7 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#include <asm/systemcfg.h>
+#include <asm/vdso_datapage.h>
 #include <asm/rtas.h>
 #include <asm/uaccess.h>
 #include <asm/prom.h>
@@ -53,7 +51,7 @@
 	if (!root)
 		return 1;
 
-	if (!(systemcfg->platform & (PLATFORM_PSERIES | PLATFORM_CELL)))
+	if (!(platform_is_pseries() || _machine == PLATFORM_CELL))
 		return 0;
 
 	if (!proc_mkdir("rtas", root))
@@ -74,7 +72,7 @@
 	if (!pde)
 		return 1;
 	pde->nlink = 1;
-	pde->data = systemcfg;
+	pde->data = vdso_data;
 	pde->size = PAGE_SIZE;
 	pde->proc_fops = &page_map_fops;
 
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index f645adb..6a5b468 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -48,9 +48,6 @@
 #include <asm/machdep.h>
 #include <asm/pSeries_reconfig.h>
 #include <asm/pci-bridge.h>
-#ifdef CONFIG_PPC64
-#include <asm/systemcfg.h>
-#endif
 
 #ifdef DEBUG
 #define DBG(fmt...) printk(KERN_ERR fmt)
@@ -74,10 +71,6 @@
 typedef int interpret_func(struct device_node *, unsigned long *,
 			   int, int, int);
 
-extern struct rtas_t rtas;
-extern struct lmb lmb;
-extern unsigned long klimit;
-
 static int __initdata dt_root_addr_cells;
 static int __initdata dt_root_size_cells;
 
@@ -391,7 +384,7 @@
 
 #ifdef CONFIG_PPC64
 		/* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
-		if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) {
+		if (_machine == PLATFORM_POWERMAC && ic && ic->parent) {
 			char *name = get_property(ic->parent, "name", NULL);
 			if (name && !strcmp(name, "u3"))
 				np->intrs[intrcount].line += 128;
@@ -1087,9 +1080,9 @@
 static int __init early_init_dt_scan_cpus(unsigned long node,
 					  const char *uname, int depth, void *data)
 {
-	char *type = of_get_flat_dt_prop(node, "device_type", NULL);
 	u32 *prop;
-	unsigned long size = 0;
+	unsigned long size;
+	char *type = of_get_flat_dt_prop(node, "device_type", &size);
 
 	/* We are scanning "cpu" nodes only */
 	if (type == NULL || strcmp(type, "cpu") != 0)
@@ -1115,7 +1108,7 @@
 
 #ifdef CONFIG_ALTIVEC
 	/* Check if we have a VMX and eventually update CPU features */
-	prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", &size);
+	prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", NULL);
 	if (prop && (*prop) > 0) {
 		cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
 		cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
@@ -1161,13 +1154,9 @@
 	prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL);
 	if (prop == NULL)
 		return 0;
-#ifdef CONFIG_PPC64
-	systemcfg->platform = *prop;
-#else
 #ifdef CONFIG_PPC_MULTIPLATFORM
 	_machine = *prop;
 #endif
-#endif
 
 #ifdef CONFIG_PPC64
 	/* check if iommu is forced on or off */
@@ -1264,7 +1253,14 @@
 	unsigned long l;
 
 	/* We are scanning "memory" nodes only */
-	if (type == NULL || strcmp(type, "memory") != 0)
+	if (type == NULL) {
+		/*
+		 * The longtrail doesn't have a device_type on the
+		 * /memory node, so look for the node called /memory@0.
+		 */
+		if (depth != 1 || strcmp(uname, "memory@0") != 0)
+			return 0;
+	} else if (strcmp(type, "memory") != 0)
 		return 0;
 
 	reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
@@ -1339,9 +1335,6 @@
 	of_scan_flat_dt(early_init_dt_scan_memory, NULL);
 	lmb_enforce_memory_limit(memory_limit);
 	lmb_analyze();
-#ifdef CONFIG_PPC64
-	systemcfg->physicalMemorySize = lmb_phys_mem_size();
-#endif
 	lmb_reserve(0, __pa(klimit));
 
 	DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
@@ -1908,7 +1901,7 @@
 	/* We don't support that function on PowerMac, at least
 	 * not yet
 	 */
-	if (systemcfg->platform == PLATFORM_POWERMAC)
+	if (_machine == PLATFORM_POWERMAC)
 		return -ENODEV;
 
 	/* fix up new node's linux_phandle field */
@@ -1992,9 +1985,11 @@
 	*next = prop;
 	write_unlock(&devtree_lock);
 
+#ifdef CONFIG_PROC_DEVICETREE
 	/* try to add to proc as well if it was initialized */
 	if (np->pde)
 		proc_device_tree_add_prop(np->pde, prop);
+#endif /* CONFIG_PROC_DEVICETREE */
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 6dc33d1..4ce0105 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -94,11 +94,17 @@
 #ifdef CONFIG_PPC64
 #define RELOC(x)        (*PTRRELOC(&(x)))
 #define ADDR(x)		(u32) add_reloc_offset((unsigned long)(x))
+#define OF_WORKAROUNDS	0
 #else
 #define RELOC(x)	(x)
 #define ADDR(x)		(u32) (x)
+#define OF_WORKAROUNDS	of_workarounds
+int of_workarounds;
 #endif
 
+#define OF_WA_CLAIM	1	/* do phys/virt claim separately, then map */
+#define OF_WA_LONGTRAIL	2	/* work around longtrail bugs */
+
 #define PROM_BUG() do {						\
         prom_printf("kernel BUG at %s line 0x%x!\n",		\
 		    RELOC(__FILE__), __LINE__);			\
@@ -111,11 +117,6 @@
 #define prom_debug(x...)
 #endif
 
-#ifdef CONFIG_PPC32
-#define PLATFORM_POWERMAC	_MACH_Pmac
-#define PLATFORM_CHRP		_MACH_chrp
-#endif
-
 
 typedef u32 prom_arg_t;
 
@@ -128,10 +129,11 @@
 
 struct prom_t {
 	ihandle root;
-	ihandle chosen;
+	phandle chosen;
 	int cpu;
 	ihandle stdout;
 	ihandle mmumap;
+	ihandle memory;
 };
 
 struct mem_map_entry {
@@ -360,16 +362,36 @@
 static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
 				unsigned long align)
 {
-	int ret;
 	struct prom_t *_prom = &RELOC(prom);
 
-	ret = call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,
-			(prom_arg_t)align);
-	if (ret != -1 && _prom->mmumap != 0)
-		/* old pmacs need us to map as well */
+	if (align == 0 && (OF_WORKAROUNDS & OF_WA_CLAIM)) {
+		/*
+		 * Old OF requires we claim physical and virtual separately
+		 * and then map explicitly (assuming virtual mode)
+		 */
+		int ret;
+		prom_arg_t result;
+
+		ret = call_prom_ret("call-method", 5, 2, &result,
+				    ADDR("claim"), _prom->memory,
+				    align, size, virt);
+		if (ret != 0 || result == -1)
+			return -1;
+		ret = call_prom_ret("call-method", 5, 2, &result,
+				    ADDR("claim"), _prom->mmumap,
+				    align, size, virt);
+		if (ret != 0) {
+			call_prom("call-method", 4, 1, ADDR("release"),
+				  _prom->memory, size, virt);
+			return -1;
+		}
+		/* the 0x12 is M (coherence) + PP == read/write */
 		call_prom("call-method", 6, 1,
-			  ADDR("map"), _prom->mmumap, 0, size, virt, virt);
-	return ret;
+			  ADDR("map"), _prom->mmumap, 0x12, size, virt, virt);
+		return virt;
+	}
+	return call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,
+			 (prom_arg_t)align);
 }
 
 static void __init __attribute__((noreturn)) prom_panic(const char *reason)
@@ -415,11 +437,52 @@
 	return call_prom("getproplen", 2, 1, node, ADDR(pname));
 }
 
-static int inline prom_setprop(phandle node, const char *pname,
-			       void *value, size_t valuelen)
+static void add_string(char **str, const char *q)
 {
-	return call_prom("setprop", 4, 1, node, ADDR(pname),
-			 (u32)(unsigned long) value, (u32) valuelen);
+	char *p = *str;
+
+	while (*q)
+		*p++ = *q++;
+	*p++ = ' ';
+	*str = p;
+}
+
+static char *tohex(unsigned int x)
+{
+	static char digits[] = "0123456789abcdef";
+	static char result[9];
+	int i;
+
+	result[8] = 0;
+	i = 8;
+	do {
+		--i;
+		result[i] = digits[x & 0xf];
+		x >>= 4;
+	} while (x != 0 && i > 0);
+	return &result[i];
+}
+
+static int __init prom_setprop(phandle node, const char *nodename,
+			       const char *pname, void *value, size_t valuelen)
+{
+	char cmd[256], *p;
+
+	if (!(OF_WORKAROUNDS & OF_WA_LONGTRAIL))
+		return call_prom("setprop", 4, 1, node, ADDR(pname),
+				 (u32)(unsigned long) value, (u32) valuelen);
+
+	/* gah... setprop doesn't work on longtrail, have to use interpret */
+	p = cmd;
+	add_string(&p, "dev");
+	add_string(&p, nodename);
+	add_string(&p, tohex((u32)(unsigned long) value));
+	add_string(&p, tohex(valuelen));
+	add_string(&p, tohex(ADDR(pname)));
+	add_string(&p, tohex(strlen(RELOC(pname))));
+	add_string(&p, "property");
+	*p = 0;
+	return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
 }
 
 /* We can't use the standard versions because of RELOC headaches. */
@@ -980,7 +1043,7 @@
 
 	rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
 	if (!IHANDLE_VALID(rtas_inst)) {
-		prom_printf("opening rtas package failed");
+		prom_printf("opening rtas package failed (%x)\n", rtas_inst);
 		return;
 	}
 
@@ -988,7 +1051,7 @@
 
 	if (call_prom_ret("call-method", 3, 2, &entry,
 			  ADDR("instantiate-rtas"),
-			  rtas_inst, base) == PROM_ERROR
+			  rtas_inst, base) != 0
 	    || entry == 0) {
 		prom_printf(" failed\n");
 		return;
@@ -997,8 +1060,10 @@
 
 	reserve_mem(base, size);
 
-	prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base));
-	prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry));
+	prom_setprop(rtas_node, "/rtas", "linux,rtas-base",
+		     &base, sizeof(base));
+	prom_setprop(rtas_node, "/rtas", "linux,rtas-entry",
+		     &entry, sizeof(entry));
 
 	prom_debug("rtas base     = 0x%x\n", base);
 	prom_debug("rtas entry    = 0x%x\n", entry);
@@ -1089,10 +1154,6 @@
 		if (base < local_alloc_bottom)
 			local_alloc_bottom = base;
 
-		/* Save away the TCE table attributes for later use. */
-		prom_setprop(node, "linux,tce-base", &base, sizeof(base));
-		prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize));
-
 		/* It seems OF doesn't null-terminate the path :-( */
 		memset(path, 0, sizeof(path));
 		/* Call OF to setup the TCE hardware */
@@ -1101,6 +1162,10 @@
 			prom_printf("package-to-path failed\n");
 		}
 
+		/* Save away the TCE table attributes for later use. */
+		prom_setprop(node, path, "linux,tce-base", &base, sizeof(base));
+		prom_setprop(node, path, "linux,tce-size", &minsize, sizeof(minsize));
+
 		prom_debug("TCE table: %s\n", path);
 		prom_debug("\tnode = 0x%x\n", node);
 		prom_debug("\tbase = 0x%x\n", base);
@@ -1342,6 +1407,7 @@
 /*
  * For really old powermacs, we need to map things we claim.
  * For that, we need the ihandle of the mmu.
+ * Also, on the longtrail, we need to work around other bugs.
  */
 static void __init prom_find_mmu(void)
 {
@@ -1355,12 +1421,19 @@
 	if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0)
 		return;
 	version[sizeof(version) - 1] = 0;
-	prom_printf("OF version is '%s'\n", version);
 	/* XXX might need to add other versions here */
-	if (strcmp(version, "Open Firmware, 1.0.5") != 0)
+	if (strcmp(version, "Open Firmware, 1.0.5") == 0)
+		of_workarounds = OF_WA_CLAIM;
+	else if (strncmp(version, "FirmWorks,3.", 12) == 0) {
+		of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL;
+		call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim");
+	} else
 		return;
+	_prom->memory = call_prom("open", 1, 1, ADDR("/memory"));
 	prom_getprop(_prom->chosen, "mmu", &_prom->mmumap,
 		     sizeof(_prom->mmumap));
+	if (!IHANDLE_VALID(_prom->memory) || !IHANDLE_VALID(_prom->mmumap))
+		of_workarounds &= ~OF_WA_CLAIM;		/* hmmm */
 }
 #else
 #define prom_find_mmu()
@@ -1382,16 +1455,17 @@
 	memset(path, 0, 256);
 	call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255);
 	val = call_prom("instance-to-package", 1, 1, _prom->stdout);
-	prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val));
+	prom_setprop(_prom->chosen, "/chosen", "linux,stdout-package",
+		     &val, sizeof(val));
 	prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device));
-	prom_setprop(_prom->chosen, "linux,stdout-path",
-		     RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1);
+	prom_setprop(_prom->chosen, "/chosen", "linux,stdout-path",
+		     path, strlen(path) + 1);
 
 	/* If it's a display, note it */
 	memset(type, 0, sizeof(type));
 	prom_getprop(val, "device_type", type, sizeof(type));
 	if (strcmp(type, RELOC("display")) == 0)
-		prom_setprop(val, "linux,boot-display", NULL, 0);
+		prom_setprop(val, path, "linux,boot-display", NULL, 0);
 }
 
 static void __init prom_close_stdin(void)
@@ -1514,7 +1588,7 @@
 
 		/* Success */
 		prom_printf("done\n");
-		prom_setprop(node, "linux,opened", NULL, 0);
+		prom_setprop(node, path, "linux,opened", NULL, 0);
 
 		/* Setup a usable color table when the appropriate
 		 * method is available. Should update this to set-colors */
@@ -1884,9 +1958,11 @@
 	/* interrupt on this revision of u3 is number 0 and level */
 	interrupts[0] = 0;
 	interrupts[1] = 1;
-	prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts));
+	prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupts",
+		     &interrupts, sizeof(interrupts));
 	parent = (u32)mpic;
-	prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent));
+	prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent",
+		     &parent, sizeof(parent));
 #endif
 }
 
@@ -1922,11 +1998,11 @@
 		RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
 
 		val = RELOC(prom_initrd_start);
-		prom_setprop(_prom->chosen, "linux,initrd-start", &val,
-			     sizeof(val));
+		prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start",
+			     &val, sizeof(val));
 		val = RELOC(prom_initrd_end);
-		prom_setprop(_prom->chosen, "linux,initrd-end", &val,
-			     sizeof(val));
+		prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end",
+			     &val, sizeof(val));
 
 		reserve_mem(RELOC(prom_initrd_start),
 			    RELOC(prom_initrd_end) - RELOC(prom_initrd_start));
@@ -1969,16 +2045,17 @@
 	prom_init_client_services(pp);
 
 	/*
+	 * See if this OF is old enough that we need to do explicit maps
+	 * and other workarounds
+	 */
+	prom_find_mmu();
+
+	/*
 	 * Init prom stdout device
 	 */
 	prom_init_stdout();
 
 	/*
-	 * See if this OF is old enough that we need to do explicit maps
-	 */
-	prom_find_mmu();
-
-	/*
 	 * Check for an initrd
 	 */
 	prom_check_initrd(r3, r4);
@@ -1989,14 +2066,15 @@
 	 */
 	RELOC(of_platform) = prom_find_machine_type();
 	getprop_rval = RELOC(of_platform);
-	prom_setprop(_prom->chosen, "linux,platform",
+	prom_setprop(_prom->chosen, "/chosen", "linux,platform",
 		     &getprop_rval, sizeof(getprop_rval));
 
 #ifdef CONFIG_PPC_PSERIES
 	/*
 	 * On pSeries, inform the firmware about our capabilities
 	 */
-	if (RELOC(of_platform) & PLATFORM_PSERIES)
+	if (RELOC(of_platform) == PLATFORM_PSERIES ||
+	    RELOC(of_platform) == PLATFORM_PSERIES_LPAR)
 		prom_send_capabilities();
 #endif
 
@@ -2050,21 +2128,23 @@
 	 * Fill in some infos for use by the kernel later on
 	 */
 	if (RELOC(prom_memory_limit))
-		prom_setprop(_prom->chosen, "linux,memory-limit",
+		prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
 			     &RELOC(prom_memory_limit),
 			     sizeof(prom_memory_limit));
 #ifdef CONFIG_PPC64
 	if (RELOC(ppc64_iommu_off))
-		prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0);
+		prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
+			     NULL, 0);
 
 	if (RELOC(iommu_force_on))
-		prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0);
+		prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on",
+			     NULL, 0);
 
 	if (RELOC(prom_tce_alloc_start)) {
-		prom_setprop(_prom->chosen, "linux,tce-alloc-start",
+		prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-start",
 			     &RELOC(prom_tce_alloc_start),
 			     sizeof(prom_tce_alloc_start));
-		prom_setprop(_prom->chosen, "linux,tce-alloc-end",
+		prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-end",
 			     &RELOC(prom_tce_alloc_end),
 			     sizeof(prom_tce_alloc_end));
 	}
@@ -2081,8 +2161,13 @@
 	prom_printf("copying OF device tree ...\n");
 	flatten_device_tree();
 
-	/* in case stdin is USB and still active on IBM machines... */
-	prom_close_stdin();
+	/*
+	 * in case stdin is USB and still active on IBM machines...
+	 * Unfortunately quiesce crashes on some powermacs if we have
+	 * closed stdin already (in particular the powerbook 101).
+	 */
+	if (RELOC(of_platform) != PLATFORM_POWERMAC)
+		prom_close_stdin();
 
 	/*
 	 * Call OF "quiesce" method to shut down pending DMA's from
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
index 5bdd5b0..7a95b8a 100644
--- a/arch/powerpc/kernel/rtas-proc.c
+++ b/arch/powerpc/kernel/rtas-proc.c
@@ -32,7 +32,6 @@
 #include <asm/rtas.h>
 #include <asm/machdep.h> /* for ppc_md */
 #include <asm/time.h>
-#include <asm/systemcfg.h>
 
 /* Token for Sensors */
 #define KEY_SWITCH		0x0001
@@ -259,7 +258,7 @@
 {
 	struct proc_dir_entry *entry;
 
-	if (!(systemcfg->platform & PLATFORM_PSERIES))
+	if (_machine != PLATFORM_PSERIES && _machine != PLATFORM_PSERIES_LPAR)
 		return 1;
 
 	rtas_node = of_find_node_by_name(NULL, "rtas");
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 9d4e07f..4283fa3 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -29,9 +29,6 @@
 #include <asm/delay.h>
 #include <asm/uaccess.h>
 #include <asm/lmb.h>
-#ifdef CONFIG_PPC64
-#include <asm/systemcfg.h>
-#endif
 
 struct rtas_t rtas = {
 	.lock = SPIN_LOCK_UNLOCKED
@@ -671,7 +668,7 @@
 	 * the stop-self token if any
 	 */
 #ifdef CONFIG_PPC64
-	if (systemcfg->platform == PLATFORM_PSERIES_LPAR)
+	if (_machine == PLATFORM_PSERIES_LPAR)
 		rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX);
 #endif
 	rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region);
diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
similarity index 92%
rename from arch/ppc64/kernel/rtas_pci.c
rename to arch/powerpc/kernel/rtas_pci.c
index 3c3f191..0e5a8e1 100644
--- a/arch/ppc64/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -5,19 +5,19 @@
  * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
  *
  * RTAS specific routines for PCI.
- * 
+ *
  * Based on code from pci.c, chrp_pci.c and pSeries_pci.c
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *    
+ *
  * 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
@@ -47,7 +47,7 @@
 static int ibm_read_pci_config;
 static int ibm_write_pci_config;
 
-static int config_access_valid(struct pci_dn *dn, int where)
+static inline int config_access_valid(struct pci_dn *dn, int where)
 {
 	if (where < 256)
 		return 1;
@@ -72,16 +72,14 @@
         return 0;
 }
 
-static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
+static int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val)
 {
 	int returnval = -1;
 	unsigned long buid, addr;
 	int ret;
-	struct pci_dn *pdn;
 
-	if (!dn || !dn->data)
+	if (!pdn)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	pdn = dn->data;
 	if (!config_access_valid(pdn, where))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -90,7 +88,7 @@
 	buid = pdn->phb->buid;
 	if (buid) {
 		ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval,
-				addr, buid >> 32, buid & 0xffffffff, size);
+				addr, BUID_HI(buid), BUID_LO(buid), size);
 	} else {
 		ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size);
 	}
@@ -100,7 +98,7 @@
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	if (returnval == EEH_IO_ERROR_VALUE(size) &&
-	    eeh_dn_check_failure (dn, NULL))
+	    eeh_dn_check_failure (pdn->node, NULL))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	return PCIBIOS_SUCCESSFUL;
@@ -118,23 +116,23 @@
 		busdn = bus->sysdata;	/* must be a phb */
 
 	/* Search only direct children of the bus */
-	for (dn = busdn->child; dn; dn = dn->sibling)
-		if (dn->data && PCI_DN(dn)->devfn == devfn
+	for (dn = busdn->child; dn; dn = dn->sibling) {
+		struct pci_dn *pdn = PCI_DN(dn);
+		if (pdn && pdn->devfn == devfn
 		    && of_device_available(dn))
-			return rtas_read_config(dn, where, size, val);
+			return rtas_read_config(pdn, where, size, val);
+	}
 
 	return PCIBIOS_DEVICE_NOT_FOUND;
 }
 
-int rtas_write_config(struct device_node *dn, int where, int size, u32 val)
+int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val)
 {
 	unsigned long buid, addr;
 	int ret;
-	struct pci_dn *pdn;
 
-	if (!dn || !dn->data)
+	if (!pdn)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	pdn = dn->data;
 	if (!config_access_valid(pdn, where))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
@@ -142,7 +140,8 @@
 		(pdn->devfn << 8) | (where & 0xff);
 	buid = pdn->phb->buid;
 	if (buid) {
-		ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val);
+		ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr,
+			BUID_HI(buid), BUID_LO(buid), size, (ulong) val);
 	} else {
 		ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val);
 	}
@@ -165,10 +164,12 @@
 		busdn = bus->sysdata;	/* must be a phb */
 
 	/* Search only direct children of the bus */
-	for (dn = busdn->child; dn; dn = dn->sibling)
-		if (dn->data && PCI_DN(dn)->devfn == devfn
+	for (dn = busdn->child; dn; dn = dn->sibling) {
+		struct pci_dn *pdn = PCI_DN(dn);
+		if (pdn && pdn->devfn == devfn
 		    && of_device_available(dn))
-			return rtas_write_config(dn, where, size, val);
+			return rtas_write_config(pdn, where, size, val);
+	}
 	return PCIBIOS_DEVICE_NOT_FOUND;
 }
 
@@ -221,7 +222,7 @@
 	/* Python's register file is 1 MB in size. */
 	chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000);
 
-	/* 
+	/*
 	 * Firmware doesn't always clear this bit which is critical
 	 * for good performance - Anton
 	 */
@@ -292,7 +293,7 @@
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		return 1;
  	}
- 
+
 	phb->first_busno =  bus_range[0];
 	phb->last_busno  =  bus_range[1];
 
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index e22856e..33e7f2c 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -33,6 +33,7 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
+#include <asm/vdso_datapage.h>
 #include <asm/pgtable.h>
 #include <asm/smp.h>
 #include <asm/elf.h>
@@ -51,6 +52,9 @@
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/lmb.h>
+#include <asm/xmon.h>
+
+#include "setup.h"
 
 #undef DEBUG
 
@@ -60,6 +64,13 @@
 #define DBG(fmt...)
 #endif
 
+#ifdef CONFIG_PPC_MULTIPLATFORM
+int _machine = 0;
+EXPORT_SYMBOL(_machine);
+#endif
+
+unsigned long klimit = (unsigned long) _end;
+
 /*
  * This still seems to be needed... -- paulus
  */ 
@@ -433,10 +444,8 @@
 	if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
 	    initrd_end > initrd_start)
 		ROOT_DEV = Root_RAM0;
-	else {
-		printk("Bogus initrd %08lx %08lx\n", initrd_start, initrd_end);
+	else
 		initrd_start = initrd_end = 0;
-	}
 
 	if (initrd_start)
 		printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end);
@@ -510,8 +519,8 @@
 	 * On pSeries LPAR, we need to know how many cpus
 	 * could possibly be added to this partition.
 	 */
-	if (systemcfg->platform == PLATFORM_PSERIES_LPAR &&
-				(dn = of_find_node_by_path("/rtas"))) {
+	if (_machine == PLATFORM_PSERIES_LPAR &&
+	    (dn = of_find_node_by_path("/rtas"))) {
 		int num_addr_cell, num_size_cell, maxcpus;
 		unsigned int *ireg;
 
@@ -555,7 +564,27 @@
 			cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]);
 	}
 
-	systemcfg->processorCount = num_present_cpus();
+	vdso_data->processorCount = num_present_cpus();
 #endif /* CONFIG_PPC64 */
 }
 #endif /* CONFIG_SMP */
+
+#ifdef CONFIG_XMON
+static int __init early_xmon(char *p)
+{
+	/* ensure xmon is enabled */
+	if (p) {
+		if (strncmp(p, "on", 2) == 0)
+			xmon_init(1);
+		if (strncmp(p, "off", 3) == 0)
+			xmon_init(0);
+		if (strncmp(p, "early", 5) != 0)
+			return 0;
+	}
+	xmon_init(1);
+	debugger(NULL);
+
+	return 0;
+}
+early_param("xmon", early_xmon);
+#endif
diff --git a/arch/powerpc/kernel/setup.h b/arch/powerpc/kernel/setup.h
new file mode 100644
index 0000000..2ebba75
--- /dev/null
+++ b/arch/powerpc/kernel/setup.h
@@ -0,0 +1,6 @@
+#ifndef _POWERPC_KERNEL_SETUP_H
+#define _POWERPC_KERNEL_SETUP_H
+
+void check_for_initrd(void);
+
+#endif /* _POWERPC_KERNEL_SETUP_H */
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 3af2631..c98cfcc 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -40,6 +40,8 @@
 #include <asm/xmon.h>
 #include <asm/time.h>
 
+#include "setup.h"
+
 #define DBG(fmt...)
 
 #if defined CONFIG_KGDB
@@ -70,8 +72,6 @@
 int have_of = 1;
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
-int _machine = 0;
-
 extern void prep_init(void);
 extern void pmac_init(void);
 extern void chrp_init(void);
@@ -279,7 +279,6 @@
 /* Warning, IO base is not yet inited */
 void __init setup_arch(char **cmdline_p)
 {
-	extern char *klimit;
 	extern void do_init_bootmem(void);
 
 	/* so udelay does something sensible, assume <= 1000 bogomips */
@@ -303,14 +302,9 @@
 		pmac_feature_init();	/* New cool way */
 #endif
 
-#ifdef CONFIG_XMON
-	xmon_map_scc();
-	if (strstr(cmd_line, "xmon")) {
-		xmon_init(1);
-		debugger(NULL);
-	}
-#endif /* CONFIG_XMON */
-	if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
+#ifdef CONFIG_XMON_DEFAULT
+	xmon_init(1);
+#endif
 
 #if defined(CONFIG_KGDB)
 	if (ppc_md.kgdb_map_scc)
@@ -343,7 +337,7 @@
 	init_mm.start_code = PAGE_OFFSET;
 	init_mm.end_code = (unsigned long) _etext;
 	init_mm.end_data = (unsigned long) _edata;
-	init_mm.brk = (unsigned long) klimit;
+	init_mm.brk = klimit;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 0471e84..fdbd9f9 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -57,10 +57,11 @@
 #include <asm/lmb.h>
 #include <asm/iseries/it_lp_naca.h>
 #include <asm/firmware.h>
-#include <asm/systemcfg.h>
 #include <asm/xmon.h>
 #include <asm/udbg.h>
 
+#include "setup.h"
+
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
 #else
@@ -94,15 +95,6 @@
 	do { udbg_putc = call_rtas_display_status_delay; } while(0)
 #endif
 
-/* extern void *stab; */
-extern unsigned long klimit;
-
-extern void mm_init_ppc64(void);
-extern void stab_initialize(unsigned long stab);
-extern void htab_initialize(void);
-extern void early_init_devtree(void *flat_dt);
-extern void unflatten_device_tree(void);
-
 int have_of = 1;
 int boot_cpuid = 0;
 int boot_cpuid_phys = 0;
@@ -254,11 +246,10 @@
 	 * Iterate all ppc_md structures until we find the proper
 	 * one for the current machine type
 	 */
-	DBG("Probing machine type for platform %x...\n",
-	    systemcfg->platform);
+	DBG("Probing machine type for platform %x...\n", _machine);
 
 	for (mach = machines; *mach; mach++) {
-		if ((*mach)->probe(systemcfg->platform))
+		if ((*mach)->probe(_machine))
 			break;
 	}
 	/* What can we do if we didn't find ? */
@@ -290,6 +281,28 @@
 	DBG(" <- early_setup()\n");
 }
 
+#ifdef CONFIG_SMP
+void early_setup_secondary(void)
+{
+	struct paca_struct *lpaca = get_paca();
+
+	/* Mark enabled in PACA */
+	lpaca->proc_enabled = 0;
+
+	/* Initialize hash table for that CPU */
+	htab_initialize_secondary();
+
+	/* Initialize STAB/SLB. We use a virtual address as it works
+	 * in real mode on pSeries and we want a virutal address on
+	 * iSeries anyway
+	 */
+	if (cpu_has_feature(CPU_FTR_SLB))
+		slb_initialize();
+	else
+		stab_initialize(lpaca->stab_addr);
+}
+
+#endif /* CONFIG_SMP */
 
 #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
 void smp_release_cpus(void)
@@ -315,7 +328,8 @@
 #endif /* CONFIG_SMP || CONFIG_KEXEC */
 
 /*
- * Initialize some remaining members of the ppc64_caches and systemcfg structures
+ * Initialize some remaining members of the ppc64_caches and systemcfg
+ * structures
  * (at least until we get rid of them completely). This is mostly some
  * cache informations about the CPU that will be used by cache flush
  * routines and/or provided to userland
@@ -340,7 +354,7 @@
 			const char *dc, *ic;
 
 			/* Then read cache informations */
-			if (systemcfg->platform == PLATFORM_POWERMAC) {
+			if (_machine == PLATFORM_POWERMAC) {
 				dc = "d-cache-block-size";
 				ic = "i-cache-block-size";
 			} else {
@@ -360,9 +374,8 @@
 				DBG("Argh, can't find dcache properties ! "
 				    "sizep: %p, lsizep: %p\n", sizep, lsizep);
 
-			systemcfg->dcache_size = ppc64_caches.dsize = size;
-			systemcfg->dcache_line_size =
-				ppc64_caches.dline_size = lsize;
+			ppc64_caches.dsize = size;
+			ppc64_caches.dline_size = lsize;
 			ppc64_caches.log_dline_size = __ilog2(lsize);
 			ppc64_caches.dlines_per_page = PAGE_SIZE / lsize;
 
@@ -378,20 +391,13 @@
 				DBG("Argh, can't find icache properties ! "
 				    "sizep: %p, lsizep: %p\n", sizep, lsizep);
 
-			systemcfg->icache_size = ppc64_caches.isize = size;
-			systemcfg->icache_line_size =
-				ppc64_caches.iline_size = lsize;
+			ppc64_caches.isize = size;
+			ppc64_caches.iline_size = lsize;
 			ppc64_caches.log_iline_size = __ilog2(lsize);
 			ppc64_caches.ilines_per_page = PAGE_SIZE / lsize;
 		}
 	}
 
-	/* Add an eye catcher and the systemcfg layout version number */
-	strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64");
-	systemcfg->version.major = SYSTEMCFG_MAJOR;
-	systemcfg->version.minor = SYSTEMCFG_MINOR;
-	systemcfg->processor = mfspr(SPRN_PVR);
-
 	DBG(" <- initialize_cache_info()\n");
 }
 
@@ -478,15 +484,14 @@
 
 	printk("-----------------------------------------------------\n");
 	printk("ppc64_pft_size                = 0x%lx\n", ppc64_pft_size);
-	printk("ppc64_interrupt_controller    = 0x%ld\n", ppc64_interrupt_controller);
-	printk("systemcfg                     = 0x%p\n", systemcfg);
-	printk("systemcfg->platform           = 0x%x\n", systemcfg->platform);
-	printk("systemcfg->processorCount     = 0x%lx\n", systemcfg->processorCount);
-	printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize);
+	printk("ppc64_interrupt_controller    = 0x%ld\n",
+	       ppc64_interrupt_controller);
+	printk("platform                      = 0x%x\n", _machine);
+	printk("physicalMemorySize            = 0x%lx\n", lmb_phys_mem_size());
 	printk("ppc64_caches.dcache_line_size = 0x%x\n",
-			ppc64_caches.dline_size);
+	       ppc64_caches.dline_size);
 	printk("ppc64_caches.icache_line_size = 0x%x\n",
-			ppc64_caches.iline_size);
+	       ppc64_caches.iline_size);
 	printk("htab_address                  = 0x%p\n", htab_address);
 	printk("htab_hash_mask                = 0x%lx\n", htab_hash_mask);
 	printk("-----------------------------------------------------\n");
@@ -551,33 +556,6 @@
 }
 
 /*
- * Called from setup_arch to initialize the bitmap of available
- * syscalls in the systemcfg page
- */
-void __init setup_syscall_map(void)
-{
-	unsigned int i, count64 = 0, count32 = 0;
-	extern unsigned long *sys_call_table;
-	extern unsigned long sys_ni_syscall;
-
-
-	for (i = 0; i < __NR_syscalls; i++) {
-		if (sys_call_table[i*2] != sys_ni_syscall) {
-			count64++;
-			systemcfg->syscall_map_64[i >> 5] |=
-				0x80000000UL >> (i & 0x1f);
-		}
-		if (sys_call_table[i*2+1] != sys_ni_syscall) {
-			count32++;
-			systemcfg->syscall_map_32[i >> 5] |=
-				0x80000000UL >> (i & 0x1f);
-		}
-	}
-	printk(KERN_INFO "Syscall map setup, %d 32-bit and %d 64-bit syscalls\n",
-	       count32, count64);
-}
-
-/*
  * Called into from start_kernel, after lock_kernel has been called.
  * Initializes bootmem, which is unsed to manage page allocation until
  * mem_init is called.
@@ -618,9 +596,6 @@
 	do_init_bootmem();
 	sparse_init();
 
-	/* initialize the syscall map in systemcfg */
-	setup_syscall_map();
-
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
@@ -858,26 +833,6 @@
 }
 EXPORT_SYMBOL(check_legacy_ioport);
 
-#ifdef CONFIG_XMON
-static int __init early_xmon(char *p)
-{
-	/* ensure xmon is enabled */
-	if (p) {
-		if (strncmp(p, "on", 2) == 0)
-			xmon_init(1);
-		if (strncmp(p, "off", 3) == 0)
-			xmon_init(0);
-		if (strncmp(p, "early", 5) != 0)
-			return 0;
-	}
-	xmon_init(1);
-	debugger(NULL);
-
-	return 0;
-}
-early_param("xmon", early_xmon);
-#endif
-
 void cpu_die(void)
 {
 	if (ppc_md.cpu_die)
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 081d931..8bdf95b 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -42,10 +42,11 @@
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
+#include <asm/sigcontext.h>
+#include <asm/vdso.h>
 #ifdef CONFIG_PPC64
 #include "ppc32.h"
 #include <asm/unistd.h>
-#include <asm/vdso.h>
 #else
 #include <asm/ucontext.h>
 #include <asm/pgtable.h>
@@ -808,14 +809,11 @@
 
 	/* Save user registers on the stack */
 	frame = &rt_sf->uc.uc_mcontext;
-#ifdef CONFIG_PPC64
 	if (vdso32_rt_sigtramp && current->thread.vdso_base) {
 		if (save_user_regs(regs, frame, 0))
 			goto badframe;
 		regs->link = current->thread.vdso_base + vdso32_rt_sigtramp;
-	} else
-#endif
-	{
+	} else {
 		if (save_user_regs(regs, frame, __NR_rt_sigreturn))
 			goto badframe;
 		regs->link = (unsigned long) frame->tramp;
@@ -1089,14 +1087,11 @@
 	    || __put_user(sig, &sc->signal))
 		goto badframe;
 
-#ifdef CONFIG_PPC64
 	if (vdso32_sigtramp && current->thread.vdso_base) {
 		if (save_user_regs(regs, &frame->mctx, 0))
 			goto badframe;
 		regs->link = current->thread.vdso_base + vdso32_sigtramp;
-	} else
-#endif
-	{
+	} else {
 		if (save_user_regs(regs, &frame->mctx, __NR_sigreturn))
 			goto badframe;
 		regs->link = (unsigned long) frame->mctx.tramp;
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 5c330c3..62dfc5b 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -44,6 +44,7 @@
 #include <asm/cputable.h>
 #include <asm/system.h>
 #include <asm/mpic.h>
+#include <asm/vdso_datapage.h>
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 #endif
@@ -368,9 +369,11 @@
 	if (cpu == boot_cpuid)
 		return -EBUSY;
 
-	systemcfg->processorCount--;
 	cpu_clear(cpu, cpu_online_map);
+#ifdef CONFIG_PPC64
+	vdso_data->processorCount--;
 	fixup_irqs(cpu_online_map);
+#endif
 	return 0;
 }
 
@@ -388,9 +391,11 @@
 	while (!cpu_online(cpu))
 		cpu_relax();
 
+#ifdef CONFIG_PPC64
 	fixup_irqs(cpu_online_map);
 	/* counter the irq disable in fixup_irqs */
 	local_irq_enable();
+#endif
 	return 0;
 }
 
@@ -419,7 +424,9 @@
 	while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
 		cpu_relax();
 
+#ifdef CONFIG_PPC64
 	flush_tlb_pending();
+#endif
 	cpu_set(cpu, cpu_online_map);
 	local_irq_enable();
 }
@@ -510,6 +517,7 @@
 
 	smp_store_cpu_info(cpu);
 	set_dec(tb_ticks_per_jiffy);
+	preempt_disable();
 	cpu_callin_map[cpu] = 1;
 
 	smp_ops->setup_cpu(cpu);
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index a8210ed..9c921d1 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -52,7 +52,6 @@
 #include <asm/semaphore.h>
 #include <asm/time.h>
 #include <asm/mmu_context.h>
-#include <asm/systemcfg.h>
 #include <asm/ppc-pci.h>
 
 /* readdir & getdents */
diff --git a/arch/ppc64/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
similarity index 99%
rename from arch/ppc64/kernel/sysfs.c
rename to arch/powerpc/kernel/sysfs.c
index e99ec62..0f0c3a9 100644
--- a/arch/ppc64/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -16,7 +16,6 @@
 #include <asm/firmware.h>
 #include <asm/hvcall.h>
 #include <asm/prom.h>
-#include <asm/systemcfg.h>
 #include <asm/paca.h>
 #include <asm/lppaca.h>
 #include <asm/machdep.h>
@@ -232,7 +231,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_SMT))
 		sysdev_create_file(s, &attr_purr);
 }
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index a6282b6..070b4b4 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -62,8 +62,8 @@
 #include <asm/irq.h>
 #include <asm/div64.h>
 #include <asm/smp.h>
+#include <asm/vdso_datapage.h>
 #ifdef CONFIG_PPC64
-#include <asm/systemcfg.h>
 #include <asm/firmware.h>
 #endif
 #ifdef CONFIG_PPC_ISERIES
@@ -261,7 +261,6 @@
 	do_gtod.varp = temp_varp;
 	do_gtod.var_idx = temp_idx;
 
-#ifdef CONFIG_PPC64
 	/*
 	 * tb_update_count is used to allow the userspace gettimeofday code
 	 * to assure itself that it sees a consistent view of the tb_to_xs and
@@ -271,14 +270,15 @@
 	 * tb_to_xs and stamp_xsec values are consistent.  If not, then it
 	 * loops back and reads them again until this criteria is met.
 	 */
-	++(systemcfg->tb_update_count);
+	++(vdso_data->tb_update_count);
 	smp_wmb();
-	systemcfg->tb_orig_stamp = new_tb_stamp;
-	systemcfg->stamp_xsec = new_stamp_xsec;
-	systemcfg->tb_to_xs = new_tb_to_xs;
+	vdso_data->tb_orig_stamp = new_tb_stamp;
+	vdso_data->stamp_xsec = new_stamp_xsec;
+	vdso_data->tb_to_xs = new_tb_to_xs;
+	vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec;
+	vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec;
 	smp_wmb();
-	++(systemcfg->tb_update_count);
-#endif
+	++(vdso_data->tb_update_count);
 }
 
 /*
@@ -357,8 +357,8 @@
 				do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
 				tb_to_xs = divres.result_low;
 				do_gtod.varp->tb_to_xs = tb_to_xs;
-				systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
-				systemcfg->tb_to_xs = tb_to_xs;
+				vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
+				vdso_data->tb_to_xs = tb_to_xs;
 			}
 			else {
 				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
@@ -483,6 +483,8 @@
 	unsigned long offset = tb_ticks_per_jiffy / max_cpus;
 	unsigned long previous_tb = per_cpu(last_jiffy, boot_cpuid);
 
+	/* make sure tb > per_cpu(last_jiffy, cpu) for all cpus always */
+	previous_tb -= tb_ticks_per_jiffy;
 	for_each_cpu(i) {
 		if (i != boot_cpuid) {
 			previous_tb += offset;
@@ -558,10 +560,8 @@
 	new_xsec += (u64)new_sec * XSEC_PER_SEC - tb_delta_xs;
 	update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs);
 
-#ifdef CONFIG_PPC64
-	systemcfg->tz_minuteswest = sys_tz.tz_minuteswest;
-	systemcfg->tz_dsttime = sys_tz.tz_dsttime;
-#endif
+	vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
+	vdso_data->tz_dsttime = sys_tz.tz_dsttime;
 
 	write_sequnlock_irqrestore(&xtime_lock, flags);
 	clock_was_set();
@@ -710,13 +710,12 @@
 	do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
 	do_gtod.varp->tb_to_xs = tb_to_xs;
 	do_gtod.tb_to_us = tb_to_us;
-#ifdef CONFIG_PPC64
-	systemcfg->tb_orig_stamp = tb_last_jiffy;
-	systemcfg->tb_update_count = 0;
-	systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
-	systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
-	systemcfg->tb_to_xs = tb_to_xs;
-#endif
+
+	vdso_data->tb_orig_stamp = tb_last_jiffy;
+	vdso_data->tb_update_count = 0;
+	vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
+	vdso_data->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
+	vdso_data->tb_to_xs = tb_to_xs;
 
 	time_freq = 0;
 
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 32f2158..1511454 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -49,7 +49,6 @@
 #ifdef CONFIG_PPC64
 #include <asm/firmware.h>
 #include <asm/processor.h>
-#include <asm/systemcfg.h>
 #endif
 
 #ifdef CONFIG_PPC64	/* XXX */
@@ -129,7 +128,7 @@
 	nl = 1;
 #endif
 #ifdef CONFIG_PPC64
-	switch (systemcfg->platform) {
+	switch (_machine) {
 	case PLATFORM_PSERIES:
 		printk("PSERIES ");
 		nl = 1;
@@ -887,10 +886,6 @@
 	die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
 }
 
-#ifdef CONFIG_PPC64
-extern perf_irq_t perf_irq;
-#endif
-
 #if defined(CONFIG_PPC64) || defined(CONFIG_E500)
 void performance_monitor_exception(struct pt_regs *regs)
 {
diff --git a/arch/ppc64/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
similarity index 100%
rename from arch/ppc64/kernel/udbg.c
rename to arch/powerpc/kernel/udbg.c
diff --git a/arch/ppc64/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
similarity index 100%
rename from arch/ppc64/kernel/udbg_16550.c
rename to arch/powerpc/kernel/udbg_16550.c
diff --git a/arch/ppc64/kernel/udbg_scc.c b/arch/powerpc/kernel/udbg_scc.c
similarity index 100%
rename from arch/ppc64/kernel/udbg_scc.c
rename to arch/powerpc/kernel/udbg_scc.c
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
new file mode 100644
index 0000000..0d4d8be
--- /dev/null
+++ b/arch/powerpc/kernel/vdso.c
@@ -0,0 +1,746 @@
+/*
+ *  linux/arch/ppc64/kernel/vdso.c
+ *
+ *    Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
+ *			 <benh@kernel.crashing.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/elf.h>
+#include <linux/security.h>
+#include <linux/bootmem.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/lmb.h>
+#include <asm/machdep.h>
+#include <asm/cputable.h>
+#include <asm/sections.h>
+#include <asm/vdso.h>
+#include <asm/vdso_datapage.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/* Max supported size for symbol names */
+#define MAX_SYMNAME	64
+
+extern char vdso32_start, vdso32_end;
+static void *vdso32_kbase = &vdso32_start;
+unsigned int vdso32_pages;
+unsigned long vdso32_sigtramp;
+unsigned long vdso32_rt_sigtramp;
+
+#ifdef CONFIG_PPC64
+extern char vdso64_start, vdso64_end;
+static void *vdso64_kbase = &vdso64_start;
+unsigned int vdso64_pages;
+unsigned long vdso64_rt_sigtramp;
+#endif /* CONFIG_PPC64 */
+
+/*
+ * The vdso data page (aka. systemcfg for old ppc64 fans) is here.
+ * Once the early boot kernel code no longer needs to muck around
+ * with it, it will become dynamically allocated
+ */
+static union {
+	struct vdso_data	data;
+	u8			page[PAGE_SIZE];
+} vdso_data_store __attribute__((__section__(".data.page_aligned")));
+struct vdso_data *vdso_data = &vdso_data_store.data;
+
+/* Format of the patch table */
+struct vdso_patch_def
+{
+	unsigned long	ftr_mask, ftr_value;
+	const char	*gen_name;
+	const char	*fix_name;
+};
+
+/* Table of functions to patch based on the CPU type/revision
+ *
+ * Currently, we only change sync_dicache to do nothing on processors
+ * with a coherent icache
+ */
+static struct vdso_patch_def vdso_patches[] = {
+	{
+		CPU_FTR_COHERENT_ICACHE, CPU_FTR_COHERENT_ICACHE,
+		"__kernel_sync_dicache", "__kernel_sync_dicache_p5"
+	},
+	{
+		CPU_FTR_USE_TB, 0,
+		"__kernel_gettimeofday", NULL
+	},
+};
+
+/*
+ * Some infos carried around for each of them during parsing at
+ * boot time.
+ */
+struct lib32_elfinfo
+{
+	Elf32_Ehdr	*hdr;		/* ptr to ELF */
+	Elf32_Sym	*dynsym;	/* ptr to .dynsym section */
+	unsigned long	dynsymsize;	/* size of .dynsym section */
+	char		*dynstr;	/* ptr to .dynstr section */
+	unsigned long	text;		/* offset of .text section in .so */
+};
+
+struct lib64_elfinfo
+{
+	Elf64_Ehdr	*hdr;
+	Elf64_Sym	*dynsym;
+	unsigned long	dynsymsize;
+	char		*dynstr;
+	unsigned long	text;
+};
+
+
+#ifdef __DEBUG
+static void dump_one_vdso_page(struct page *pg, struct page *upg)
+{
+	printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT),
+	       page_count(pg),
+	       pg->flags);
+	if (upg/* && pg != upg*/) {
+		printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg)
+						       << PAGE_SHIFT),
+		       page_count(upg),
+		       upg->flags);
+	}
+	printk("\n");
+}
+
+static void dump_vdso_pages(struct vm_area_struct * vma)
+{
+	int i;
+
+	if (!vma || test_thread_flag(TIF_32BIT)) {
+		printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase);
+		for (i=0; i<vdso32_pages; i++) {
+			struct page *pg = virt_to_page(vdso32_kbase +
+						       i*PAGE_SIZE);
+			struct page *upg = (vma && vma->vm_mm) ?
+				follow_page(vma->vm_mm, vma->vm_start +
+					    i*PAGE_SIZE, 0)
+				: NULL;
+			dump_one_vdso_page(pg, upg);
+		}
+	}
+	if (!vma || !test_thread_flag(TIF_32BIT)) {
+		printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase);
+		for (i=0; i<vdso64_pages; i++) {
+			struct page *pg = virt_to_page(vdso64_kbase +
+						       i*PAGE_SIZE);
+			struct page *upg = (vma && vma->vm_mm) ?
+				follow_page(vma->vm_mm, vma->vm_start +
+					    i*PAGE_SIZE, 0)
+				: NULL;
+			dump_one_vdso_page(pg, upg);
+		}
+	}
+}
+#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 = test_thread_flag(TIF_32BIT) ?
+		vdso32_kbase : vdso64_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
+ */
+int arch_setup_additional_pages(struct linux_binprm *bprm,
+				int executable_stack)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	unsigned long vdso_pages;
+	unsigned long vdso_base;
+
+#ifdef CONFIG_PPC64
+	if (test_thread_flag(TIF_32BIT)) {
+		vdso_pages = vdso32_pages;
+		vdso_base = VDSO32_MBASE;
+	} else {
+		vdso_pages = vdso64_pages;
+		vdso_base = VDSO64_MBASE;
+	}
+#else
+	vdso_pages = vdso32_pages;
+	vdso_base = VDSO32_MBASE;
+#endif
+
+	current->thread.vdso_base = 0;
+
+	/* vDSO has a problem and was disabled, just don't "enable" it for the
+	 * process
+	 */
+	if (vdso_pages == 0)
+		return 0;
+
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (vma == NULL)
+		return -ENOMEM;
+
+	memset(vma, 0, sizeof(*vma));
+
+	/* Add a page to the vdso size for the data page */
+	vdso_pages ++;
+
+	/*
+	 * pick a base address for the vDSO in process space. We try to put it
+	 * at vdso_base which is the "natural" base for it, but we might fail
+	 * and end up putting it elsewhere.
+	 */
+	vdso_base = get_unmapped_area(NULL, vdso_base,
+				      vdso_pages << PAGE_SHIFT, 0, 0);
+	if (vdso_base & ~PAGE_MASK) {
+		kmem_cache_free(vm_area_cachep, vma);
+		return (int)vdso_base;
+	}
+
+	current->thread.vdso_base = vdso_base;
+
+	vma->vm_mm = mm;
+	vma->vm_start = current->thread.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.
+	 * gdb can break that with ptrace interface, and thus trigger COW on
+	 * those pages but it's then your responsibility to never do that on
+	 * the "data" page of the vDSO or you'll stop getting kernel updates
+	 * 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 | VM_RESERVED;
+	vma->vm_flags |= mm->def_flags;
+	vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
+	vma->vm_ops = &vdso_vmops;
+
+	down_write(&mm->mmap_sem);
+	if (insert_vm_struct(mm, vma)) {
+		up_write(&mm->mmap_sem);
+		kmem_cache_free(vm_area_cachep, vma);
+		return -ENOMEM;
+	}
+	mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+	up_write(&mm->mmap_sem);
+
+	return 0;
+}
+
+static void * __init find_section32(Elf32_Ehdr *ehdr, const char *secname,
+				  unsigned long *size)
+{
+	Elf32_Shdr *sechdrs;
+	unsigned int i;
+	char *secnames;
+
+	/* Grab section headers and strings so we can tell who is who */
+	sechdrs = (void *)ehdr + ehdr->e_shoff;
+	secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
+
+	/* Find the section they want */
+	for (i = 1; i < ehdr->e_shnum; i++) {
+		if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) {
+			if (size)
+				*size = sechdrs[i].sh_size;
+			return (void *)ehdr + sechdrs[i].sh_offset;
+		}
+	}
+	*size = 0;
+	return NULL;
+}
+
+static Elf32_Sym * __init find_symbol32(struct lib32_elfinfo *lib,
+					const char *symname)
+{
+	unsigned int i;
+	char name[MAX_SYMNAME], *c;
+
+	for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) {
+		if (lib->dynsym[i].st_name == 0)
+			continue;
+		strlcpy(name, lib->dynstr + lib->dynsym[i].st_name,
+			MAX_SYMNAME);
+		c = strchr(name, '@');
+		if (c)
+			*c = 0;
+		if (strcmp(symname, name) == 0)
+			return &lib->dynsym[i];
+	}
+	return NULL;
+}
+
+/* Note that we assume the section is .text and the symbol is relative to
+ * the library base
+ */
+static unsigned long __init find_function32(struct lib32_elfinfo *lib,
+					    const char *symname)
+{
+	Elf32_Sym *sym = find_symbol32(lib, symname);
+
+	if (sym == NULL) {
+		printk(KERN_WARNING "vDSO32: function %s not found !\n",
+		       symname);
+		return 0;
+	}
+	return sym->st_value - VDSO32_LBASE;
+}
+
+static int vdso_do_func_patch32(struct lib32_elfinfo *v32,
+				struct lib64_elfinfo *v64,
+				const char *orig, const char *fix)
+{
+	Elf32_Sym *sym32_gen, *sym32_fix;
+
+	sym32_gen = find_symbol32(v32, orig);
+	if (sym32_gen == NULL) {
+		printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", orig);
+		return -1;
+	}
+	if (fix == NULL) {
+		sym32_gen->st_name = 0;
+		return 0;
+	}
+	sym32_fix = find_symbol32(v32, fix);
+	if (sym32_fix == NULL) {
+		printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", fix);
+		return -1;
+	}
+	sym32_gen->st_value = sym32_fix->st_value;
+	sym32_gen->st_size = sym32_fix->st_size;
+	sym32_gen->st_info = sym32_fix->st_info;
+	sym32_gen->st_other = sym32_fix->st_other;
+	sym32_gen->st_shndx = sym32_fix->st_shndx;
+
+	return 0;
+}
+
+
+#ifdef CONFIG_PPC64
+
+static void * __init find_section64(Elf64_Ehdr *ehdr, const char *secname,
+				  unsigned long *size)
+{
+	Elf64_Shdr *sechdrs;
+	unsigned int i;
+	char *secnames;
+
+	/* Grab section headers and strings so we can tell who is who */
+	sechdrs = (void *)ehdr + ehdr->e_shoff;
+	secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
+
+	/* Find the section they want */
+	for (i = 1; i < ehdr->e_shnum; i++) {
+		if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) {
+			if (size)
+				*size = sechdrs[i].sh_size;
+			return (void *)ehdr + sechdrs[i].sh_offset;
+		}
+	}
+	if (size)
+		*size = 0;
+	return NULL;
+}
+
+static Elf64_Sym * __init find_symbol64(struct lib64_elfinfo *lib,
+					const char *symname)
+{
+	unsigned int i;
+	char name[MAX_SYMNAME], *c;
+
+	for (i = 0; i < (lib->dynsymsize / sizeof(Elf64_Sym)); i++) {
+		if (lib->dynsym[i].st_name == 0)
+			continue;
+		strlcpy(name, lib->dynstr + lib->dynsym[i].st_name,
+			MAX_SYMNAME);
+		c = strchr(name, '@');
+		if (c)
+			*c = 0;
+		if (strcmp(symname, name) == 0)
+			return &lib->dynsym[i];
+	}
+	return NULL;
+}
+
+/* Note that we assume the section is .text and the symbol is relative to
+ * the library base
+ */
+static unsigned long __init find_function64(struct lib64_elfinfo *lib,
+					    const char *symname)
+{
+	Elf64_Sym *sym = find_symbol64(lib, symname);
+
+	if (sym == NULL) {
+		printk(KERN_WARNING "vDSO64: function %s not found !\n",
+		       symname);
+		return 0;
+	}
+#ifdef VDS64_HAS_DESCRIPTORS
+	return *((u64 *)(vdso64_kbase + sym->st_value - VDSO64_LBASE)) -
+		VDSO64_LBASE;
+#else
+	return sym->st_value - VDSO64_LBASE;
+#endif
+}
+
+static int vdso_do_func_patch64(struct lib32_elfinfo *v32,
+				struct lib64_elfinfo *v64,
+				const char *orig, const char *fix)
+{
+	Elf64_Sym *sym64_gen, *sym64_fix;
+
+	sym64_gen = find_symbol64(v64, orig);
+	if (sym64_gen == NULL) {
+		printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", orig);
+		return -1;
+	}
+	if (fix == NULL) {
+		sym64_gen->st_name = 0;
+		return 0;
+	}
+	sym64_fix = find_symbol64(v64, fix);
+	if (sym64_fix == NULL) {
+		printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", fix);
+		return -1;
+	}
+	sym64_gen->st_value = sym64_fix->st_value;
+	sym64_gen->st_size = sym64_fix->st_size;
+	sym64_gen->st_info = sym64_fix->st_info;
+	sym64_gen->st_other = sym64_fix->st_other;
+	sym64_gen->st_shndx = sym64_fix->st_shndx;
+
+	return 0;
+}
+
+#endif /* CONFIG_PPC64 */
+
+
+static __init int vdso_do_find_sections(struct lib32_elfinfo *v32,
+					struct lib64_elfinfo *v64)
+{
+	void *sect;
+
+	/*
+	 * Locate symbol tables & text section
+	 */
+
+	v32->dynsym = find_section32(v32->hdr, ".dynsym", &v32->dynsymsize);
+	v32->dynstr = find_section32(v32->hdr, ".dynstr", NULL);
+	if (v32->dynsym == NULL || v32->dynstr == NULL) {
+		printk(KERN_ERR "vDSO32: required symbol section not found\n");
+		return -1;
+	}
+	sect = find_section32(v32->hdr, ".text", NULL);
+	if (sect == NULL) {
+		printk(KERN_ERR "vDSO32: the .text section was not found\n");
+		return -1;
+	}
+	v32->text = sect - vdso32_kbase;
+
+#ifdef CONFIG_PPC64
+	v64->dynsym = find_section64(v64->hdr, ".dynsym", &v64->dynsymsize);
+	v64->dynstr = find_section64(v64->hdr, ".dynstr", NULL);
+	if (v64->dynsym == NULL || v64->dynstr == NULL) {
+		printk(KERN_ERR "vDSO64: required symbol section not found\n");
+		return -1;
+	}
+	sect = find_section64(v64->hdr, ".text", NULL);
+	if (sect == NULL) {
+		printk(KERN_ERR "vDSO64: the .text section was not found\n");
+		return -1;
+	}
+	v64->text = sect - vdso64_kbase;
+#endif /* CONFIG_PPC64 */
+
+	return 0;
+}
+
+static __init void vdso_setup_trampolines(struct lib32_elfinfo *v32,
+					  struct lib64_elfinfo *v64)
+{
+	/*
+	 * Find signal trampolines
+	 */
+
+#ifdef CONFIG_PPC64
+	vdso64_rt_sigtramp = find_function64(v64, "__kernel_sigtramp_rt64");
+#endif
+	vdso32_sigtramp	   = find_function32(v32, "__kernel_sigtramp32");
+	vdso32_rt_sigtramp = find_function32(v32, "__kernel_sigtramp_rt32");
+}
+
+static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32,
+				       struct lib64_elfinfo *v64)
+{
+	Elf32_Sym *sym32;
+#ifdef CONFIG_PPC64
+	Elf64_Sym *sym64;
+
+       	sym64 = find_symbol64(v64, "__kernel_datapage_offset");
+	if (sym64 == NULL) {
+		printk(KERN_ERR "vDSO64: Can't find symbol "
+		       "__kernel_datapage_offset !\n");
+		return -1;
+	}
+	*((int *)(vdso64_kbase + sym64->st_value - VDSO64_LBASE)) =
+		(vdso64_pages << PAGE_SHIFT) -
+		(sym64->st_value - VDSO64_LBASE);
+#endif /* CONFIG_PPC64 */
+
+	sym32 = find_symbol32(v32, "__kernel_datapage_offset");
+	if (sym32 == NULL) {
+		printk(KERN_ERR "vDSO32: Can't find symbol "
+		       "__kernel_datapage_offset !\n");
+		return -1;
+	}
+	*((int *)(vdso32_kbase + (sym32->st_value - VDSO32_LBASE))) =
+		(vdso32_pages << PAGE_SHIFT) -
+		(sym32->st_value - VDSO32_LBASE);
+
+	return 0;
+}
+
+static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32,
+				       struct lib64_elfinfo *v64)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vdso_patches); i++) {
+		struct vdso_patch_def *patch = &vdso_patches[i];
+		int match = (cur_cpu_spec->cpu_features & patch->ftr_mask)
+			== patch->ftr_value;
+		if (!match)
+			continue;
+
+		DBG("replacing %s with %s...\n", patch->gen_name,
+		    patch->fix_name ? "NONE" : patch->fix_name);
+
+		/*
+		 * Patch the 32 bits and 64 bits symbols. Note that we do not
+		 * patch the "." symbol on 64 bits.
+		 * It would be easy to do, but doesn't seem to be necessary,
+		 * patching the OPD symbol is enough.
+		 */
+		vdso_do_func_patch32(v32, v64, patch->gen_name,
+				     patch->fix_name);
+#ifdef CONFIG_PPC64
+		vdso_do_func_patch64(v32, v64, patch->gen_name,
+				     patch->fix_name);
+#endif /* CONFIG_PPC64 */
+	}
+
+	return 0;
+}
+
+
+static __init int vdso_setup(void)
+{
+	struct lib32_elfinfo	v32;
+	struct lib64_elfinfo	v64;
+
+	v32.hdr = vdso32_kbase;
+#ifdef CONFIG_PPC64
+	v64.hdr = vdso64_kbase;
+#endif
+	if (vdso_do_find_sections(&v32, &v64))
+		return -1;
+
+	if (vdso_fixup_datapage(&v32, &v64))
+		return -1;
+
+	if (vdso_fixup_alt_funcs(&v32, &v64))
+		return -1;
+
+	vdso_setup_trampolines(&v32, &v64);
+
+	return 0;
+}
+
+/*
+ * Called from setup_arch to initialize the bitmap of available
+ * syscalls in the systemcfg page
+ */
+static void __init vdso_setup_syscall_map(void)
+{
+	unsigned int i;
+	extern unsigned long *sys_call_table;
+	extern unsigned long sys_ni_syscall;
+
+
+	for (i = 0; i < __NR_syscalls; i++) {
+#ifdef CONFIG_PPC64
+		if (sys_call_table[i*2] != sys_ni_syscall)
+			vdso_data->syscall_map_64[i >> 5] |=
+				0x80000000UL >> (i & 0x1f);
+		if (sys_call_table[i*2+1] != sys_ni_syscall)
+			vdso_data->syscall_map_32[i >> 5] |=
+				0x80000000UL >> (i & 0x1f);
+#else /* CONFIG_PPC64 */
+		if (sys_call_table[i] != sys_ni_syscall)
+			vdso_data->syscall_map_32[i >> 5] |=
+				0x80000000UL >> (i & 0x1f);
+#endif /* CONFIG_PPC64 */
+	}
+}
+
+
+void __init vdso_init(void)
+{
+	int i;
+
+#ifdef CONFIG_PPC64
+	/*
+	 * Fill up the "systemcfg" stuff for backward compatiblity
+	 */
+	strcpy(vdso_data->eye_catcher, "SYSTEMCFG:PPC64");
+	vdso_data->version.major = SYSTEMCFG_MAJOR;
+	vdso_data->version.minor = SYSTEMCFG_MINOR;
+	vdso_data->processor = mfspr(SPRN_PVR);
+	vdso_data->platform = _machine;
+	vdso_data->physicalMemorySize = lmb_phys_mem_size();
+	vdso_data->dcache_size = ppc64_caches.dsize;
+	vdso_data->dcache_line_size = ppc64_caches.dline_size;
+	vdso_data->icache_size = ppc64_caches.isize;
+	vdso_data->icache_line_size = ppc64_caches.iline_size;
+
+	/*
+	 * Calculate the size of the 64 bits vDSO
+	 */
+	vdso64_pages = (&vdso64_end - &vdso64_start) >> PAGE_SHIFT;
+	DBG("vdso64_kbase: %p, 0x%x pages\n", vdso64_kbase, vdso64_pages);
+#endif /* CONFIG_PPC64 */
+
+
+	/*
+	 * Calculate the size of the 32 bits vDSO
+	 */
+	vdso32_pages = (&vdso32_end - &vdso32_start) >> PAGE_SHIFT;
+	DBG("vdso32_kbase: %p, 0x%x pages\n", vdso32_kbase, vdso32_pages);
+
+
+	/*
+	 * Setup the syscall map in the vDOS
+	 */
+	vdso_setup_syscall_map();
+	/*
+	 * Initialize the vDSO images in memory, that is do necessary
+	 * fixups of vDSO symbols, locate trampolines, etc...
+	 */
+	if (vdso_setup()) {
+		printk(KERN_ERR "vDSO setup failure, not enabled !\n");
+		vdso32_pages = 0;
+#ifdef CONFIG_PPC64
+		vdso64_pages = 0;
+#endif
+		return;
+	}
+
+	/* Make sure pages are in the correct state */
+	for (i = 0; i < vdso32_pages; i++) {
+		struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
+		ClearPageReserved(pg);
+		get_page(pg);
+
+	}
+#ifdef CONFIG_PPC64
+	for (i = 0; i < vdso64_pages; i++) {
+		struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
+		ClearPageReserved(pg);
+		get_page(pg);
+	}
+#endif /* CONFIG_PPC64 */
+
+	get_page(virt_to_page(vdso_data));
+}
+
+int in_gate_area_no_task(unsigned long addr)
+{
+	return 0;
+}
+
+int in_gate_area(struct task_struct *task, unsigned long addr)
+{
+	return 0;
+}
+
+struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+{
+	return NULL;
+}
+
diff --git a/arch/ppc64/kernel/vdso32/Makefile b/arch/powerpc/kernel/vdso32/Makefile
similarity index 90%
rename from arch/ppc64/kernel/vdso32/Makefile
rename to arch/powerpc/kernel/vdso32/Makefile
index 0b1b0df..8a3bed5 100644
--- a/arch/ppc64/kernel/vdso32/Makefile
+++ b/arch/powerpc/kernel/vdso32/Makefile
@@ -5,6 +5,10 @@
 
 # Build rules
 
+ifeq ($(CONFIG_PPC32),y)
+CROSS32CC := $(CC)
+endif
+
 targets := $(obj-vdso32) vdso32.so
 obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
 
@@ -15,7 +19,7 @@
 
 obj-y += vdso32_wrapper.o
 extra-y += vdso32.lds
-CPPFLAGS_vdso32.lds += -P -C -U$(ARCH)
+CPPFLAGS_vdso32.lds += -P -C -Upowerpc
 
 # Force dependency (incbin is bad)
 $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
diff --git a/arch/ppc64/kernel/vdso32/cacheflush.S b/arch/powerpc/kernel/vdso32/cacheflush.S
similarity index 100%
rename from arch/ppc64/kernel/vdso32/cacheflush.S
rename to arch/powerpc/kernel/vdso32/cacheflush.S
diff --git a/arch/ppc64/kernel/vdso32/datapage.S b/arch/powerpc/kernel/vdso32/datapage.S
similarity index 82%
rename from arch/ppc64/kernel/vdso32/datapage.S
rename to arch/powerpc/kernel/vdso32/datapage.S
index 4f4eb0b..a08c26e 100644
--- a/arch/ppc64/kernel/vdso32/datapage.S
+++ b/arch/powerpc/kernel/vdso32/datapage.S
@@ -66,3 +66,19 @@
 	blr
   .cfi_endproc
 V_FUNCTION_END(__kernel_get_syscall_map)
+
+/*
+ * void unsigned long long  __kernel_get_tbfreq(void);
+ *
+ * returns the timebase frequency in HZ
+ */
+V_FUNCTION_BEGIN(__kernel_get_tbfreq)
+  .cfi_startproc
+	mflr	r12
+  .cfi_register lr,r12
+	bl	__get_datapage@local
+	lwz	r3,CFG_TB_TICKS_PER_SEC(r3)
+	lwz	r4,(CFG_TB_TICKS_PER_SEC + 4)(r3)
+	mtlr	r12
+  .cfi_endproc
+V_FUNCTION_END(__kernel_get_tbfreq)
diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
new file mode 100644
index 0000000..aeb5fc9
--- /dev/null
+++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -0,0 +1,315 @@
+/*
+ * Userland implementation of gettimeofday() for 32 bits processes in a
+ * ppc64 kernel for use in the vDSO
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org,
+ *                    IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+	.text
+/*
+ * Exact prototype of gettimeofday
+ *
+ * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_gettimeofday)
+  .cfi_startproc
+	mflr	r12
+  .cfi_register lr,r12
+
+	mr	r10,r3			/* r10 saves tv */
+	mr	r11,r4			/* r11 saves tz */
+	bl	__get_datapage@local	/* get data page */
+	mr	r9, r3			/* datapage ptr in r9 */
+	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
+	bne-	2f			/* out of line -> do syscall */
+
+	/* seconds are xsec >> 20 */
+	rlwinm	r5,r4,12,20,31
+	rlwimi	r5,r3,12,0,19
+	stw	r5,TVAL32_TV_SEC(r10)
+
+	/* get remaining xsec and convert to usec. we scale
+	 * up remaining xsec by 12 bits and get the top 32 bits
+	 * of the multiplication
+	 */
+	rlwinm	r5,r4,12,0,19
+	lis	r6,1000000@h
+	ori	r6,r6,1000000@l
+	mulhwu	r5,r5,r6
+	stw	r5,TVAL32_TV_USEC(r10)
+
+	cmpli	cr0,r11,0		/* check if tz is NULL */
+	beq	1f
+	lwz	r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */
+	lwz	r5,CFG_TZ_DSTTIME(r9)
+	stw	r4,TZONE_TZ_MINWEST(r11)
+	stw	r5,TZONE_TZ_DSTTIME(r11)
+
+1:	mtlr	r12
+	li	r3,0
+	blr
+
+2:
+	mtlr	r12
+	mr	r3,r10
+	mr	r4,r11
+	li	r0,__NR_gettimeofday
+	sc
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_gettimeofday)
+
+/*
+ * Exact prototype of clock_gettime()
+ *
+ * int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_clock_gettime)
+  .cfi_startproc
+	/* Check for supported clock IDs */
+	cmpli	cr0,r3,CLOCK_REALTIME
+	cmpli	cr1,r3,CLOCK_MONOTONIC
+	cror	cr0,cr0,cr1
+	bne	cr0,99f
+
+	mflr	r12			/* r12 saves lr */
+  .cfi_register lr,r12
+	mr	r10,r3			/* r10 saves id */
+	mr	r11,r4			/* r11 saves tp */
+	bl	__get_datapage@local	/* get data page */
+	mr	r9, r3			/* datapage ptr in r9 */
+	beq	cr1,50f			/* if monotonic -> jump there */
+
+	/*
+	 * CLOCK_REALTIME
+	 */
+
+	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
+	bne-	98f			/* out of line -> do syscall */
+
+	/* seconds are xsec >> 20 */
+	rlwinm	r5,r4,12,20,31
+	rlwimi	r5,r3,12,0,19
+	stw	r5,TSPC32_TV_SEC(r11)
+
+	/* get remaining xsec and convert to nsec. we scale
+	 * up remaining xsec by 12 bits and get the top 32 bits
+	 * of the multiplication, then we multiply by 1000
+	 */
+	rlwinm	r5,r4,12,0,19
+	lis	r6,1000000@h
+	ori	r6,r6,1000000@l
+	mulhwu	r5,r5,r6
+	mulli	r5,r5,1000
+	stw	r5,TSPC32_TV_NSEC(r11)
+	mtlr	r12
+	li	r3,0
+	blr
+
+	/*
+	 * CLOCK_MONOTONIC
+	 */
+
+50:	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
+	bne-	98f			/* out of line -> do syscall */
+
+	/* seconds are xsec >> 20 */
+	rlwinm	r6,r4,12,20,31
+	rlwimi	r6,r3,12,0,19
+
+	/* get remaining xsec and convert to nsec. we scale
+	 * up remaining xsec by 12 bits and get the top 32 bits
+	 * of the multiplication, then we multiply by 1000
+	 */
+	rlwinm	r7,r4,12,0,19
+	lis	r5,1000000@h
+	ori	r5,r5,1000000@l
+	mulhwu	r7,r7,r5
+	mulli	r7,r7,1000
+
+	/* now we must fixup using wall to monotonic. We need to snapshot
+	 * that value and do the counter trick again. Fortunately, we still
+	 * have the counter value in r8 that was returned by __do_get_xsec.
+	 * At this point, r6,r7 contain our sec/nsec values, r3,r4 and r5
+	 * can be used
+	 */
+
+	lwz	r3,WTOM_CLOCK_SEC(r9)
+	lwz	r4,WTOM_CLOCK_NSEC(r9)
+
+	/* We now have our result in r3,r4. We create a fake dependency
+	 * on that result and re-check the counter
+	 */
+	or	r5,r4,r3
+	xor	r0,r5,r5
+	add	r9,r9,r0
+#ifdef CONFIG_PPC64
+	lwz	r0,(CFG_TB_UPDATE_COUNT+4)(r9)
+#else
+	lwz	r0,(CFG_TB_UPDATE_COUNT)(r9)
+#endif
+        cmpl    cr0,r8,r0		/* check if updated */
+	bne-	50b
+
+	/* Calculate and store result. Note that this mimmics the C code,
+	 * which may cause funny results if nsec goes negative... is that
+	 * possible at all ?
+	 */
+	add	r3,r3,r6
+	add	r4,r4,r7
+	lis	r5,NSEC_PER_SEC@h
+	ori	r5,r5,NSEC_PER_SEC@l
+	cmpli	cr0,r4,r5
+	blt	1f
+	subf	r4,r5,r4
+	addi	r3,r3,1
+1:	stw	r3,TSPC32_TV_SEC(r11)
+	stw	r4,TSPC32_TV_NSEC(r11)
+
+	mtlr	r12
+	li	r3,0
+	blr
+
+	/*
+	 * syscall fallback
+	 */
+98:
+	mtlr	r12
+	mr	r3,r10
+	mr	r4,r11
+99:
+	li	r0,__NR_clock_gettime
+	sc
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_clock_gettime)
+
+
+/*
+ * Exact prototype of clock_getres()
+ *
+ * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_clock_getres)
+  .cfi_startproc
+	/* Check for supported clock IDs */
+	cmpwi	cr0,r3,CLOCK_REALTIME
+	cmpwi	cr1,r3,CLOCK_MONOTONIC
+	cror	cr0,cr0,cr1
+	bne	cr0,99f
+
+	li	r3,0
+	cmpli	cr0,r4,0
+	beqlr
+	lis	r5,CLOCK_REALTIME_RES@h
+	ori	r5,r5,CLOCK_REALTIME_RES@l
+	stw	r3,TSPC32_TV_SEC(r4)
+	stw	r5,TSPC32_TV_NSEC(r4)
+	blr
+
+	/*
+	 * syscall fallback
+	 */
+99:
+	li	r0,__NR_clock_getres
+	sc
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_clock_getres)
+
+
+/*
+ * This is the core of gettimeofday() & friends, it returns the xsec
+ * value in r3 & r4 and expects the datapage ptr (non clobbered)
+ * in r9. clobbers r0,r4,r5,r6,r7,r8.
+ * When returning, r8 contains the counter value that can be reused
+ * by the monotonic clock implementation
+ */
+__do_get_xsec:
+  .cfi_startproc
+	/* Check for update count & load values. We use the low
+	 * order 32 bits of the update count
+	 */
+#ifdef CONFIG_PPC64
+1:	lwz	r8,(CFG_TB_UPDATE_COUNT+4)(r9)
+#else
+1:	lwz	r8,(CFG_TB_UPDATE_COUNT)(r9)
+#endif
+	andi.	r0,r8,1			/* pending update ? loop */
+	bne-	1b
+	xor	r0,r8,r8		/* create dependency */
+	add	r9,r9,r0
+
+	/* Load orig stamp (offset to TB) */
+	lwz	r5,CFG_TB_ORIG_STAMP(r9)
+	lwz	r6,(CFG_TB_ORIG_STAMP+4)(r9)
+
+	/* Get a stable TB value */
+2:	mftbu	r3
+	mftbl	r4
+	mftbu	r0
+	cmpl	cr0,r3,r0
+	bne-	2b
+
+	/* Substract tb orig stamp. If the high part is non-zero, we jump to
+	 * the slow path which call the syscall.
+	 * If it's ok, then we have our 32 bits tb_ticks value in r7
+	 */
+	subfc	r7,r6,r4
+	subfe.	r0,r5,r3
+	bne-	3f
+
+	/* Load scale factor & do multiplication */
+	lwz	r5,CFG_TB_TO_XS(r9)	/* load values */
+	lwz	r6,(CFG_TB_TO_XS+4)(r9)
+	mulhwu	r4,r7,r5
+	mulhwu	r6,r7,r6
+	mullw	r0,r7,r5
+	addc	r6,r6,r0
+
+	/* At this point, we have the scaled xsec value in r4 + XER:CA
+	 * we load & add the stamp since epoch
+	 */
+	lwz	r5,CFG_STAMP_XSEC(r9)
+	lwz	r6,(CFG_STAMP_XSEC+4)(r9)
+	adde	r4,r4,r6
+	addze	r3,r5
+
+	/* We now have our result in r3,r4. We create a fake dependency
+	 * on that result and re-check the counter
+	 */
+	or	r6,r4,r3
+	xor	r0,r6,r6
+	add	r9,r9,r0
+#ifdef CONFIG_PPC64
+	lwz	r0,(CFG_TB_UPDATE_COUNT+4)(r9)
+#else
+	lwz	r0,(CFG_TB_UPDATE_COUNT)(r9)
+#endif
+        cmpl    cr0,r8,r0		/* check if updated */
+	bne-	1b
+
+	/* Warning ! The caller expects CR:EQ to be set to indicate a
+	 * successful calculation (so it won't fallback to the syscall
+	 * method). We have overriden that CR bit in the counter check,
+	 * but fortunately, the loop exit condition _is_ CR:EQ set, so
+	 * we can exit safely here. If you change this code, be careful
+	 * of that side effect.
+	 */
+3:	blr
+  .cfi_endproc
diff --git a/arch/ppc64/kernel/vdso32/note.S b/arch/powerpc/kernel/vdso32/note.S
similarity index 100%
rename from arch/ppc64/kernel/vdso32/note.S
rename to arch/powerpc/kernel/vdso32/note.S
diff --git a/arch/ppc64/kernel/vdso32/sigtramp.S b/arch/powerpc/kernel/vdso32/sigtramp.S
similarity index 100%
rename from arch/ppc64/kernel/vdso32/sigtramp.S
rename to arch/powerpc/kernel/vdso32/sigtramp.S
diff --git a/arch/ppc64/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S
similarity index 97%
rename from arch/ppc64/kernel/vdso32/vdso32.lds.S
rename to arch/powerpc/kernel/vdso32/vdso32.lds.S
index 6f87a91..f4bad72 100644
--- a/arch/ppc64/kernel/vdso32/vdso32.lds.S
+++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S
@@ -102,9 +102,12 @@
 {
   VDSO_VERSION_STRING {
     global:
-	__kernel_datapage_offset; /* Has to be there for the kernel to find it */
+	__kernel_datapage_offset; /* Has to be there for the kernel to find */
 	__kernel_get_syscall_map;
 	__kernel_gettimeofday;
+	__kernel_clock_gettime;
+	__kernel_clock_getres;
+	__kernel_get_tbfreq;
 	__kernel_sync_dicache;
 	__kernel_sync_dicache_p5;
 	__kernel_sigtramp32;
diff --git a/arch/ppc64/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
similarity index 79%
rename from arch/ppc64/kernel/vdso32/vdso32_wrapper.S
rename to arch/powerpc/kernel/vdso32/vdso32_wrapper.S
index 76ca28e..556f0ca 100644
--- a/arch/ppc64/kernel/vdso32/vdso32_wrapper.S
+++ b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
@@ -6,7 +6,7 @@
 	.globl vdso32_start, vdso32_end
 	.balign PAGE_SIZE
 vdso32_start:
-	.incbin "arch/ppc64/kernel/vdso32/vdso32.so"
+	.incbin "arch/powerpc/kernel/vdso32/vdso32.so"
 	.balign PAGE_SIZE
 vdso32_end:
 
diff --git a/arch/ppc64/kernel/vdso64/Makefile b/arch/powerpc/kernel/vdso64/Makefile
similarity index 100%
rename from arch/ppc64/kernel/vdso64/Makefile
rename to arch/powerpc/kernel/vdso64/Makefile
diff --git a/arch/ppc64/kernel/vdso64/cacheflush.S b/arch/powerpc/kernel/vdso64/cacheflush.S
similarity index 100%
rename from arch/ppc64/kernel/vdso64/cacheflush.S
rename to arch/powerpc/kernel/vdso64/cacheflush.S
diff --git a/arch/ppc64/kernel/vdso64/datapage.S b/arch/powerpc/kernel/vdso64/datapage.S
similarity index 83%
rename from arch/ppc64/kernel/vdso64/datapage.S
rename to arch/powerpc/kernel/vdso64/datapage.S
index ed6e599..e67eda0f 100644
--- a/arch/ppc64/kernel/vdso64/datapage.S
+++ b/arch/powerpc/kernel/vdso64/datapage.S
@@ -66,3 +66,19 @@
 	blr
   .cfi_endproc
 V_FUNCTION_END(__kernel_get_syscall_map)
+
+
+/*
+ * void unsigned long  __kernel_get_tbfreq(void);
+ *
+ * returns the timebase frequency in HZ
+ */
+V_FUNCTION_BEGIN(__kernel_get_tbfreq)
+  .cfi_startproc
+	mflr	r12
+  .cfi_register lr,r12
+	bl	V_LOCAL_FUNC(__get_datapage)
+	ld	r3,CFG_TB_TICKS_PER_SEC(r3)
+	mtlr	r12
+  .cfi_endproc
+V_FUNCTION_END(__kernel_get_tbfreq)
diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S
new file mode 100644
index 0000000..d371c02
--- /dev/null
+++ b/arch/powerpc/kernel/vdso64/gettimeofday.S
@@ -0,0 +1,242 @@
+/*
+ * Userland implementation of gettimeofday() for 64 bits processes in a
+ * ppc64 kernel for use in the vDSO
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
+ *                    IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+	.text
+/*
+ * Exact prototype of gettimeofday
+ *
+ * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_gettimeofday)
+  .cfi_startproc
+	mflr	r12
+  .cfi_register lr,r12
+
+	mr	r11,r3			/* r11 holds tv */
+	mr	r10,r4			/* r10 holds tz */
+	bl	V_LOCAL_FUNC(__get_datapage)	/* get data page */
+	bl	V_LOCAL_FUNC(__do_get_xsec)	/* get xsec from tb & kernel */
+	lis     r7,15			/* r7 = 1000000 = USEC_PER_SEC */
+	ori     r7,r7,16960
+	rldicl  r5,r4,44,20		/* r5 = sec = xsec / XSEC_PER_SEC */
+	rldicr  r6,r5,20,43		/* r6 = sec * XSEC_PER_SEC */
+	std	r5,TVAL64_TV_SEC(r11)	/* store sec in tv */
+	subf	r0,r6,r4		/* r0 = xsec = (xsec - r6) */
+	mulld   r0,r0,r7		/* usec = (xsec * USEC_PER_SEC) /
+					 * XSEC_PER_SEC
+					 */
+	rldicl  r0,r0,44,20
+	cmpldi	cr0,r10,0		/* check if tz is NULL */
+	std	r0,TVAL64_TV_USEC(r11)	/* store usec in tv */
+	beq	1f
+	lwz	r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */
+	lwz	r5,CFG_TZ_DSTTIME(r3)
+	stw	r4,TZONE_TZ_MINWEST(r10)
+	stw	r5,TZONE_TZ_DSTTIME(r10)
+1:	mtlr	r12
+	li	r3,0			/* always success */
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_gettimeofday)
+
+
+/*
+ * Exact prototype of clock_gettime()
+ *
+ * int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_clock_gettime)
+  .cfi_startproc
+	/* Check for supported clock IDs */
+	cmpwi	cr0,r3,CLOCK_REALTIME
+	cmpwi	cr1,r3,CLOCK_MONOTONIC
+	cror	cr0,cr0,cr1
+	bne	cr0,99f
+
+	mflr	r12			/* r12 saves lr */
+  .cfi_register lr,r12
+	mr	r10,r3			/* r10 saves id */
+	mr	r11,r4			/* r11 saves tp */
+	bl	V_LOCAL_FUNC(__get_datapage)	/* get data page */
+	beq	cr1,50f			/* if monotonic -> jump there */
+
+	/*
+	 * CLOCK_REALTIME
+	 */
+
+	bl	V_LOCAL_FUNC(__do_get_xsec)	/* get xsec from tb & kernel */
+
+	lis     r7,0x3b9a		/* r7 = 1000000000 = NSEC_PER_SEC */
+	ori     r7,r7,0xca00
+	rldicl  r5,r4,44,20		/* r5 = sec = xsec / XSEC_PER_SEC */
+	rldicr  r6,r5,20,43		/* r6 = sec * XSEC_PER_SEC */
+	std	r5,TSPC64_TV_SEC(r11)	/* store sec in tv */
+	subf	r0,r6,r4		/* r0 = xsec = (xsec - r6) */
+	mulld   r0,r0,r7		/* nsec = (xsec * NSEC_PER_SEC) /
+					 * XSEC_PER_SEC
+					 */
+	rldicl  r0,r0,44,20
+	std	r0,TSPC64_TV_NSEC(r11)	/* store nsec in tp */
+
+	mtlr	r12
+	li	r3,0
+	blr
+
+	/*
+	 * CLOCK_MONOTONIC
+	 */
+
+50:	bl	V_LOCAL_FUNC(__do_get_xsec)	/* get xsec from tb & kernel */
+
+	lis     r7,0x3b9a		/* r7 = 1000000000 = NSEC_PER_SEC */
+	ori     r7,r7,0xca00
+	rldicl  r5,r4,44,20		/* r5 = sec = xsec / XSEC_PER_SEC */
+	rldicr  r6,r5,20,43		/* r6 = sec * XSEC_PER_SEC */
+	subf	r0,r6,r4		/* r0 = xsec = (xsec - r6) */
+	mulld   r0,r0,r7		/* nsec = (xsec * NSEC_PER_SEC) /
+					 * XSEC_PER_SEC
+					 */
+	rldicl  r6,r0,44,20
+
+	/* now we must fixup using wall to monotonic. We need to snapshot
+	 * that value and do the counter trick again. Fortunately, we still
+	 * have the counter value in r8 that was returned by __do_get_xsec.
+	 * At this point, r5,r6 contain our sec/nsec values.
+	 * can be used
+	 */
+
+	lwz	r4,WTOM_CLOCK_SEC(r9)
+	lwz	r7,WTOM_CLOCK_NSEC(r9)
+
+	/* We now have our result in r4,r7. We create a fake dependency
+	 * on that result and re-check the counter
+	 */
+	or	r9,r4,r7
+	xor	r0,r9,r9
+	add	r3,r3,r0
+	ld	r0,CFG_TB_UPDATE_COUNT(r3)
+        cmpld   cr0,r0,r8		/* check if updated */
+	bne-	50b
+
+	/* Calculate and store result. Note that this mimmics the C code,
+	 * which may cause funny results if nsec goes negative... is that
+	 * possible at all ?
+	 */
+	add	r4,r4,r5
+	add	r7,r7,r6
+	lis	r9,NSEC_PER_SEC@h
+	ori	r9,r9,NSEC_PER_SEC@l
+	cmpli	cr0,r7,r9
+	blt	1f
+	subf	r7,r9,r7
+	addi	r4,r4,1
+1:	std	r4,TSPC64_TV_SEC(r11)
+	std	r7,TSPC64_TV_NSEC(r11)
+
+	mtlr	r12
+	li	r3,0
+	blr
+
+	/*
+	 * syscall fallback
+	 */
+98:
+	mtlr	r12
+	mr	r3,r10
+	mr	r4,r11
+99:
+	li	r0,__NR_clock_gettime
+	sc
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_clock_gettime)
+
+
+/*
+ * Exact prototype of clock_getres()
+ *
+ * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res);
+ *
+ */
+V_FUNCTION_BEGIN(__kernel_clock_getres)
+  .cfi_startproc
+	/* Check for supported clock IDs */
+	cmpwi	cr0,r3,CLOCK_REALTIME
+	cmpwi	cr1,r3,CLOCK_MONOTONIC
+	cror	cr0,cr0,cr1
+	bne	cr0,99f
+
+	li	r3,0
+	cmpli	cr0,r4,0
+	beqlr
+	lis	r5,CLOCK_REALTIME_RES@h
+	ori	r5,r5,CLOCK_REALTIME_RES@l
+	std	r3,TSPC64_TV_SEC(r4)
+	std	r5,TSPC64_TV_NSEC(r4)
+	blr
+
+	/*
+	 * syscall fallback
+	 */
+99:
+	li	r0,__NR_clock_getres
+	sc
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__kernel_clock_getres)
+
+
+/*
+ * This is the core of gettimeofday(), it returns the xsec
+ * value in r4 and expects the datapage ptr (non clobbered)
+ * in r3. clobbers r0,r4,r5,r6,r7,r8
+ * When returning, r8 contains the counter value that can be reused
+ */
+V_FUNCTION_BEGIN(__do_get_xsec)
+  .cfi_startproc
+	/* check for update count & load values */
+1:	ld	r8,CFG_TB_UPDATE_COUNT(r3)
+	andi.	r0,r4,1			/* pending update ? loop */
+	bne-	1b
+	xor	r0,r4,r4		/* create dependency */
+	add	r3,r3,r0
+
+	/* Get TB & offset it */
+	mftb	r7
+	ld	r9,CFG_TB_ORIG_STAMP(r3)
+	subf	r7,r9,r7
+
+	/* Scale result */
+	ld	r5,CFG_TB_TO_XS(r3)
+	mulhdu	r7,r7,r5
+
+	/* Add stamp since epoch */
+	ld	r6,CFG_STAMP_XSEC(r3)
+	add	r4,r6,r7
+
+	xor	r0,r4,r4
+	add	r3,r3,r0
+	ld	r0,CFG_TB_UPDATE_COUNT(r3)
+        cmpld   cr0,r0,r8		/* check if updated */
+	bne-	1b
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__do_get_xsec)
diff --git a/arch/ppc64/kernel/vdso64/note.S b/arch/powerpc/kernel/vdso64/note.S
similarity index 100%
rename from arch/ppc64/kernel/vdso64/note.S
rename to arch/powerpc/kernel/vdso64/note.S
diff --git a/arch/ppc64/kernel/vdso64/sigtramp.S b/arch/powerpc/kernel/vdso64/sigtramp.S
similarity index 100%
rename from arch/ppc64/kernel/vdso64/sigtramp.S
rename to arch/powerpc/kernel/vdso64/sigtramp.S
diff --git a/arch/ppc64/kernel/vdso64/vdso64.lds.S b/arch/powerpc/kernel/vdso64/vdso64.lds.S
similarity index 97%
rename from arch/ppc64/kernel/vdso64/vdso64.lds.S
rename to arch/powerpc/kernel/vdso64/vdso64.lds.S
index 9cb2818..4bdf224 100644
--- a/arch/ppc64/kernel/vdso64/vdso64.lds.S
+++ b/arch/powerpc/kernel/vdso64/vdso64.lds.S
@@ -102,9 +102,12 @@
 {
   VDSO_VERSION_STRING {
     global:
-	__kernel_datapage_offset; /* Has to be there for the kernel to find it */
+	__kernel_datapage_offset; /* Has to be there for the kernel to find */
 	__kernel_get_syscall_map;
     	__kernel_gettimeofday;
+	__kernel_clock_gettime;
+	__kernel_clock_getres;
+	__kernel_get_tbfreq;
 	__kernel_sync_dicache;
 	__kernel_sync_dicache_p5;
 	__kernel_sigtramp_rt64;
diff --git a/arch/ppc64/kernel/vdso64/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
similarity index 79%
rename from arch/ppc64/kernel/vdso64/vdso64_wrapper.S
rename to arch/powerpc/kernel/vdso64/vdso64_wrapper.S
index 771c274..0529cb9 100644
--- a/arch/ppc64/kernel/vdso64/vdso64_wrapper.S
+++ b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
@@ -6,7 +6,7 @@
 	.globl vdso64_start, vdso64_end
 	.balign PAGE_SIZE
 vdso64_start:
-	.incbin "arch/ppc64/kernel/vdso64/vdso64.so"
+	.incbin "arch/powerpc/kernel/vdso64/vdso64.so"
 	.balign PAGE_SIZE
 vdso64_end:
 
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 97082a4..71a6add 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -21,6 +21,7 @@
 #include <asm/iommu.h>
 #include <asm/dma.h>
 #include <asm/vio.h>
+#include <asm/prom.h>
 
 static const struct vio_device_id *vio_match_device(
 		const struct vio_device_id *, const struct vio_dev *);
@@ -265,7 +266,33 @@
 	return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
 }
 
+static int vio_hotplug(struct device *dev, char **envp, int num_envp,
+			char *buffer, int buffer_size)
+{
+	const struct vio_dev *vio_dev = to_vio_dev(dev);
+	char *cp;
+	int length;
+
+	if (!num_envp)
+		return -ENOMEM;
+
+	if (!vio_dev->dev.platform_data)
+		return -ENODEV;
+	cp = (char *)get_property(vio_dev->dev.platform_data, "compatible", &length);
+	if (!cp)
+		return -ENODEV;
+
+	envp[0] = buffer;
+	length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
+				vio_dev->type, cp);
+	if (buffer_size - length <= 0)
+		return -ENOMEM;
+	envp[1] = NULL;
+	return 0;
+}
+
 struct bus_type vio_bus_type = {
 	.name = "vio",
+	.hotplug = vio_hotplug,
 	.match = vio_bus_match,
 };
diff --git a/arch/powerpc/lib/bitops.c b/arch/powerpc/lib/bitops.c
index b67ce30..f68ad71 100644
--- a/arch/powerpc/lib/bitops.c
+++ b/arch/powerpc/lib/bitops.c
@@ -41,7 +41,7 @@
 	tmp = *p;
 
 found_first:
-	tmp &= (~0UL >> (64 - size));
+	tmp &= (~0UL >> (BITS_PER_LONG - size));
 	if (tmp == 0UL)		/* Are any bits set? */
 		return result + size;	/* Nope. */
 found_middle:
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 22e4748..706e8a6 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -84,10 +84,11 @@
 extern unsigned long dart_tablebase;
 #endif /* CONFIG_U3_DART */
 
+static unsigned long _SDR1;
+struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
+
 hpte_t *htab_address;
 unsigned long htab_hash_mask;
-unsigned long _SDR1;
-struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
 int mmu_linear_psize = MMU_PAGE_4K;
 int mmu_virtual_psize = MMU_PAGE_4K;
 #ifdef CONFIG_HUGETLB_PAGE
@@ -165,7 +166,7 @@
 		 * normal insert callback here.
 		 */
 #ifdef CONFIG_PPC_ISERIES
-		if (systemcfg->platform == PLATFORM_ISERIES_LPAR)
+		if (_machine == PLATFORM_ISERIES_LPAR)
 			ret = iSeries_hpte_insert(hpteg, va,
 						  virt_to_abs(paddr),
 						  tmp_mode,
@@ -174,7 +175,7 @@
 		else
 #endif
 #ifdef CONFIG_PPC_PSERIES
-		if (systemcfg->platform & PLATFORM_LPAR)
+		if (_machine & PLATFORM_LPAR)
 			ret = pSeries_lpar_hpte_insert(hpteg, va,
 						       virt_to_abs(paddr),
 						       tmp_mode,
@@ -293,7 +294,7 @@
 	 * Not in the device-tree, let's fallback on known size
 	 * list for 16M capable GP & GR
 	 */
-	if ((systemcfg->platform != PLATFORM_ISERIES_LPAR) &&
+	if ((_machine != PLATFORM_ISERIES_LPAR) &&
 	    cpu_has_feature(CPU_FTR_16M_PAGE))
 		memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
 		       sizeof(mmu_psize_defaults_gp));
@@ -364,7 +365,7 @@
 
 static unsigned long __init htab_get_table_size(void)
 {
-	unsigned long rnd_mem_size, pteg_count;
+	unsigned long mem_size, rnd_mem_size, pteg_count;
 
 	/* If hash size isn't already provided by the platform, we try to
 	 * retreive it from the device-tree. If it's not there neither, we
@@ -376,8 +377,9 @@
 		return 1UL << ppc64_pft_size;
 
 	/* round mem_size up to next power of 2 */
-	rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize);
-	if (rnd_mem_size < systemcfg->physicalMemorySize)
+	mem_size = lmb_phys_mem_size();
+	rnd_mem_size = 1UL << __ilog2(mem_size);
+	if (rnd_mem_size < mem_size)
 		rnd_mem_size <<= 1;
 
 	/* # pages / 2 */
@@ -386,6 +388,15 @@
 	return pteg_count << 7;
 }
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+void create_section_mapping(unsigned long start, unsigned long end)
+{
+		BUG_ON(htab_bolt_mapping(start, end, start,
+			_PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX,
+			mmu_linear_psize));
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
 void __init htab_initialize(void)
 {
 	unsigned long table, htab_size_bytes;
@@ -410,7 +421,7 @@
 
 	htab_hash_mask = pteg_count - 1;
 
-	if (systemcfg->platform & PLATFORM_LPAR) {
+	if (platform_is_lpar()) {
 		/* Using a hypervisor which owns the htab */
 		htab_address = NULL;
 		_SDR1 = 0; 
@@ -431,6 +442,9 @@
 
 		/* Initialize the HPT with no entries */
 		memset((void *)table, 0, htab_size_bytes);
+
+		/* Set SDR1 */
+		mtspr(SPRN_SDR1, _SDR1);
 	}
 
 	mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX;
@@ -500,6 +514,12 @@
 #undef KB
 #undef MB
 
+void __init htab_initialize_secondary(void)
+{
+	if (!platform_is_lpar())
+		mtspr(SPRN_SDR1, _SDR1);
+}
+
 /*
  * Called by asm hashtable.S for doing lazy icache flush
  */
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 4612a79..7d4b8b5 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -84,9 +84,6 @@
 /* XXX should be in current.h  -- paulus */
 extern struct task_struct *current_set[NR_CPUS];
 
-char *klimit = _end;
-struct device_node *memory_node;
-
 extern int init_bootmem_done;
 
 /*
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index ce974c8..1134f70 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -20,6 +20,8 @@
  *
  */
 
+#undef DEBUG
+
 #include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -64,6 +66,12 @@
 #include <asm/vdso.h>
 #include <asm/imalloc.h>
 
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
 #if PGTABLE_RANGE > USER_VSID_RANGE
 #warning Limited user VSID range means pagetable space is wasted
 #endif
@@ -72,8 +80,6 @@
 #warning TASK_SIZE is smaller than it needs to be.
 #endif
 
-unsigned long klimit = (unsigned long)_end;
-
 /* max amount of RAM to use */
 unsigned long __max_memory;
 
@@ -188,14 +194,14 @@
 }
 
 #ifdef CONFIG_PPC_64K_PAGES
-static const int pgtable_cache_size[2] = {
-	PTE_TABLE_SIZE, PGD_TABLE_SIZE
+static const unsigned int pgtable_cache_size[3] = {
+	PTE_TABLE_SIZE, PMD_TABLE_SIZE, PGD_TABLE_SIZE
 };
 static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-	"pte_pmd_cache", "pgd_cache",
+	"pte_pmd_cache", "pmd_cache", "pgd_cache",
 };
 #else
-static const int pgtable_cache_size[2] = {
+static const unsigned int pgtable_cache_size[2] = {
 	PTE_TABLE_SIZE, PMD_TABLE_SIZE
 };
 static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
@@ -213,6 +219,8 @@
 		int size = pgtable_cache_size[i];
 		const char *name = pgtable_cache_name[i];
 
+		DBG("Allocating page table cache %s (#%d) "
+		    "for size: %08x...\n", name, i, size);
 		pgtable_cache[i] = kmem_cache_create(name,
 						     size, size,
 						     SLAB_HWCACHE_ALIGN |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 6f55efd..e2c95fc 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -46,9 +46,7 @@
 #include <asm/prom.h>
 #include <asm/lmb.h>
 #include <asm/sections.h>
-#ifdef CONFIG_PPC64
 #include <asm/vdso.h>
-#endif
 
 #include "mmu_decl.h"
 
@@ -110,6 +108,7 @@
 void online_page(struct page *page)
 {
 	ClearPageReserved(page);
+	set_page_count(page, 0);
 	free_cold_page(page);
 	totalram_pages++;
 	num_physpages++;
@@ -127,6 +126,9 @@
 	unsigned long start_pfn = start >> PAGE_SHIFT;
 	unsigned long nr_pages = size >> PAGE_SHIFT;
 
+	start += KERNELBASE;
+	create_section_mapping(start, start + size);
+
 	/* this should work for most non-highmem platforms */
 	zone = pgdata->node_zones;
 
@@ -393,10 +395,8 @@
 
 	mem_init_done = 1;
 
-#ifdef CONFIG_PPC64
 	/* Initialize the vDSO */
 	vdso_init();
-#endif
 }
 
 /*
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index da09ba0..bd2cf13 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -17,9 +17,8 @@
 #include <linux/nodemask.h>
 #include <linux/cpu.h>
 #include <linux/notifier.h>
+#include <asm/sparsemem.h>
 #include <asm/lmb.h>
-#include <asm/machdep.h>
-#include <asm/abs_addr.h>
 #include <asm/system.h>
 #include <asm/smp.h>
 
@@ -28,45 +27,113 @@
 static int numa_debug;
 #define dbg(args...) if (numa_debug) { printk(KERN_INFO args); }
 
-#ifdef DEBUG_NUMA
-#define ARRAY_INITIALISER -1
-#else
-#define ARRAY_INITIALISER 0
-#endif
-
-int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] =
-	ARRAY_INITIALISER};
-char *numa_memory_lookup_table;
+int numa_cpu_lookup_table[NR_CPUS];
 cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES];
-int nr_cpus_in_node[MAX_NUMNODES] = { [0 ... (MAX_NUMNODES -1)] = 0};
-
 struct pglist_data *node_data[MAX_NUMNODES];
-bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
+
+EXPORT_SYMBOL(numa_cpu_lookup_table);
+EXPORT_SYMBOL(numa_cpumask_lookup_table);
+EXPORT_SYMBOL(node_data);
+
+static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
 static int min_common_depth;
 
 /*
- * We need somewhere to store start/span for each node until we have
+ * We need somewhere to store start/end/node for each region until we have
  * allocated the real node_data structures.
  */
+#define MAX_REGIONS	(MAX_LMB_REGIONS*2)
 static struct {
-	unsigned long node_start_pfn;
-	unsigned long node_end_pfn;
-	unsigned long node_present_pages;
-} init_node_data[MAX_NUMNODES] __initdata;
+	unsigned long start_pfn;
+	unsigned long end_pfn;
+	int nid;
+} init_node_data[MAX_REGIONS] __initdata;
 
-EXPORT_SYMBOL(node_data);
-EXPORT_SYMBOL(numa_cpu_lookup_table);
-EXPORT_SYMBOL(numa_memory_lookup_table);
-EXPORT_SYMBOL(numa_cpumask_lookup_table);
-EXPORT_SYMBOL(nr_cpus_in_node);
+int __init early_pfn_to_nid(unsigned long pfn)
+{
+	unsigned int i;
+
+	for (i = 0; init_node_data[i].end_pfn; i++) {
+		unsigned long start_pfn = init_node_data[i].start_pfn;
+		unsigned long end_pfn = init_node_data[i].end_pfn;
+
+		if ((start_pfn <= pfn) && (pfn < end_pfn))
+			return init_node_data[i].nid;
+	}
+
+	return -1;
+}
+
+void __init add_region(unsigned int nid, unsigned long start_pfn,
+		       unsigned long pages)
+{
+	unsigned int i;
+
+	dbg("add_region nid %d start_pfn 0x%lx pages 0x%lx\n",
+		nid, start_pfn, pages);
+
+	for (i = 0; init_node_data[i].end_pfn; i++) {
+		if (init_node_data[i].nid != nid)
+			continue;
+		if (init_node_data[i].end_pfn == start_pfn) {
+			init_node_data[i].end_pfn += pages;
+			return;
+		}
+		if (init_node_data[i].start_pfn == (start_pfn + pages)) {
+			init_node_data[i].start_pfn -= pages;
+			return;
+		}
+	}
+
+	/*
+	 * Leave last entry NULL so we dont iterate off the end (we use
+	 * entry.end_pfn to terminate the walk).
+	 */
+	if (i >= (MAX_REGIONS - 1)) {
+		printk(KERN_ERR "WARNING: too many memory regions in "
+				"numa code, truncating\n");
+		return;
+	}
+
+	init_node_data[i].start_pfn = start_pfn;
+	init_node_data[i].end_pfn = start_pfn + pages;
+	init_node_data[i].nid = nid;
+}
+
+/* We assume init_node_data has no overlapping regions */
+void __init get_region(unsigned int nid, unsigned long *start_pfn,
+		       unsigned long *end_pfn, unsigned long *pages_present)
+{
+	unsigned int i;
+
+	*start_pfn = -1UL;
+	*end_pfn = *pages_present = 0;
+
+	for (i = 0; init_node_data[i].end_pfn; i++) {
+		if (init_node_data[i].nid != nid)
+			continue;
+
+		*pages_present += init_node_data[i].end_pfn -
+			init_node_data[i].start_pfn;
+
+		if (init_node_data[i].start_pfn < *start_pfn)
+			*start_pfn = init_node_data[i].start_pfn;
+
+		if (init_node_data[i].end_pfn > *end_pfn)
+			*end_pfn = init_node_data[i].end_pfn;
+	}
+
+	/* We didnt find a matching region, return start/end as 0 */
+	if (*start_pfn == -1UL)
+		start_pfn = 0;
+}
 
 static inline void map_cpu_to_node(int cpu, int node)
 {
 	numa_cpu_lookup_table[cpu] = node;
-	if (!(cpu_isset(cpu, numa_cpumask_lookup_table[node]))) {
+
+	if (!(cpu_isset(cpu, numa_cpumask_lookup_table[node])))
 		cpu_set(cpu, numa_cpumask_lookup_table[node]);
-		nr_cpus_in_node[node]++;
-	}
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -78,7 +145,6 @@
 
 	if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) {
 		cpu_clear(cpu, numa_cpumask_lookup_table[node]);
-		nr_cpus_in_node[node]--;
 	} else {
 		printk(KERN_ERR "WARNING: cpu %lu not found in node %d\n",
 		       cpu, node);
@@ -86,7 +152,7 @@
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static struct device_node * __devinit find_cpu_node(unsigned int cpu)
+static struct device_node *find_cpu_node(unsigned int cpu)
 {
 	unsigned int hw_cpuid = get_hard_smp_processor_id(cpu);
 	struct device_node *cpu_node = NULL;
@@ -213,7 +279,7 @@
 	return rc;
 }
 
-static unsigned long read_n_cells(int n, unsigned int **buf)
+static unsigned long __init read_n_cells(int n, unsigned int **buf)
 {
 	unsigned long result = 0;
 
@@ -295,7 +361,8 @@
  * or zero. If the returned value of size is 0 the region should be
  * discarded as it lies wholy above the memory limit.
  */
-static unsigned long __init numa_enforce_memory_limit(unsigned long start, unsigned long size)
+static unsigned long __init numa_enforce_memory_limit(unsigned long start,
+						      unsigned long size)
 {
 	/*
 	 * We use lmb_end_of_DRAM() in here instead of memory_limit because
@@ -320,8 +387,7 @@
 	struct device_node *cpu = NULL;
 	struct device_node *memory = NULL;
 	int addr_cells, size_cells;
-	int max_domain = 0;
-	long entries = lmb_end_of_DRAM() >> MEMORY_INCREMENT_SHIFT;
+	int max_domain;
 	unsigned long i;
 
 	if (numa_enabled == 0) {
@@ -329,13 +395,6 @@
 		return -1;
 	}
 
-	numa_memory_lookup_table =
-		(char *)abs_to_virt(lmb_alloc(entries * sizeof(char), 1));
-	memset(numa_memory_lookup_table, 0, entries * sizeof(char));
-
-	for (i = 0; i < entries ; i++)
-		numa_memory_lookup_table[i] = ARRAY_INITIALISER;
-
 	min_common_depth = find_min_common_depth();
 
 	dbg("NUMA associativity depth for CPU/Memory: %d\n", min_common_depth);
@@ -387,9 +446,6 @@
 		start = read_n_cells(addr_cells, &memcell_buf);
 		size = read_n_cells(size_cells, &memcell_buf);
 
-		start = _ALIGN_DOWN(start, MEMORY_INCREMENT);
-		size = _ALIGN_UP(size, MEMORY_INCREMENT);
-
 		numa_domain = of_node_numa_domain(memory);
 
 		if (numa_domain >= MAX_NUMNODES) {
@@ -403,44 +459,15 @@
 		if (max_domain < numa_domain)
 			max_domain = numa_domain;
 
-		if (! (size = numa_enforce_memory_limit(start, size))) {
+		if (!(size = numa_enforce_memory_limit(start, size))) {
 			if (--ranges)
 				goto new_range;
 			else
 				continue;
 		}
 
-		/*
-		 * Initialize new node struct, or add to an existing one.
-		 */
-		if (init_node_data[numa_domain].node_end_pfn) {
-			if ((start / PAGE_SIZE) <
-			    init_node_data[numa_domain].node_start_pfn)
-				init_node_data[numa_domain].node_start_pfn =
-					start / PAGE_SIZE;
-			if (((start / PAGE_SIZE) + (size / PAGE_SIZE)) >
-			    init_node_data[numa_domain].node_end_pfn)
-				init_node_data[numa_domain].node_end_pfn =
-					(start / PAGE_SIZE) +
-					(size / PAGE_SIZE);
-
-			init_node_data[numa_domain].node_present_pages +=
-				size / PAGE_SIZE;
-		} else {
-			node_set_online(numa_domain);
-
-			init_node_data[numa_domain].node_start_pfn =
-				start / PAGE_SIZE;
-			init_node_data[numa_domain].node_end_pfn =
-				init_node_data[numa_domain].node_start_pfn +
-				size / PAGE_SIZE;
-			init_node_data[numa_domain].node_present_pages =
-				size / PAGE_SIZE;
-		}
-
-		for (i = start ; i < (start+size); i += MEMORY_INCREMENT)
-			numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] =
-				numa_domain;
+		add_region(numa_domain, start >> PAGE_SHIFT,
+			   size >> PAGE_SHIFT);
 
 		if (--ranges)
 			goto new_range;
@@ -456,32 +483,15 @@
 {
 	unsigned long top_of_ram = lmb_end_of_DRAM();
 	unsigned long total_ram = lmb_phys_mem_size();
-	unsigned long i;
 
 	printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
 	       top_of_ram, total_ram);
 	printk(KERN_INFO "Memory hole size: %ldMB\n",
 	       (top_of_ram - total_ram) >> 20);
 
-	if (!numa_memory_lookup_table) {
-		long entries = top_of_ram >> MEMORY_INCREMENT_SHIFT;
-		numa_memory_lookup_table =
-			(char *)abs_to_virt(lmb_alloc(entries * sizeof(char), 1));
-		memset(numa_memory_lookup_table, 0, entries * sizeof(char));
-		for (i = 0; i < entries ; i++)
-			numa_memory_lookup_table[i] = ARRAY_INITIALISER;
-	}
-
 	map_cpu_to_node(boot_cpuid, 0);
-
+	add_region(0, 0, lmb_end_of_DRAM() >> PAGE_SHIFT);
 	node_set_online(0);
-
-	init_node_data[0].node_start_pfn = 0;
-	init_node_data[0].node_end_pfn = lmb_end_of_DRAM() / PAGE_SIZE;
-	init_node_data[0].node_present_pages = total_ram / PAGE_SIZE;
-
-	for (i = 0 ; i < top_of_ram; i += MEMORY_INCREMENT)
-		numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = 0;
 }
 
 static void __init dump_numa_topology(void)
@@ -499,8 +509,9 @@
 
 		count = 0;
 
-		for (i = 0; i < lmb_end_of_DRAM(); i += MEMORY_INCREMENT) {
-			if (numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] == node) {
+		for (i = 0; i < lmb_end_of_DRAM();
+		     i += (1 << SECTION_SIZE_BITS)) {
+			if (early_pfn_to_nid(i >> PAGE_SHIFT) == node) {
 				if (count == 0)
 					printk(" 0x%lx", i);
 				++count;
@@ -525,10 +536,12 @@
  *
  * Returns the physical address of the memory.
  */
-static unsigned long careful_allocation(int nid, unsigned long size,
-					unsigned long align, unsigned long end)
+static void __init *careful_allocation(int nid, unsigned long size,
+				       unsigned long align,
+				       unsigned long end_pfn)
 {
-	unsigned long ret = lmb_alloc_base(size, align, end);
+	int new_nid;
+	unsigned long ret = lmb_alloc_base(size, align, end_pfn << PAGE_SHIFT);
 
 	/* retry over all memory */
 	if (!ret)
@@ -542,28 +555,27 @@
 	 * If the memory came from a previously allocated node, we must
 	 * retry with the bootmem allocator.
 	 */
-	if (pa_to_nid(ret) < nid) {
-		nid = pa_to_nid(ret);
-		ret = (unsigned long)__alloc_bootmem_node(NODE_DATA(nid),
+	new_nid = early_pfn_to_nid(ret >> PAGE_SHIFT);
+	if (new_nid < nid) {
+		ret = (unsigned long)__alloc_bootmem_node(NODE_DATA(new_nid),
 				size, align, 0);
 
 		if (!ret)
 			panic("numa.c: cannot allocate %lu bytes on node %d",
-			      size, nid);
+			      size, new_nid);
 
-		ret = virt_to_abs(ret);
+		ret = __pa(ret);
 
 		dbg("alloc_bootmem %lx %lx\n", ret, size);
 	}
 
-	return ret;
+	return (void *)ret;
 }
 
 void __init do_init_bootmem(void)
 {
 	int nid;
-	int addr_cells, size_cells;
-	struct device_node *memory = NULL;
+	unsigned int i;
 	static struct notifier_block ppc64_numa_nb = {
 		.notifier_call = cpu_numa_callback,
 		.priority = 1 /* Must run before sched domains notifier. */
@@ -581,99 +593,66 @@
 	register_cpu_notifier(&ppc64_numa_nb);
 
 	for_each_online_node(nid) {
-		unsigned long start_paddr, end_paddr;
-		int i;
+		unsigned long start_pfn, end_pfn, pages_present;
 		unsigned long bootmem_paddr;
 		unsigned long bootmap_pages;
 
-		start_paddr = init_node_data[nid].node_start_pfn * PAGE_SIZE;
-		end_paddr = init_node_data[nid].node_end_pfn * PAGE_SIZE;
+		get_region(nid, &start_pfn, &end_pfn, &pages_present);
 
 		/* Allocate the node structure node local if possible */
-		NODE_DATA(nid) = (struct pglist_data *)careful_allocation(nid,
+		NODE_DATA(nid) = careful_allocation(nid,
 					sizeof(struct pglist_data),
-					SMP_CACHE_BYTES, end_paddr);
-		NODE_DATA(nid) = abs_to_virt(NODE_DATA(nid));
+					SMP_CACHE_BYTES, end_pfn);
+		NODE_DATA(nid) = __va(NODE_DATA(nid));
 		memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
 
   		dbg("node %d\n", nid);
 		dbg("NODE_DATA() = %p\n", NODE_DATA(nid));
 
 		NODE_DATA(nid)->bdata = &plat_node_bdata[nid];
-		NODE_DATA(nid)->node_start_pfn =
-			init_node_data[nid].node_start_pfn;
-		NODE_DATA(nid)->node_spanned_pages =
-			end_paddr - start_paddr;
+		NODE_DATA(nid)->node_start_pfn = start_pfn;
+		NODE_DATA(nid)->node_spanned_pages = end_pfn - start_pfn;
 
 		if (NODE_DATA(nid)->node_spanned_pages == 0)
   			continue;
 
-  		dbg("start_paddr = %lx\n", start_paddr);
-  		dbg("end_paddr = %lx\n", end_paddr);
+  		dbg("start_paddr = %lx\n", start_pfn << PAGE_SHIFT);
+  		dbg("end_paddr = %lx\n", end_pfn << PAGE_SHIFT);
 
-		bootmap_pages = bootmem_bootmap_pages((end_paddr - start_paddr) >> PAGE_SHIFT);
+		bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
+		bootmem_paddr = (unsigned long)careful_allocation(nid,
+					bootmap_pages << PAGE_SHIFT,
+					PAGE_SIZE, end_pfn);
+		memset(__va(bootmem_paddr), 0, bootmap_pages << PAGE_SHIFT);
 
-		bootmem_paddr = careful_allocation(nid,
-				bootmap_pages << PAGE_SHIFT,
-				PAGE_SIZE, end_paddr);
-		memset(abs_to_virt(bootmem_paddr), 0,
-		       bootmap_pages << PAGE_SHIFT);
 		dbg("bootmap_paddr = %lx\n", bootmem_paddr);
 
 		init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT,
-				  start_paddr >> PAGE_SHIFT,
-				  end_paddr >> PAGE_SHIFT);
+				  start_pfn, end_pfn);
 
-		/*
-		 * We need to do another scan of all memory sections to
-		 * associate memory with the correct node.
-		 */
-		addr_cells = get_mem_addr_cells();
-		size_cells = get_mem_size_cells();
-		memory = NULL;
-		while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
-			unsigned long mem_start, mem_size;
-			int numa_domain, ranges;
-			unsigned int *memcell_buf;
-			unsigned int len;
+		/* Add free regions on this node */
+		for (i = 0; init_node_data[i].end_pfn; i++) {
+			unsigned long start, end;
 
-			memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
-			if (!memcell_buf || len <= 0)
+			if (init_node_data[i].nid != nid)
 				continue;
 
-			ranges = memory->n_addrs;	/* ranges in cell */
-new_range:
-			mem_start = read_n_cells(addr_cells, &memcell_buf);
-			mem_size = read_n_cells(size_cells, &memcell_buf);
-			if (numa_enabled) {
-				numa_domain = of_node_numa_domain(memory);
-				if (numa_domain  >= MAX_NUMNODES)
-					numa_domain = 0;
-			} else
-				numa_domain =  0;
+			start = init_node_data[i].start_pfn << PAGE_SHIFT;
+			end = init_node_data[i].end_pfn << PAGE_SHIFT;
 
-			if (numa_domain != nid)
-				continue;
-
-			mem_size = numa_enforce_memory_limit(mem_start, mem_size);
-  			if (mem_size) {
-  				dbg("free_bootmem %lx %lx\n", mem_start, mem_size);
-  				free_bootmem_node(NODE_DATA(nid), mem_start, mem_size);
-			}
-
-			if (--ranges)		/* process all ranges in cell */
-				goto new_range;
+			dbg("free_bootmem %lx %lx\n", start, end - start);
+  			free_bootmem_node(NODE_DATA(nid), start, end - start);
 		}
 
-		/*
-		 * Mark reserved regions on this node
-		 */
+		/* Mark reserved regions on this node */
 		for (i = 0; i < lmb.reserved.cnt; i++) {
 			unsigned long physbase = lmb.reserved.region[i].base;
 			unsigned long size = lmb.reserved.region[i].size;
+			unsigned long start_paddr = start_pfn << PAGE_SHIFT;
+			unsigned long end_paddr = end_pfn << PAGE_SHIFT;
 
-			if (pa_to_nid(physbase) != nid &&
-			    pa_to_nid(physbase+size-1) != nid)
+			if (early_pfn_to_nid(physbase >> PAGE_SHIFT) != nid &&
+			    early_pfn_to_nid((physbase+size-1) >> PAGE_SHIFT) != nid)
 				continue;
 
 			if (physbase < end_paddr &&
@@ -693,46 +672,19 @@
 						     size);
 			}
 		}
-		/*
-		 * This loop may look famaliar, but we have to do it again
-		 * after marking our reserved memory to mark memory present
-		 * for sparsemem.
-		 */
-		addr_cells = get_mem_addr_cells();
-		size_cells = get_mem_size_cells();
-		memory = NULL;
-		while ((memory = of_find_node_by_type(memory, "memory")) != NULL) {
-			unsigned long mem_start, mem_size;
-			int numa_domain, ranges;
-			unsigned int *memcell_buf;
-			unsigned int len;
 
-			memcell_buf = (unsigned int *)get_property(memory, "reg", &len);
-			if (!memcell_buf || len <= 0)
+		/* Add regions into sparsemem */
+		for (i = 0; init_node_data[i].end_pfn; i++) {
+			unsigned long start, end;
+
+			if (init_node_data[i].nid != nid)
 				continue;
 
-			ranges = memory->n_addrs;	/* ranges in cell */
-new_range2:
-			mem_start = read_n_cells(addr_cells, &memcell_buf);
-			mem_size = read_n_cells(size_cells, &memcell_buf);
-			if (numa_enabled) {
-				numa_domain = of_node_numa_domain(memory);
-				if (numa_domain  >= MAX_NUMNODES)
-					numa_domain = 0;
-			} else
-				numa_domain =  0;
+			start = init_node_data[i].start_pfn;
+			end = init_node_data[i].end_pfn;
 
-			if (numa_domain != nid)
-				continue;
-
-			mem_size = numa_enforce_memory_limit(mem_start, mem_size);
-			memory_present(numa_domain, mem_start >> PAGE_SHIFT,
-				       (mem_start + mem_size) >> PAGE_SHIFT);
-
-			if (--ranges)		/* process all ranges in cell */
-				goto new_range2;
+			memory_present(nid, start, end);
 		}
-
 	}
 }
 
@@ -746,21 +698,18 @@
 	memset(zholes_size, 0, sizeof(zholes_size));
 
 	for_each_online_node(nid) {
-		unsigned long start_pfn;
-		unsigned long end_pfn;
+		unsigned long start_pfn, end_pfn, pages_present;
 
-		start_pfn = init_node_data[nid].node_start_pfn;
-		end_pfn = init_node_data[nid].node_end_pfn;
+		get_region(nid, &start_pfn, &end_pfn, &pages_present);
 
 		zones_size[ZONE_DMA] = end_pfn - start_pfn;
-		zholes_size[ZONE_DMA] = zones_size[ZONE_DMA] -
-			init_node_data[nid].node_present_pages;
+		zholes_size[ZONE_DMA] = zones_size[ZONE_DMA] - pages_present;
 
 		dbg("free_area_init node %d %lx %lx (hole: %lx)\n", nid,
 		    zones_size[ZONE_DMA], start_pfn, zholes_size[ZONE_DMA]);
 
-		free_area_init_node(nid, NODE_DATA(nid), zones_size,
-							start_pfn, zholes_size);
+		free_area_init_node(nid, NODE_DATA(nid), zones_size, start_pfn,
+				    zholes_size);
 	}
 }
 
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 9008424..c7f7bb6 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -122,8 +122,11 @@
 		 *
 		 */
 		if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags,
-				      mmu_virtual_psize))
-			panic("Can't map bolted IO mapping");
+				      mmu_virtual_psize)) {
+			printk(KERN_ERR "Failed to do bolted mapping IO "
+			       "memory at %016lx !\n", pa);
+			return -ENOMEM;
+		}
 	}
 	return 0;
 }
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index fa325db..cfbb4e1 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -20,6 +20,7 @@
 #include <asm/cputable.h>
 #include <asm/lmb.h>
 #include <asm/abs_addr.h>
+#include <asm/firmware.h>
 
 struct stab_entry {
 	unsigned long esid_data;
@@ -256,7 +257,7 @@
 
 		paca[cpu].stab_addr = newstab;
 		paca[cpu].stab_real = virt_to_abs(newstab);
-		printk(KERN_DEBUG "Segment table for CPU %d at 0x%lx "
+		printk(KERN_INFO "Segment table for CPU %d at 0x%lx "
 		       "virtual, 0x%lx absolute\n",
 		       cpu, paca[cpu].stab_addr, paca[cpu].stab_real);
 	}
@@ -270,10 +271,28 @@
 void stab_initialize(unsigned long stab)
 {
 	unsigned long vsid = get_kernel_vsid(KERNELBASE);
+	unsigned long stabreal;
 
 	asm volatile("isync; slbia; isync":::"memory");
 	make_ste(stab, GET_ESID(KERNELBASE), vsid);
 
 	/* Order update */
 	asm volatile("sync":::"memory");
+
+	/* Set ASR */
+	stabreal = get_paca()->stab_real | 0x1ul;
+
+#ifdef CONFIG_PPC_ISERIES
+	if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+		HvCall1(HvCallBaseSetASR, stabreal);
+		return;
+	}
+#endif /* CONFIG_PPC_ISERIES */
+#ifdef CONFIG_PPC_PSERIES
+	if (platform_is_lpar()) {
+		plpar_hcall_norets(H_SET_ASR, stabreal);
+		return;
+	}
+#endif
+	mtspr(SPRN_ASR, stabreal);
 }
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index c4ee547..a3401b4 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -14,7 +14,6 @@
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
-#include <asm/systemcfg.h>
 #include <asm/rtas.h>
 #include <asm/oprofile_impl.h>
 #include <asm/reg.h>
@@ -233,8 +232,7 @@
 	mmcra = mfspr(SPRN_MMCRA);
 
 	/* Were we in the hypervisor? */
-	if ((systemcfg->platform == PLATFORM_PSERIES_LPAR) &&
-	    (mmcra & MMCRA_SIHV))
+	if (platform_is_lpar() && (mmcra & MMCRA_SIHV))
 		/* function descriptor madness */
 		return *((unsigned long *)hypervisor_bucket);
 
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index ecd32d5..4099dda 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -361,7 +361,9 @@
 	printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
 
 	irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */
-	prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS - 4);
+	prom_get_irq_senses(init_senses, NUM_ISA_INTERRUPTS, NR_IRQS - 4);
+	/* i8259 cascade is always positive level */
+	init_senses[0] = IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE;
 
 	iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len);
 	if (iranges == NULL)
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index a06603d..01090e9 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -103,6 +103,9 @@
 		struct pt_regs *regsParm)
 {
 	int irq;
+#ifdef CONFIG_IRQSTACKS
+	struct thread_info *curtp, *irqtp;
+#endif
 
 	++Pci_Interrupt_Count;
 
@@ -110,7 +113,20 @@
 	case XmPciLpEvent_SlotInterrupt:
 		irq = eventParm->hvLpEvent.xCorrelationToken;
 		/* Dispatch the interrupt handlers for this irq */
-		ppc_irq_dispatch_handler(regsParm, irq);
+#ifdef CONFIG_IRQSTACKS
+		/* Switch to the irq stack to handle this */
+		curtp = current_thread_info();
+		irqtp = hardirq_ctx[smp_processor_id()];
+		if (curtp != irqtp) {
+			irqtp->task = curtp->task;
+			irqtp->flags = 0;
+			call___do_IRQ(irq, regsParm, irqtp);
+			irqtp->task = NULL;
+			if (irqtp->flags)
+				set_bits(irqtp->flags, &curtp->flags);
+		} else
+#endif
+			__do_IRQ(irq, regsParm);
 		HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
 			eventParm->eventData.slotInterrupt.subBusNumber,
 			eventParm->eventData.slotInterrupt.deviceId);
@@ -310,10 +326,8 @@
 }
 
 /*
- * Need to define this so ppc_irq_dispatch_handler will NOT call
- * enable_IRQ at the end of interrupt handling.  However, this does
- * nothing because there is not enough information provided to do
- * the EOI HvCall.  This is done by XmPciLpEvent.c
+ * This does nothing because there is not enough information
+ * provided to do the EOI HvCall.  This is done by XmPciLpEvent.c
  */
 static void iSeries_end_IRQ(unsigned int irq)
 {
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S
index 09f1452..dfe7aa1 100644
--- a/arch/powerpc/platforms/iseries/misc.S
+++ b/arch/powerpc/platforms/iseries/misc.S
@@ -15,6 +15,7 @@
 
 #include <asm/processor.h>
 #include <asm/asm-offsets.h>
+#include <asm/ppc_asm.h>
 
 	.text
 
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index d3e4bf7..6a29f30 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -39,7 +39,8 @@
 #include <asm/sections.h>
 #include <asm/iommu.h>
 #include <asm/firmware.h>
-
+#include <asm/systemcfg.h>
+#include <asm/system.h>
 #include <asm/time.h>
 #include <asm/paca.h>
 #include <asm/cache.h>
@@ -71,7 +72,7 @@
 #endif
 
 /* Function Prototypes */
-static void build_iSeries_Memory_Map(void);
+static unsigned long build_iSeries_Memory_Map(void);
 static void iseries_shared_idle(void);
 static void iseries_dedicated_idle(void);
 #ifdef CONFIG_PCI
@@ -84,7 +85,6 @@
 int piranha_simulator;
 
 extern int rd_size;		/* Defined in drivers/block/rd.c */
-extern unsigned long klimit;
 extern unsigned long embedded_sysmap_start;
 extern unsigned long embedded_sysmap_end;
 
@@ -403,9 +403,11 @@
  * a table used to translate Linux's physical addresses to these
  * absolute addresses.  Absolute addresses are needed when
  * communicating with the hypervisor (e.g. to build HPT entries)
+ *
+ * Returns the physical memory size
  */
 
-static void __init build_iSeries_Memory_Map(void)
+static unsigned long __init build_iSeries_Memory_Map(void)
 {
 	u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize;
 	u32 nextPhysChunk;
@@ -538,7 +540,7 @@
 	 * which should be equal to
 	 *   nextPhysChunk
 	 */
-	systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk);
+	return chunk_to_addr(nextPhysChunk);
 }
 
 /*
@@ -564,8 +566,8 @@
 	printk("Max physical processors = %d\n",
 			itVpdAreas.xSlicMaxPhysicalProcs);
 
-	systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR;
-	printk("Processor version = %x\n", systemcfg->processor);
+	_systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR;
+	printk("Processor version = %x\n", _systemcfg->processor);
 }
 
 static void iSeries_show_cpuinfo(struct seq_file *m)
@@ -694,20 +696,18 @@
 		if (hvlpevent_is_pending())
 			process_iSeries_events();
 
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
 static void iseries_dedicated_idle(void)
 {
-	long oldval;
+	set_thread_flag(TIF_POLLING_NRFLAG);
 
 	while (1) {
-		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
-		if (!oldval) {
-			set_thread_flag(TIF_POLLING_NRFLAG);
-
+		if (!need_resched()) {
 			while (!need_resched()) {
 				ppc64_runlatch_off();
 				HMT_low();
@@ -720,13 +720,12 @@
 			}
 
 			HMT_medium();
-			clear_thread_flag(TIF_POLLING_NRFLAG);
-		} else {
-			set_need_resched();
 		}
 
 		ppc64_runlatch_on();
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
@@ -931,7 +930,7 @@
 	dt_end_node(dt);
 }
 
-void build_flat_dt(struct iseries_flat_dt *dt)
+void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
 {
 	u64 tmp[2];
 
@@ -947,7 +946,7 @@
 	dt_prop_str(dt, "name", "memory");
 	dt_prop_str(dt, "device_type", "memory");
 	tmp[0] = 0;
-	tmp[1] = systemcfg->physicalMemorySize;
+	tmp[1] = phys_mem_size;
 	dt_prop_u64_list(dt, "reg", tmp, 2);
 	dt_end_node(dt);
 
@@ -967,13 +966,15 @@
 
 void * __init iSeries_early_setup(void)
 {
+	unsigned long phys_mem_size;
+
 	iSeries_fixup_klimit();
 
 	/*
 	 * Initialize the table which translate Linux physical addresses to
 	 * AS/400 absolute addresses
 	 */
-	build_iSeries_Memory_Map();
+	phys_mem_size = build_iSeries_Memory_Map();
 
 	iSeries_get_cmdline();
 
@@ -983,7 +984,7 @@
 	/* Parse early parameters, in particular mem=x */
 	parse_early_param();
 
-	build_flat_dt(&iseries_dt);
+	build_flat_dt(&iseries_dt, phys_mem_size);
 
 	return (void *) __pa(&iseries_dt);
 }
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 340c21c..895aeb3 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -380,9 +380,6 @@
 	for_each_pci_dev(dev)
 		pci_read_irq_line(dev);
 
-	/* Do the mapping of the IO space */
-	phbs_remap_io();
-
 	DBG(" <- maple_pcibios_fixup\n");
 }
 
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 8f818d0..dfd41b9 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -918,9 +918,6 @@
 			PCI_DN(np)->busno = 0xf0;
 	}
 
-	/* map in PCI I/O space */
-	phbs_remap_io();
-
 	/* pmac_check_ht_link(); */
 
 	/* Tell pci.c to not use the common resource allocation mechanism */
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 83a49e8..90040c4 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -74,6 +74,9 @@
 #define GATWICK_IRQ_POOL_SIZE        10
 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
 
+#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
+static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
+
 /*
  * Mark an irq as "lost".  This is only used on the pmac
  * since it can lose interrupts (see pmac_set_irq_mask).
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index e1f9443..957b091 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -305,9 +305,19 @@
 	psurge_start = ioremap(PSURGE_START, 4);
 	psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
 
-	/* this is not actually strictly necessary -- paulus. */
-	for (i = 1; i < ncpus; ++i)
-		smp_hw_index[i] = i;
+	/*
+	 * This is necessary because OF doesn't know about the
+	 * secondary cpu(s), and thus there aren't nodes in the
+	 * device tree for them, and smp_setup_cpu_maps hasn't
+	 * set their bits in cpu_possible_map and cpu_present_map.
+	 */
+	if (ncpus > NR_CPUS)
+		ncpus = NR_CPUS;
+	for (i = 1; i < ncpus ; ++i) {
+		cpu_set(i, cpu_present_map);
+		cpu_set(i, cpu_possible_map);
+		set_hard_smp_processor_id(i, i);
+	}
 
 	if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
 
@@ -348,6 +358,7 @@
 	int t;
 
 	set_dec(tb_ticks_per_jiffy);
+	/* XXX fixme */
 	set_tb(0, 0);
 	last_jiffy_stamp(cpu_nr) = 0;
 
@@ -363,8 +374,6 @@
 
 	/* now interrupt the secondary, starting both TBs */
 	psurge_set_ipi(1);
-
-	smp_tb_synchronized = 1;
 }
 
 static struct irqaction psurge_irqaction = {
@@ -625,9 +634,8 @@
 	for (t = 100000; t > 0 && sec_tb_reset; --t)
 		udelay(10);
 	if (sec_tb_reset)
+		/* XXX BUG_ON here? */
 		printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");
-	else
-		smp_tb_synchronized = 1;
 
 	/* Now, restart the timebase by leaving the GPIO to an open collector */
        	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
@@ -810,19 +818,9 @@
 }
 
 
-/* Core99 Macs (dual G4s and G5s) */
-struct smp_ops_t core99_smp_ops = {
-	.message_pass	= smp_mpic_message_pass,
-	.probe		= smp_core99_probe,
-	.kick_cpu	= smp_core99_kick_cpu,
-	.setup_cpu	= smp_core99_setup_cpu,
-	.give_timebase	= smp_core99_give_timebase,
-	.take_timebase	= smp_core99_take_timebase,
-};
-
 #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)
 
-int __cpu_disable(void)
+int smp_core99_cpu_disable(void)
 {
 	cpu_clear(smp_processor_id(), cpu_online_map);
 
@@ -846,7 +844,7 @@
 	low_cpu_die();
 }
 
-void __cpu_die(unsigned int cpu)
+void smp_core99_cpu_die(unsigned int cpu)
 {
 	int timeout;
 
@@ -858,8 +856,21 @@
 		}
 		msleep(1);
 	}
-	cpu_callin_map[cpu] = 0;
 	cpu_dead[cpu] = 0;
 }
 
 #endif
+
+/* Core99 Macs (dual G4s and G5s) */
+struct smp_ops_t core99_smp_ops = {
+	.message_pass	= smp_mpic_message_pass,
+	.probe		= smp_core99_probe,
+	.kick_cpu	= smp_core99_kick_cpu,
+	.setup_cpu	= smp_core99_setup_cpu,
+	.give_timebase	= smp_core99_give_timebase,
+	.take_timebase	= smp_core99_take_timebase,
+#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)
+	.cpu_disable	= smp_core99_cpu_disable,
+	.cpu_die	= smp_core99_cpu_die,
+#endif
+};
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index b9938fe..e7ca5b1 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -3,3 +3,5 @@
 obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_IBMVIO)	+= vio.o
 obj-$(CONFIG_XICS)	+= xics.o
+obj-$(CONFIG_SCANLOG)	+= scanlog.o
+obj-$(CONFIG_EEH)    += eeh.o eeh_event.o
diff --git a/arch/ppc64/kernel/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
similarity index 63%
rename from arch/ppc64/kernel/eeh.c
rename to arch/powerpc/platforms/pseries/eeh.c
index 035d1b1..79de231 100644
--- a/arch/ppc64/kernel/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1,39 +1,37 @@
 /*
  * eeh.c
  * Copyright (C) 2001 Dave Engebretsen & 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <linux/bootmem.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/notifier.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/rbtree.h>
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
+#include <asm/atomic.h>
 #include <asm/eeh.h>
+#include <asm/eeh_event.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/rtas.h>
-#include <asm/atomic.h>
-#include <asm/systemcfg.h>
 #include <asm/ppc-pci.h>
+#include <asm/rtas.h>
 
 #undef DEBUG
 
@@ -49,8 +47,8 @@
  *  were "empty": all reads return 0xff's and all writes are silently
  *  ignored.  EEH slot isolation events can be triggered by parity
  *  errors on the address or data busses (e.g. during posted writes),
- *  which in turn might be caused by dust, vibration, humidity,
- *  radioactivity or plain-old failed hardware.
+ *  which in turn might be caused by low voltage on the bus, dust,
+ *  vibration, humidity, radioactivity or plain-old failed hardware.
  *
  *  Note, however, that one of the leading causes of EEH slot
  *  freeze events are buggy device drivers, buggy device microcode,
@@ -71,26 +69,15 @@
  *  and sent out for processing.
  */
 
-/** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */
-#define BUID_HI(buid) ((buid) >> 32)
-#define BUID_LO(buid) ((buid) & 0xffffffff)
-
-/* EEH event workqueue setup. */
-static DEFINE_SPINLOCK(eeh_eventlist_lock);
-LIST_HEAD(eeh_eventlist);
-static void eeh_event_handler(void *);
-DECLARE_WORK(eeh_event_wq, eeh_event_handler, NULL);
-
-static struct notifier_block *eeh_notifier_chain;
-
-/*
- * If a device driver keeps reading an MMIO register in an interrupt
+/* If a device driver keeps reading an MMIO register in an interrupt
  * handler after a slot isolation event has occurred, we assume it
  * is broken and panic.  This sets the threshold for how many read
  * attempts we allow before panicking.
  */
-#define EEH_MAX_FAILS	1000
-static atomic_t eeh_fail_count;
+#define EEH_MAX_FAILS	100000
+
+/* Misc forward declaraions */
+static void eeh_save_bars(struct pci_dev * pdev, struct pci_dn *pdn);
 
 /* RTAS tokens */
 static int ibm_set_eeh_option;
@@ -101,12 +88,19 @@
 
 static int eeh_subsystem_enabled;
 
+/* Lock to avoid races due to multiple reports of an error */
+static DEFINE_SPINLOCK(confirm_error_lock);
+
 /* Buffer for reporting slot-error-detail rtas calls */
 static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
 static DEFINE_SPINLOCK(slot_errbuf_lock);
 static int eeh_error_buf_size;
 
 /* System monitoring statistics */
+static DEFINE_PER_CPU(unsigned long, no_device);
+static DEFINE_PER_CPU(unsigned long, no_dn);
+static DEFINE_PER_CPU(unsigned long, no_cfg_addr);
+static DEFINE_PER_CPU(unsigned long, ignored_check);
 static DEFINE_PER_CPU(unsigned long, total_mmio_ffs);
 static DEFINE_PER_CPU(unsigned long, false_positives);
 static DEFINE_PER_CPU(unsigned long, ignored_failures);
@@ -224,9 +218,9 @@
 	while (*p) {
 		parent = *p;
 		piar = rb_entry(parent, struct pci_io_addr_range, rb_node);
-		if (alo < piar->addr_lo) {
+		if (ahi < piar->addr_lo) {
 			p = &parent->rb_left;
-		} else if (ahi > piar->addr_hi) {
+		} else if (alo > piar->addr_hi) {
 			p = &parent->rb_right;
 		} else {
 			if (dev != piar->pcidev ||
@@ -245,6 +239,11 @@
 	piar->pcidev = dev;
 	piar->flags = flags;
 
+#ifdef DEBUG
+	printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n",
+	                  alo, ahi, pci_name (dev));
+#endif
+
 	rb_link_node(&piar->rb_node, parent, p);
 	rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root);
 
@@ -260,18 +259,17 @@
 
 	dn = pci_device_to_OF_node(dev);
 	if (!dn) {
-		printk(KERN_WARNING "PCI: no pci dn found for dev=%s\n",
-			pci_name(dev));
+		printk(KERN_WARNING "PCI: no pci dn found for dev=%s\n", pci_name(dev));
 		return;
 	}
 
 	/* Skip any devices for which EEH is not enabled. */
-	pdn = dn->data;
+	pdn = PCI_DN(dn);
 	if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
 	    pdn->eeh_mode & EEH_MODE_NOCHECK) {
 #ifdef DEBUG
-		printk(KERN_INFO "PCI: skip building address cache for=%s\n",
-		       pci_name(dev));
+		printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n",
+		       pci_name(dev), pdn->node->full_name);
 #endif
 		return;
 	}
@@ -307,7 +305,7 @@
  * we maintain a cache of devices that can be quickly searched.
  * This routine adds a device to that cache.
  */
-void pci_addr_cache_insert_device(struct pci_dev *dev)
+static void pci_addr_cache_insert_device(struct pci_dev *dev)
 {
 	unsigned long flags;
 
@@ -350,7 +348,7 @@
  * the tree multiple times (once per resource).
  * But so what; device removal doesn't need to be that fast.
  */
-void pci_addr_cache_remove_device(struct pci_dev *dev)
+static void pci_addr_cache_remove_device(struct pci_dev *dev)
 {
 	unsigned long flags;
 
@@ -370,8 +368,12 @@
  */
 void __init pci_addr_cache_build(void)
 {
+	struct device_node *dn;
 	struct pci_dev *dev = NULL;
 
+	if (!eeh_subsystem_enabled)
+		return;
+
 	spin_lock_init(&pci_io_addr_cache_root.piar_lock);
 
 	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
@@ -380,6 +382,10 @@
 			continue;
 		}
 		pci_addr_cache_insert_device(dev);
+
+		/* Save the BAR's; firmware doesn't restore these after EEH reset */
+		dn = pci_device_to_OF_node(dev);
+		eeh_save_bars(dev, PCI_DN(dn));
 	}
 
 #ifdef DEBUG
@@ -391,22 +397,26 @@
 /* --------------------------------------------------------------- */
 /* Above lies the PCI Address Cache. Below lies the EEH event infrastructure */
 
-/**
- * eeh_register_notifier - Register to find out about EEH events.
- * @nb: notifier block to callback on events
- */
-int eeh_register_notifier(struct notifier_block *nb)
+void eeh_slot_error_detail (struct pci_dn *pdn, int severity)
 {
-	return notifier_chain_register(&eeh_notifier_chain, nb);
-}
+	unsigned long flags;
+	int rc;
 
-/**
- * eeh_unregister_notifier - Unregister to an EEH event notifier.
- * @nb: notifier block to callback on events
- */
-int eeh_unregister_notifier(struct notifier_block *nb)
-{
-	return notifier_chain_unregister(&eeh_notifier_chain, nb);
+	/* Log the error with the rtas logger */
+	spin_lock_irqsave(&slot_errbuf_lock, flags);
+	memset(slot_errbuf, 0, eeh_error_buf_size);
+
+	rc = rtas_call(ibm_slot_error_detail,
+	               8, 1, NULL, pdn->eeh_config_addr,
+	               BUID_HI(pdn->phb->buid),
+	               BUID_LO(pdn->phb->buid), NULL, 0,
+	               virt_to_phys(slot_errbuf),
+	               eeh_error_buf_size,
+	               severity);
+
+	if (rc == 0)
+		log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
+	spin_unlock_irqrestore(&slot_errbuf_lock, flags);
 }
 
 /**
@@ -414,16 +424,16 @@
  * @dn: device node to read
  * @rets: array to return results in
  */
-static int read_slot_reset_state(struct device_node *dn, int rets[])
+static int read_slot_reset_state(struct pci_dn *pdn, int rets[])
 {
 	int token, outputs;
-	struct pci_dn *pdn = dn->data;
 
 	if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) {
 		token = ibm_read_slot_reset_state2;
 		outputs = 4;
 	} else {
 		token = ibm_read_slot_reset_state;
+		rets[2] = 0; /* fake PE Unavailable info */
 		outputs = 3;
 	}
 
@@ -432,75 +442,8 @@
 }
 
 /**
- * eeh_panic - call panic() for an eeh event that cannot be handled.
- * The philosophy of this routine is that it is better to panic and
- * halt the OS than it is to risk possible data corruption by
- * oblivious device drivers that don't know better.
- *
- * @dev pci device that had an eeh event
- * @reset_state current reset state of the device slot
- */
-static void eeh_panic(struct pci_dev *dev, int reset_state)
-{
-	/*
-	 * XXX We should create a separate sysctl for this.
-	 *
-	 * Since the panic_on_oops sysctl is used to halt the system
-	 * in light of potential corruption, we can use it here.
-	 */
-	if (panic_on_oops)
-		panic("EEH: MMIO failure (%d) on device:%s\n", reset_state,
-		      pci_name(dev));
-	else {
-		__get_cpu_var(ignored_failures)++;
-		printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s\n",
-		       reset_state, pci_name(dev));
-	}
-}
-
-/**
- * eeh_event_handler - dispatch EEH events.  The detection of a frozen
- * slot can occur inside an interrupt, where it can be hard to do
- * anything about it.  The goal of this routine is to pull these
- * detection events out of the context of the interrupt handler, and
- * re-dispatch them for processing at a later time in a normal context.
- *
- * @dummy - unused
- */
-static void eeh_event_handler(void *dummy)
-{
-	unsigned long flags;
-	struct eeh_event	*event;
-
-	while (1) {
-		spin_lock_irqsave(&eeh_eventlist_lock, flags);
-		event = NULL;
-		if (!list_empty(&eeh_eventlist)) {
-			event = list_entry(eeh_eventlist.next, struct eeh_event, list);
-			list_del(&event->list);
-		}
-		spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
-		if (event == NULL)
-			break;
-
-		printk(KERN_INFO "EEH: MMIO failure (%d), notifiying device "
-		       "%s\n", event->reset_state,
-		       pci_name(event->dev));
-
-		atomic_set(&eeh_fail_count, 0);
-		notifier_call_chain (&eeh_notifier_chain,
-				     EEH_NOTIFY_FREEZE, event);
-
-		__get_cpu_var(slot_resets)++;
-
-		pci_dev_put(event->dev);
-		kfree(event);
-	}
-}
-
-/**
  * eeh_token_to_phys - convert EEH address token to phys address
- * @token i/o token, should be address in the form 0xE....
+ * @token i/o token, should be address in the form 0xA....
  */
 static inline unsigned long eeh_token_to_phys(unsigned long token)
 {
@@ -515,6 +458,70 @@
 	return pa | (token & (PAGE_SIZE-1));
 }
 
+/** 
+ * Return the "partitionable endpoint" (pe) under which this device lies
+ */
+static struct device_node * find_device_pe(struct device_node *dn)
+{
+	while ((dn->parent) && PCI_DN(dn->parent) &&
+	      (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
+		dn = dn->parent;
+	}
+	return dn;
+}
+
+/** Mark all devices that are peers of this device as failed.
+ *  Mark the device driver too, so that it can see the failure
+ *  immediately; this is critical, since some drivers poll
+ *  status registers in interrupts ... If a driver is polling,
+ *  and the slot is frozen, then the driver can deadlock in
+ *  an interrupt context, which is bad.
+ */
+
+static void __eeh_mark_slot (struct device_node *dn, int mode_flag)
+{
+	while (dn) {
+		if (PCI_DN(dn)) {
+			PCI_DN(dn)->eeh_mode |= mode_flag;
+
+			if (dn->child)
+				__eeh_mark_slot (dn->child, mode_flag);
+		}
+		dn = dn->sibling;
+	}
+}
+
+void eeh_mark_slot (struct device_node *dn, int mode_flag)
+{
+	dn = find_device_pe (dn);
+	PCI_DN(dn)->eeh_mode |= mode_flag;
+	__eeh_mark_slot (dn->child, mode_flag);
+}
+
+static void __eeh_clear_slot (struct device_node *dn, int mode_flag)
+{
+	while (dn) {
+		if (PCI_DN(dn)) {
+			PCI_DN(dn)->eeh_mode &= ~mode_flag;
+			PCI_DN(dn)->eeh_check_count = 0;
+			if (dn->child)
+				__eeh_clear_slot (dn->child, mode_flag);
+		}
+		dn = dn->sibling;
+	}
+}
+
+void eeh_clear_slot (struct device_node *dn, int mode_flag)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&confirm_error_lock, flags);
+	dn = find_device_pe (dn);
+	PCI_DN(dn)->eeh_mode &= ~mode_flag;
+	PCI_DN(dn)->eeh_check_count = 0;
+	__eeh_clear_slot (dn->child, mode_flag);
+	spin_unlock_irqrestore(&confirm_error_lock, flags);
+}
+
 /**
  * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze
  * @dn device node
@@ -526,7 +533,7 @@
  * will query firmware for the EEH status.
  *
  * Returns 0 if there has not been an EEH error; otherwise returns
- * a non-zero value and queues up a solt isolation event notification.
+ * a non-zero value and queues up a slot isolation event notification.
  *
  * It is safe to call this routine in an interrupt context.
  */
@@ -535,42 +542,59 @@
 	int ret;
 	int rets[3];
 	unsigned long flags;
-	int rc, reset_state;
-	struct eeh_event  *event;
 	struct pci_dn *pdn;
+	int rc = 0;
 
 	__get_cpu_var(total_mmio_ffs)++;
 
 	if (!eeh_subsystem_enabled)
 		return 0;
 
-	if (!dn)
+	if (!dn) {
+		__get_cpu_var(no_dn)++;
 		return 0;
-	pdn = dn->data;
+	}
+	pdn = PCI_DN(dn);
 
 	/* Access to IO BARs might get this far and still not want checking. */
-	if (!pdn->eeh_capable || !(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
+	if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
 	    pdn->eeh_mode & EEH_MODE_NOCHECK) {
+		__get_cpu_var(ignored_check)++;
+#ifdef DEBUG
+		printk ("EEH:ignored check (%x) for %s %s\n", 
+		        pdn->eeh_mode, pci_name (dev), dn->full_name);
+#endif
 		return 0;
 	}
 
 	if (!pdn->eeh_config_addr) {
+		__get_cpu_var(no_cfg_addr)++;
 		return 0;
 	}
 
-	/*
-	 * If we already have a pending isolation event for this
-	 * slot, we know it's bad already, we don't need to check...
+	/* If we already have a pending isolation event for this
+	 * slot, we know it's bad already, we don't need to check.
+	 * Do this checking under a lock; as multiple PCI devices
+	 * in one slot might report errors simultaneously, and we
+	 * only want one error recovery routine running.
 	 */
+	spin_lock_irqsave(&confirm_error_lock, flags);
+	rc = 1;
 	if (pdn->eeh_mode & EEH_MODE_ISOLATED) {
-		atomic_inc(&eeh_fail_count);
-		if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) {
+		pdn->eeh_check_count ++;
+		if (pdn->eeh_check_count >= EEH_MAX_FAILS) {
+			printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n",
+			        pdn->eeh_check_count);
+			dump_stack();
+			
 			/* re-read the slot reset state */
-			if (read_slot_reset_state(dn, rets) != 0)
+			if (read_slot_reset_state(pdn, rets) != 0)
 				rets[0] = -1;	/* reset state unknown */
-			eeh_panic(dev, rets[0]);
+
+			/* If we are here, then we hit an infinite loop. Stop. */
+			panic("EEH: MMIO halt (%d) on device:%s\n", rets[0], pci_name(dev));
 		}
-		return 0;
+		goto dn_unlock;
 	}
 
 	/*
@@ -580,66 +604,69 @@
 	 * function zero of a multi-function device.
 	 * In any case they must share a common PHB.
 	 */
-	ret = read_slot_reset_state(dn, rets);
-	if (!(ret == 0 && rets[1] == 1 && (rets[0] == 2 || rets[0] == 4))) {
+	ret = read_slot_reset_state(pdn, rets);
+
+	/* If the call to firmware failed, punt */
+	if (ret != 0) {
+		printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n",
+		       ret, dn->full_name);
 		__get_cpu_var(false_positives)++;
-		return 0;
+		rc = 0;
+		goto dn_unlock;
 	}
 
-	/* prevent repeated reports of this failure */
-	pdn->eeh_mode |= EEH_MODE_ISOLATED;
+	/* If EEH is not supported on this device, punt. */
+	if (rets[1] != 1) {
+		printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
+		       ret, dn->full_name);
+		__get_cpu_var(false_positives)++;
+		rc = 0;
+		goto dn_unlock;
+	}
 
-	reset_state = rets[0];
+	/* If not the kind of error we know about, punt. */
+	if (rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
+		__get_cpu_var(false_positives)++;
+		rc = 0;
+		goto dn_unlock;
+	}
 
-	spin_lock_irqsave(&slot_errbuf_lock, flags);
-	memset(slot_errbuf, 0, eeh_error_buf_size);
+	/* Note that config-io to empty slots may fail;
+	 * we recognize empty because they don't have children. */
+	if ((rets[0] == 5) && (dn->child == NULL)) {
+		__get_cpu_var(false_positives)++;
+		rc = 0;
+		goto dn_unlock;
+	}
 
-	rc = rtas_call(ibm_slot_error_detail,
-	               8, 1, NULL, pdn->eeh_config_addr,
-	               BUID_HI(pdn->phb->buid),
-	               BUID_LO(pdn->phb->buid), NULL, 0,
-	               virt_to_phys(slot_errbuf),
-	               eeh_error_buf_size,
-	               1 /* Temporary Error */);
+	__get_cpu_var(slot_resets)++;
+ 
+	/* Avoid repeated reports of this failure, including problems
+	 * with other functions on this device, and functions under
+	 * bridges. */
+	eeh_mark_slot (dn, EEH_MODE_ISOLATED);
+	spin_unlock_irqrestore(&confirm_error_lock, flags);
 
-	if (rc == 0)
-		log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
-	spin_unlock_irqrestore(&slot_errbuf_lock, flags);
-
-	printk(KERN_INFO "EEH: MMIO failure (%d) on device: %s %s\n",
-	       rets[0], dn->name, dn->full_name);
-	event = kmalloc(sizeof(*event), GFP_ATOMIC);
-	if (event == NULL) {
-		eeh_panic(dev, reset_state);
-		return 1;
- 	}
-
-	event->dev = dev;
-	event->dn = dn;
-	event->reset_state = reset_state;
-
-	/* We may or may not be called in an interrupt context */
-	spin_lock_irqsave(&eeh_eventlist_lock, flags);
-	list_add(&event->list, &eeh_eventlist);
-	spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
-
+	eeh_send_failure_event (dn, dev, rets[0], rets[2]);
+	
 	/* Most EEH events are due to device driver bugs.  Having
 	 * a stack trace will help the device-driver authors figure
 	 * out what happened.  So print that out. */
-	dump_stack();
-	schedule_work(&eeh_event_wq);
+	if (rets[0] != 5) dump_stack();
+	return 1;
 
-	return 0;
+dn_unlock:
+	spin_unlock_irqrestore(&confirm_error_lock, flags);
+	return rc;
 }
 
-EXPORT_SYMBOL(eeh_dn_check_failure);
+EXPORT_SYMBOL_GPL(eeh_dn_check_failure);
 
 /**
  * eeh_check_failure - check if all 1's data is due to EEH slot freeze
  * @token i/o token, should be address in the form 0xA....
  * @val value, should be all 1's (XXX why do we need this arg??)
  *
- * Check for an eeh failure at the given token address.
  * Check for an EEH failure at the given token address.  Call this
  * routine if the result of a read was all 0xff's and you want to
  * find out if this is due to an EEH slot freeze event.  This routine
@@ -656,8 +683,10 @@
 	/* Finding the phys addr + pci device; this is pretty quick. */
 	addr = eeh_token_to_phys((unsigned long __force) token);
 	dev = pci_get_device_by_addr(addr);
-	if (!dev)
+	if (!dev) {
+		__get_cpu_var(no_device)++;
 		return val;
+	}
 
 	dn = pci_device_to_OF_node(dev);
 	eeh_dn_check_failure (dn, dev);
@@ -668,6 +697,217 @@
 
 EXPORT_SYMBOL(eeh_check_failure);
 
+/* ------------------------------------------------------------- */
+/* The code below deals with error recovery */
+
+/** Return negative value if a permanent error, else return
+ * a number of milliseconds to wait until the PCI slot is
+ * ready to be used.
+ */
+static int
+eeh_slot_availability(struct pci_dn *pdn)
+{
+	int rc;
+	int rets[3];
+
+	rc = read_slot_reset_state(pdn, rets);
+
+	if (rc) return rc;
+
+	if (rets[1] == 0) return -1;  /* EEH is not supported */
+	if (rets[0] == 0)  return 0;  /* Oll Korrect */
+	if (rets[0] == 5) {
+		if (rets[2] == 0) return -1; /* permanently unavailable */
+		return rets[2]; /* number of millisecs to wait */
+	}
+	return -1;
+}
+
+/** rtas_pci_slot_reset raises/lowers the pci #RST line
+ *  state: 1/0 to raise/lower the #RST
+ *
+ * Clear the EEH-frozen condition on a slot.  This routine
+ * asserts the PCI #RST line if the 'state' argument is '1',
+ * and drops the #RST line if 'state is '0'.  This routine is
+ * safe to call in an interrupt context.
+ *
+ */
+
+static void
+rtas_pci_slot_reset(struct pci_dn *pdn, int state)
+{
+	int rc;
+
+	BUG_ON (pdn==NULL); 
+
+	if (!pdn->phb) {
+		printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n",
+		        pdn->node->full_name);
+		return;
+	}
+
+	rc = rtas_call(ibm_set_slot_reset,4,1, NULL,
+	               pdn->eeh_config_addr,
+	               BUID_HI(pdn->phb->buid),
+	               BUID_LO(pdn->phb->buid),
+	               state);
+	if (rc) {
+		printk (KERN_WARNING "EEH: Unable to reset the failed slot, (%d) #RST=%d dn=%s\n", 
+		        rc, state, pdn->node->full_name);
+		return;
+	}
+}
+
+/** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
+ *  dn -- device node to be reset.
+ */
+
+void
+rtas_set_slot_reset(struct pci_dn *pdn)
+{
+	int i, rc;
+
+	rtas_pci_slot_reset (pdn, 1);
+
+	/* The PCI bus requires that the reset be held high for at least
+	 * a 100 milliseconds. We wait a bit longer 'just in case'.  */
+
+#define PCI_BUS_RST_HOLD_TIME_MSEC 250
+	msleep (PCI_BUS_RST_HOLD_TIME_MSEC);
+	
+	/* We might get hit with another EEH freeze as soon as the 
+	 * pci slot reset line is dropped. Make sure we don't miss
+	 * these, and clear the flag now. */
+	eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED);
+
+	rtas_pci_slot_reset (pdn, 0);
+
+	/* After a PCI slot has been reset, the PCI Express spec requires
+	 * a 1.5 second idle time for the bus to stabilize, before starting
+	 * up traffic. */
+#define PCI_BUS_SETTLE_TIME_MSEC 1800
+	msleep (PCI_BUS_SETTLE_TIME_MSEC);
+
+	/* Now double check with the firmware to make sure the device is
+	 * ready to be used; if not, wait for recovery. */
+	for (i=0; i<10; i++) {
+		rc = eeh_slot_availability (pdn);
+		if (rc <= 0) break;
+
+		msleep (rc+100);
+	}
+}
+
+/* ------------------------------------------------------- */
+/** Save and restore of PCI BARs
+ *
+ * Although firmware will set up BARs during boot, it doesn't
+ * set up device BAR's after a device reset, although it will,
+ * if requested, set up bridge configuration. Thus, we need to
+ * configure the PCI devices ourselves.  
+ */
+
+/**
+ * __restore_bars - Restore the Base Address Registers
+ * Loads the PCI configuration space base address registers,
+ * the expansion ROM base address, the latency timer, and etc.
+ * from the saved values in the device node.
+ */
+static inline void __restore_bars (struct pci_dn *pdn)
+{
+	int i;
+
+	if (NULL==pdn->phb) return;
+	for (i=4; i<10; i++) {
+		rtas_write_config(pdn, i*4, 4, pdn->config_space[i]);
+	}
+
+	/* 12 == Expansion ROM Address */
+	rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]);
+
+#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
+#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)])
+
+	rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1,
+	            SAVED_BYTE(PCI_CACHE_LINE_SIZE));
+
+	rtas_write_config (pdn, PCI_LATENCY_TIMER, 1,
+	            SAVED_BYTE(PCI_LATENCY_TIMER));
+
+	/* max latency, min grant, interrupt pin and line */
+	rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]);
+}
+
+/**
+ * eeh_restore_bars - restore the PCI config space info
+ *
+ * This routine performs a recursive walk to the children
+ * of this device as well.
+ */
+void eeh_restore_bars(struct pci_dn *pdn)
+{
+	struct device_node *dn;
+	if (!pdn) 
+		return;
+	
+	if (! pdn->eeh_is_bridge)
+		__restore_bars (pdn);
+
+	dn = pdn->node->child;
+	while (dn) {
+		eeh_restore_bars (PCI_DN(dn));
+		dn = dn->sibling;
+	}
+}
+
+/**
+ * eeh_save_bars - save device bars
+ *
+ * Save the values of the device bars. Unlike the restore
+ * routine, this routine is *not* recursive. This is because
+ * PCI devices are added individuallly; but, for the restore,
+ * an entire slot is reset at a time.
+ */
+static void eeh_save_bars(struct pci_dev * pdev, struct pci_dn *pdn)
+{
+	int i;
+
+	if (!pdev || !pdn )
+		return;
+	
+	for (i = 0; i < 16; i++)
+		pci_read_config_dword(pdev, i * 4, &pdn->config_space[i]);
+
+	if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+		pdn->eeh_is_bridge = 1;
+}
+
+void
+rtas_configure_bridge(struct pci_dn *pdn)
+{
+	int token = rtas_token ("ibm,configure-bridge");
+	int rc;
+
+	if (token == RTAS_UNKNOWN_SERVICE)
+		return;
+	rc = rtas_call(token,3,1, NULL,
+	               pdn->eeh_config_addr,
+	               BUID_HI(pdn->phb->buid),
+	               BUID_LO(pdn->phb->buid));
+	if (rc) {
+		printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n",
+		        rc, pdn->node->full_name);
+	}
+}
+
+/* ------------------------------------------------------------- */
+/* The code below deals with enabling EEH for devices during  the
+ * early boot sequence.  EEH must be enabled before any PCI probing
+ * can be done.
+ */
+
+#define EEH_ENABLE 1
+
 struct eeh_early_enable_info {
 	unsigned int buid_hi;
 	unsigned int buid_lo;
@@ -684,9 +924,11 @@
 	u32 *device_id = (u32 *)get_property(dn, "device-id", NULL);
 	u32 *regs;
 	int enable;
-	struct pci_dn *pdn = dn->data;
+	struct pci_dn *pdn = PCI_DN(dn);
 
 	pdn->eeh_mode = 0;
+	pdn->eeh_check_count = 0;
+	pdn->eeh_freeze_count = 0;
 
 	if (status && strcmp(status, "ok") != 0)
 		return NULL;	/* ignore devices with bad status */
@@ -723,8 +965,9 @@
 		/* First register entry is addr (00BBSS00)  */
 		/* Try to enable eeh */
 		ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
-				regs[0], info->buid_hi, info->buid_lo,
-				EEH_ENABLE);
+		                regs[0], info->buid_hi, info->buid_lo,
+		                EEH_ENABLE);
+
 		if (ret == 0) {
 			eeh_subsystem_enabled = 1;
 			pdn->eeh_mode |= EEH_MODE_SUPPORTED;
@@ -736,7 +979,7 @@
 
 			/* This device doesn't support EEH, but it may have an
 			 * EEH parent, in which case we mark it as supported. */
-			if (dn->parent && dn->parent->data
+			if (dn->parent && PCI_DN(dn->parent)
 			    && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
 				/* Parent supports EEH. */
 				pdn->eeh_mode |= EEH_MODE_SUPPORTED;
@@ -749,7 +992,7 @@
 		       dn->full_name);
 	}
 
-	return NULL; 
+	return NULL;
 }
 
 /*
@@ -770,6 +1013,9 @@
 	struct device_node *phb, *np;
 	struct eeh_early_enable_info info;
 
+	spin_lock_init(&confirm_error_lock);
+	spin_lock_init(&slot_errbuf_lock);
+
 	np = of_find_node_by_path("/rtas");
 	if (np == NULL)
 		return;
@@ -797,13 +1043,11 @@
 	for (phb = of_find_node_by_name(NULL, "pci"); phb;
 	     phb = of_find_node_by_name(phb, "pci")) {
 		unsigned long buid;
-		struct pci_dn *pci;
 
 		buid = get_phb_buid(phb);
-		if (buid == 0 || phb->data == NULL)
+		if (buid == 0 || PCI_DN(phb) == NULL)
 			continue;
 
-		pci = phb->data;
 		info.buid_lo = BUID_LO(buid);
 		info.buid_hi = BUID_HI(buid);
 		traverse_pci_devices(phb, early_enable_eeh, &info);
@@ -832,11 +1076,13 @@
 	struct pci_controller *phb;
 	struct eeh_early_enable_info info;
 
-	if (!dn || !dn->data)
+	if (!dn || !PCI_DN(dn))
 		return;
 	phb = PCI_DN(dn)->phb;
 	if (NULL == phb || 0 == phb->buid) {
-		printk(KERN_WARNING "EEH: Expected buid but found none\n");
+		printk(KERN_WARNING "EEH: Expected buid but found none for %s\n",
+		       dn->full_name);
+		dump_stack();
 		return;
 	}
 
@@ -844,7 +1090,7 @@
 	info.buid_lo = BUID_LO(phb->buid);
 	early_enable_eeh(dn, &info);
 }
-EXPORT_SYMBOL(eeh_add_device_early);
+EXPORT_SYMBOL_GPL(eeh_add_device_early);
 
 /**
  * eeh_add_device_late - perform EEH initialization for the indicated pci device
@@ -855,6 +1101,9 @@
  */
 void eeh_add_device_late(struct pci_dev *dev)
 {
+	struct device_node *dn;
+	struct pci_dn *pdn;
+
 	if (!dev || !eeh_subsystem_enabled)
 		return;
 
@@ -862,9 +1111,15 @@
 	printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev));
 #endif
 
+	pci_dev_get (dev);
+	dn = pci_device_to_OF_node(dev);
+	pdn = PCI_DN(dn);
+	pdn->pcidev = dev;
+
 	pci_addr_cache_insert_device (dev);
+	eeh_save_bars(dev, pdn);
 }
-EXPORT_SYMBOL(eeh_add_device_late);
+EXPORT_SYMBOL_GPL(eeh_add_device_late);
 
 /**
  * eeh_remove_device - undo EEH setup for the indicated pci device
@@ -875,6 +1130,7 @@
  */
 void eeh_remove_device(struct pci_dev *dev)
 {
+	struct device_node *dn;
 	if (!dev || !eeh_subsystem_enabled)
 		return;
 
@@ -883,20 +1139,29 @@
 	printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev));
 #endif
 	pci_addr_cache_remove_device(dev);
+
+	dn = pci_device_to_OF_node(dev);
+	PCI_DN(dn)->pcidev = NULL;
+	pci_dev_put (dev);
 }
-EXPORT_SYMBOL(eeh_remove_device);
+EXPORT_SYMBOL_GPL(eeh_remove_device);
 
 static int proc_eeh_show(struct seq_file *m, void *v)
 {
 	unsigned int cpu;
 	unsigned long ffs = 0, positives = 0, failures = 0;
 	unsigned long resets = 0;
+	unsigned long no_dev = 0, no_dn = 0, no_cfg = 0, no_check = 0;
 
 	for_each_cpu(cpu) {
 		ffs += per_cpu(total_mmio_ffs, cpu);
 		positives += per_cpu(false_positives, cpu);
 		failures += per_cpu(ignored_failures, cpu);
 		resets += per_cpu(slot_resets, cpu);
+		no_dev += per_cpu(no_device, cpu);
+		no_dn += per_cpu(no_dn, cpu);
+		no_cfg += per_cpu(no_cfg_addr, cpu);
+		no_check += per_cpu(ignored_check, cpu);
 	}
 
 	if (0 == eeh_subsystem_enabled) {
@@ -904,13 +1169,17 @@
 		seq_printf(m, "eeh_total_mmio_ffs=%ld\n", ffs);
 	} else {
 		seq_printf(m, "EEH Subsystem is enabled\n");
-		seq_printf(m, "eeh_total_mmio_ffs=%ld\n"
-			   "eeh_false_positives=%ld\n"
-			   "eeh_ignored_failures=%ld\n"
-			   "eeh_slot_resets=%ld\n"
-				"eeh_fail_count=%d\n",
-			   ffs, positives, failures, resets,
-				eeh_fail_count.counter);
+		seq_printf(m,
+				"no device=%ld\n"
+				"no device node=%ld\n"
+				"no config address=%ld\n"
+				"check not wanted=%ld\n"
+				"eeh_total_mmio_ffs=%ld\n"
+				"eeh_false_positives=%ld\n"
+				"eeh_ignored_failures=%ld\n"
+				"eeh_slot_resets=%ld\n",
+				no_dev, no_dn, no_cfg, no_check,
+				ffs, positives, failures, resets);
 	}
 
 	return 0;
@@ -932,7 +1201,7 @@
 {
 	struct proc_dir_entry *e;
 
-	if (systemcfg->platform & PLATFORM_PSERIES) {
+	if (platform_is_pseries()) {
 		e = create_proc_entry("ppc64/eeh", 0, NULL);
 		if (e)
 			e->proc_fops = &proc_eeh_operations;
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c
new file mode 100644
index 0000000..9249733
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/eeh_event.c
@@ -0,0 +1,155 @@
+/*
+ * eeh_event.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ * Copyright (c) 2005 Linas Vepstas <linas@linas.org>
+ */
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <asm/eeh_event.h>
+
+/** Overview:
+ *  EEH error states may be detected within exception handlers;
+ *  however, the recovery processing needs to occur asynchronously
+ *  in a normal kernel context and not an interrupt context.
+ *  This pair of routines creates an event and queues it onto a
+ *  work-queue, where a worker thread can drive recovery.
+ */
+
+/* EEH event workqueue setup. */
+static spinlock_t eeh_eventlist_lock = SPIN_LOCK_UNLOCKED;
+LIST_HEAD(eeh_eventlist);
+static void eeh_thread_launcher(void *);
+DECLARE_WORK(eeh_event_wq, eeh_thread_launcher, NULL);
+
+/**
+ * eeh_panic - call panic() for an eeh event that cannot be handled.
+ * The philosophy of this routine is that it is better to panic and
+ * halt the OS than it is to risk possible data corruption by
+ * oblivious device drivers that don't know better.
+ *
+ * @dev pci device that had an eeh event
+ * @reset_state current reset state of the device slot
+ */
+static void eeh_panic(struct pci_dev *dev, int reset_state)
+{
+	/*
+	 * Since the panic_on_oops sysctl is used to halt the system
+	 * in light of potential corruption, we can use it here.
+	 */
+	if (panic_on_oops) {
+		panic("EEH: MMIO failure (%d) on device:%s\n", reset_state,
+		      pci_name(dev));
+	}
+	else {
+		printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s\n",
+		       reset_state, pci_name(dev));
+	}
+}
+
+/**
+ * eeh_event_handler - dispatch EEH events.  The detection of a frozen
+ * slot can occur inside an interrupt, where it can be hard to do
+ * anything about it.  The goal of this routine is to pull these
+ * detection events out of the context of the interrupt handler, and
+ * re-dispatch them for processing at a later time in a normal context.
+ *
+ * @dummy - unused
+ */
+static int eeh_event_handler(void * dummy)
+{
+	unsigned long flags;
+	struct eeh_event	*event;
+
+	daemonize ("eehd");
+
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irqsave(&eeh_eventlist_lock, flags);
+		event = NULL;
+		if (!list_empty(&eeh_eventlist)) {
+			event = list_entry(eeh_eventlist.next, struct eeh_event, list);
+			list_del(&event->list);
+		}
+		spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
+		if (event == NULL)
+			break;
+
+		printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n",
+		       pci_name(event->dev));
+
+		eeh_panic (event->dev, event->state);
+
+		kfree(event);
+	}
+
+	return 0;
+}
+
+/**
+ * eeh_thread_launcher
+ *
+ * @dummy - unused
+ */
+static void eeh_thread_launcher(void *dummy)
+{
+	if (kernel_thread(eeh_event_handler, NULL, CLONE_KERNEL) < 0)
+		printk(KERN_ERR "Failed to start EEH daemon\n");
+}
+
+/**
+ * eeh_send_failure_event - generate a PCI error event
+ * @dev pci device
+ *
+ * This routine can be called within an interrupt context;
+ * the actual event will be delivered in a normal context
+ * (from a workqueue).
+ */
+int eeh_send_failure_event (struct device_node *dn,
+                            struct pci_dev *dev,
+                            int state,
+                            int time_unavail)
+{
+	unsigned long flags;
+	struct eeh_event *event;
+
+	event = kmalloc(sizeof(*event), GFP_ATOMIC);
+	if (event == NULL) {
+		printk (KERN_ERR "EEH: out of memory, event not handled\n");
+		return 1;
+ 	}
+
+	if (dev)
+		pci_dev_get(dev);
+
+	event->dn = dn;
+	event->dev = dev;
+	event->state = state;
+	event->time_unavail = time_unavail;
+
+	/* We may or may not be called in an interrupt context */
+	spin_lock_irqsave(&eeh_eventlist_lock, flags);
+	list_add(&event->list, &eeh_eventlist);
+	spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
+
+	schedule_work(&eeh_event_wq);
+
+	return 0;
+}
+
+/********************** END OF FILE ******************************/
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index fcc50bf..97ba521 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -42,7 +42,6 @@
 #include <asm/machdep.h>
 #include <asm/abs_addr.h>
 #include <asm/pSeries_reconfig.h>
-#include <asm/systemcfg.h>
 #include <asm/firmware.h>
 #include <asm/tce.h>
 #include <asm/ppc-pci.h>
@@ -582,7 +581,7 @@
 		return;
 	}
 
-	if (systemcfg->platform & PLATFORM_LPAR) {
+	if (platform_is_lpar()) {
 		if (firmware_has_feature(FW_FEATURE_MULTITCE)) {
 			ppc_md.tce_build = tce_buildmulti_pSeriesLP;
 			ppc_md.tce_free	 = tce_freemulti_pSeriesLP;
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index c198656..999a962 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -107,7 +107,6 @@
 
 void __init pSeries_final_fixup(void)
 {
-	phbs_remap_io();
 	pSeries_request_regions();
 
 	pci_addr_cache_build();
@@ -123,7 +122,7 @@
 	int i;
 	unsigned int reg;
 
-	if (!(systemcfg->platform & PLATFORM_PSERIES))
+	if (!platform_is_pseries())
 		return;
 
 	printk("Using INTC for W82c105 IDE controller.\n");
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index d7d4003..d886416 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -408,7 +408,7 @@
 {
 	struct proc_dir_entry *ent;
 
-	if (!(systemcfg->platform & PLATFORM_PSERIES))
+	if (!platform_is_pseries())
 		return 0;
 
 	ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index e26b042..a6f628d 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -27,7 +27,6 @@
 #include <asm/prom.h>
 #include <asm/nvram.h>
 #include <asm/atomic.h>
-#include <asm/systemcfg.h>
 
 #if 0
 #define DEBUG(A...)	printk(KERN_ERR A)
@@ -482,10 +481,12 @@
 {
 	struct proc_dir_entry *entry;
 
-	/* No RTAS, only warn if we are on a pSeries box  */
+	if (!platform_is_pseries())
+		return 0;
+
+	/* No RTAS */
 	if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) {
-		if (systemcfg->platform & PLATFORM_PSERIES)
-			printk(KERN_INFO "rtasd: no event-scan on system\n");
+		printk(KERN_INFO "rtasd: no event-scan on system\n");
 		return 1;
 	}
 
diff --git a/arch/ppc64/kernel/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c
similarity index 100%
rename from arch/ppc64/kernel/scanlog.c
rename to arch/powerpc/platforms/pseries/scanlog.c
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index e78c393..3199082 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -249,7 +249,7 @@
 		ppc_md.idle_loop = default_idle;
 	}
 
-	if (systemcfg->platform & PLATFORM_LPAR)
+	if (platform_is_lpar())
 		ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
 	else
 		ppc_md.enable_pmcs = power4_enable_pmcs;
@@ -306,9 +306,7 @@
 	}
 
 	of_node_put(dn);
- no_rtas:
-	printk(KERN_INFO "firmware_features = 0x%lx\n", 
-	       ppc64_firmware_features);
+no_rtas:
 
 	DBG(" <- fw_feature_init()\n");
 }
@@ -378,7 +376,7 @@
 
 	fw_feature_init();
 	
-	if (systemcfg->platform & PLATFORM_LPAR)
+	if (platform_is_lpar())
 		hpte_init_lpar();
 	else {
 		hpte_init_native();
@@ -388,7 +386,7 @@
 
 	generic_find_legacy_serial_ports(&physport, &default_speed);
 
-	if (systemcfg->platform & PLATFORM_LPAR)
+	if (platform_is_lpar())
 		find_udbg_vterm();
 	else if (physport) {
 		/* Map the uart for udbg. */
@@ -469,6 +467,7 @@
 		 * more.
 		 */
 		clear_thread_flag(TIF_POLLING_NRFLAG);
+		smp_mb__after_clear_bit();
 
 		/*
 		 * SMT dynamic mode. Cede will result in this thread going
@@ -481,6 +480,7 @@
 			cede_processor();
 		else
 			local_irq_enable();
+		set_thread_flag(TIF_POLLING_NRFLAG);
 	} else {
 		/*
 		 * Give the HV an opportunity at the processor, since we are
@@ -492,11 +492,11 @@
 
 static void pseries_dedicated_idle(void)
 { 
-	long oldval;
 	struct paca_struct *lpaca = get_paca();
 	unsigned int cpu = smp_processor_id();
 	unsigned long start_snooze;
 	unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
+	set_thread_flag(TIF_POLLING_NRFLAG);
 
 	while (1) {
 		/*
@@ -505,10 +505,7 @@
 		 */
 		lpaca->lppaca.idle = 1;
 
-		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-		if (!oldval) {
-			set_thread_flag(TIF_POLLING_NRFLAG);
-
+		if (!need_resched()) {
 			start_snooze = __get_tb() +
 				*smt_snooze_delay * tb_ticks_per_usec;
 
@@ -531,15 +528,14 @@
 			}
 
 			HMT_medium();
-			clear_thread_flag(TIF_POLLING_NRFLAG);
-		} else {
-			set_need_resched();
 		}
 
 		lpaca->lppaca.idle = 0;
 		ppc64_runlatch_on();
 
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 
 		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
 			cpu_die();
@@ -583,7 +579,9 @@
 		lpaca->lppaca.idle = 0;
 		ppc64_runlatch_on();
 
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 
 		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
 			cpu_die();
@@ -592,7 +590,7 @@
 
 static int pSeries_pci_probe_mode(struct pci_bus *bus)
 {
-	if (systemcfg->platform & PLATFORM_LPAR)
+	if (platform_is_lpar())
 		return PCI_PROBE_DEVTREE;
 	return PCI_PROBE_NORMAL;
 }
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 7a243e8..5800cde 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -46,6 +46,7 @@
 #include <asm/rtas.h>
 #include <asm/pSeries_reconfig.h>
 #include <asm/mpic.h>
+#include <asm/vdso_datapage.h>
 
 #include "plpar_wrappers.h"
 
@@ -96,7 +97,7 @@
 	int cpu = smp_processor_id();
 
 	cpu_clear(cpu, cpu_online_map);
-	systemcfg->processorCount--;
+	vdso_data->processorCount--;
 
 	/*fix boot_cpuid here*/
 	if (cpu == boot_cpuid)
@@ -441,7 +442,7 @@
 	smp_ops->cpu_die = pSeries_cpu_die;
 
 	/* Processors can be added/removed only on LPAR */
-	if (systemcfg->platform == PLATFORM_PSERIES_LPAR)
+	if (platform_is_lpar())
 		pSeries_reconfig_notifier_register(&pSeries_smp_nb);
 #endif
 
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index c72c86f..72ac180 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -545,7 +545,9 @@
 		of_node_put(np);
 	}
 
-	if (systemcfg->platform == PLATFORM_PSERIES) {
+	if (platform_is_lpar())
+		ops = &pSeriesLP_ops;
+	else {
 #ifdef CONFIG_SMP
 		for_each_cpu(i) {
 			int hard_id;
@@ -561,12 +563,11 @@
 #else
 		xics_per_cpu[0] = ioremap(intr_base, intr_size);
 #endif /* CONFIG_SMP */
-	} else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
-		ops = &pSeriesLP_ops;
 	}
 
 	xics_8259_pic.enable = i8259_pic.enable;
 	xics_8259_pic.disable = i8259_pic.disable;
+	xics_8259_pic.end = i8259_pic.end;
 	for (i = 0; i < 16; ++i)
 		get_irq_desc(i)->handler = &xics_8259_pic;
 	for (; i < NR_IRQS; ++i)
diff --git a/arch/powerpc/sysdev/u3_iommu.c b/arch/powerpc/sysdev/u3_iommu.c
index 543d659..f32baf7 100644
--- a/arch/powerpc/sysdev/u3_iommu.c
+++ b/arch/powerpc/sysdev/u3_iommu.c
@@ -226,7 +226,7 @@
 	iommu_table_u3.it_busno = 0;
 	iommu_table_u3.it_offset = 0;
 	/* it_size is in number of entries */
-	iommu_table_u3.it_size = dart_tablesize / sizeof(u32);
+	iommu_table_u3.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR;
 
 	/* Initialize the common IOMMU code */
 	iommu_table_u3.it_base = (unsigned long)dart_vbase;
diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile
index 79a784f..b20312e 100644
--- a/arch/powerpc/xmon/Makefile
+++ b/arch/powerpc/xmon/Makefile
@@ -8,4 +8,4 @@
 obj-$(CONFIG_6xx)	+= start_32.o
 obj-$(CONFIG_4xx)	+= start_32.o
 obj-$(CONFIG_PPC64)	+= start_64.o
-obj-y			+= xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o
+obj-y			+= xmon.o ppc-dis.o ppc-opc.o setjmp.o nonstdio.o
diff --git a/arch/powerpc/xmon/nonstdio.c b/arch/powerpc/xmon/nonstdio.c
new file mode 100644
index 0000000..7876583
--- /dev/null
+++ b/arch/powerpc/xmon/nonstdio.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ *      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/string.h>
+#include <asm/time.h>
+#include "nonstdio.h"
+
+int xmon_putchar(int c)
+{
+	char ch = c;
+
+	if (c == '\n')
+		xmon_putchar('\r');
+	return xmon_write(&ch, 1) == 1? c: -1;
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int xmon_expect(const char *str, unsigned long timeout)
+{
+	int c;
+	unsigned long t0;
+
+	/* assume 25MHz default timebase if tb_ticks_per_sec not set yet */
+	timeout *= tb_ticks_per_sec? tb_ticks_per_sec: 25000000;
+	t0 = get_tbl();
+	do {
+		lineptr = line;
+		for (;;) {
+			c = xmon_read_poll();
+			if (c == -1) {
+				if (get_tbl() - t0 > timeout)
+					return 0;
+				continue;
+			}
+			if (c == '\n')
+				break;
+			if (c != '\r' && lineptr < &line[sizeof(line) - 1])
+				*lineptr++ = c;
+		}
+		*lineptr = 0;
+	} while (strstr(line, str) == NULL);
+	return 1;
+}
+
+int xmon_getchar(void)
+{
+	int c;
+
+	if (lineleft == 0) {
+		lineptr = line;
+		for (;;) {
+			c = xmon_readchar();
+			if (c == -1 || c == 4)
+				break;
+			if (c == '\r' || c == '\n') {
+				*lineptr++ = '\n';
+				xmon_putchar('\n');
+				break;
+			}
+			switch (c) {
+			case 0177:
+			case '\b':
+				if (lineptr > line) {
+					xmon_putchar('\b');
+					xmon_putchar(' ');
+					xmon_putchar('\b');
+					--lineptr;
+				}
+				break;
+			case 'U' & 0x1F:
+				while (lineptr > line) {
+					xmon_putchar('\b');
+					xmon_putchar(' ');
+					xmon_putchar('\b');
+					--lineptr;
+				}
+				break;
+			default:
+				if (lineptr >= &line[sizeof(line) - 1])
+					xmon_putchar('\a');
+				else {
+					xmon_putchar(c);
+					*lineptr++ = c;
+				}
+			}
+		}
+		lineleft = lineptr - line;
+		lineptr = line;
+	}
+	if (lineleft == 0)
+		return -1;
+	--lineleft;
+	return *lineptr++;
+}
+
+char *xmon_gets(char *str, int nb)
+{
+	char *p;
+	int c;
+
+	for (p = str; p < str + nb - 1; ) {
+		c = xmon_getchar();
+		if (c == -1) {
+			if (p == str)
+				return NULL;
+			break;
+		}
+		*p++ = c;
+		if (c == '\n')
+			break;
+	}
+	*p = 0;
+	return str;
+}
+
+void xmon_printf(const char *format, ...)
+{
+	va_list args;
+	int n;
+	static char xmon_outbuf[1024];
+
+	va_start(args, format);
+	n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args);
+	va_end(args);
+	xmon_write(xmon_outbuf, n);
+}
diff --git a/arch/powerpc/xmon/nonstdio.h b/arch/powerpc/xmon/nonstdio.h
index 84211a2..47cebbd 100644
--- a/arch/powerpc/xmon/nonstdio.h
+++ b/arch/powerpc/xmon/nonstdio.h
@@ -1,22 +1,14 @@
-typedef int	FILE;
-extern FILE *xmon_stdin, *xmon_stdout;
 #define EOF	(-1)
-#define stdin	xmon_stdin
-#define stdout	xmon_stdout
-#define printf	xmon_printf
-#define fprintf	xmon_fprintf
-#define fputs	xmon_fputs
-#define fgets	xmon_fgets
-#define putchar	xmon_putchar
-#define getchar	xmon_getchar
-#define putc	xmon_putc
-#define getc	xmon_getc
-#define fopen(n, m)	NULL
-#define fflush(f)	do {} while (0)
-#define fclose(f)	do {} while (0)
-extern char *fgets(char *, int, void *);
-extern void xmon_printf(const char *, ...);
-extern void xmon_fprintf(void *, const char *, ...);
-extern void xmon_sprintf(char *, const char *, ...);
 
-#define perror(s)	printf("%s: no files!\n", (s))
+#define printf	xmon_printf
+#define putchar	xmon_putchar
+
+extern int xmon_putchar(int c);
+extern int xmon_getchar(void);
+extern char *xmon_gets(char *, int);
+extern void xmon_printf(const char *, ...);
+extern void xmon_map_scc(void);
+extern int xmon_expect(const char *str, unsigned long timeout);
+extern int xmon_write(void *ptr, int nb);
+extern int xmon_readchar(void);
+extern int xmon_read_poll(void);
diff --git a/arch/powerpc/xmon/setjmp.S b/arch/powerpc/xmon/setjmp.S
index f8e40df..96a91f1 100644
--- a/arch/powerpc/xmon/setjmp.S
+++ b/arch/powerpc/xmon/setjmp.S
@@ -14,61 +14,61 @@
 
 _GLOBAL(xmon_setjmp)
 	mflr	r0
-	STL	r0,0(r3)
-	STL	r1,SZL(r3)
-	STL	r2,2*SZL(r3)
+	PPC_STL	r0,0(r3)
+	PPC_STL	r1,SZL(r3)
+	PPC_STL	r2,2*SZL(r3)
 	mfcr	r0
-	STL	r0,3*SZL(r3)
-	STL	r13,4*SZL(r3)
-	STL	r14,5*SZL(r3)
-	STL	r15,6*SZL(r3)
-	STL	r16,7*SZL(r3)
-	STL	r17,8*SZL(r3)
-	STL	r18,9*SZL(r3)
-	STL	r19,10*SZL(r3)
-	STL	r20,11*SZL(r3)
-	STL	r21,12*SZL(r3)
-	STL	r22,13*SZL(r3)
-	STL	r23,14*SZL(r3)
-	STL	r24,15*SZL(r3)
-	STL	r25,16*SZL(r3)
-	STL	r26,17*SZL(r3)
-	STL	r27,18*SZL(r3)
-	STL	r28,19*SZL(r3)
-	STL	r29,20*SZL(r3)
-	STL	r30,21*SZL(r3)
-	STL	r31,22*SZL(r3)
+	PPC_STL	r0,3*SZL(r3)
+	PPC_STL	r13,4*SZL(r3)
+	PPC_STL	r14,5*SZL(r3)
+	PPC_STL	r15,6*SZL(r3)
+	PPC_STL	r16,7*SZL(r3)
+	PPC_STL	r17,8*SZL(r3)
+	PPC_STL	r18,9*SZL(r3)
+	PPC_STL	r19,10*SZL(r3)
+	PPC_STL	r20,11*SZL(r3)
+	PPC_STL	r21,12*SZL(r3)
+	PPC_STL	r22,13*SZL(r3)
+	PPC_STL	r23,14*SZL(r3)
+	PPC_STL	r24,15*SZL(r3)
+	PPC_STL	r25,16*SZL(r3)
+	PPC_STL	r26,17*SZL(r3)
+	PPC_STL	r27,18*SZL(r3)
+	PPC_STL	r28,19*SZL(r3)
+	PPC_STL	r29,20*SZL(r3)
+	PPC_STL	r30,21*SZL(r3)
+	PPC_STL	r31,22*SZL(r3)
 	li	r3,0
 	blr
 
 _GLOBAL(xmon_longjmp)
-	CMPI	r4,0
+	PPC_LCMPI r4,0
 	bne	1f
 	li	r4,1
-1:	LDL	r13,4*SZL(r3)
-	LDL	r14,5*SZL(r3)
-	LDL	r15,6*SZL(r3)
-	LDL	r16,7*SZL(r3)
-	LDL	r17,8*SZL(r3)
-	LDL	r18,9*SZL(r3)
-	LDL	r19,10*SZL(r3)
-	LDL	r20,11*SZL(r3)
-	LDL	r21,12*SZL(r3)
-	LDL	r22,13*SZL(r3)
-	LDL	r23,14*SZL(r3)
-	LDL	r24,15*SZL(r3)
-	LDL	r25,16*SZL(r3)
-	LDL	r26,17*SZL(r3)
-	LDL	r27,18*SZL(r3)
-	LDL	r28,19*SZL(r3)
-	LDL	r29,20*SZL(r3)
-	LDL	r30,21*SZL(r3)
-	LDL	r31,22*SZL(r3)
-	LDL	r0,3*SZL(r3)
+1:	PPC_LL	r13,4*SZL(r3)
+	PPC_LL	r14,5*SZL(r3)
+	PPC_LL	r15,6*SZL(r3)
+	PPC_LL	r16,7*SZL(r3)
+	PPC_LL	r17,8*SZL(r3)
+	PPC_LL	r18,9*SZL(r3)
+	PPC_LL	r19,10*SZL(r3)
+	PPC_LL	r20,11*SZL(r3)
+	PPC_LL	r21,12*SZL(r3)
+	PPC_LL	r22,13*SZL(r3)
+	PPC_LL	r23,14*SZL(r3)
+	PPC_LL	r24,15*SZL(r3)
+	PPC_LL	r25,16*SZL(r3)
+	PPC_LL	r26,17*SZL(r3)
+	PPC_LL	r27,18*SZL(r3)
+	PPC_LL	r28,19*SZL(r3)
+	PPC_LL	r29,20*SZL(r3)
+	PPC_LL	r30,21*SZL(r3)
+	PPC_LL	r31,22*SZL(r3)
+	PPC_LL	r0,3*SZL(r3)
 	mtcrf	0x38,r0
-	LDL	r0,0(r3)
-	LDL	r1,SZL(r3)
-	LDL	r2,2*SZL(r3)
+	PPC_LL	r0,0(r3)
+	PPC_LL	r1,SZL(r3)
+	PPC_LL	r2,2*SZL(r3)
 	mtlr	r0
 	mr	r3,r4
 	blr
@@ -84,52 +84,52 @@
  * different ABIs, though).
  */
 _GLOBAL(xmon_save_regs)
-	STL	r0,0*SZL(r3)
-	STL	r2,2*SZL(r3)
-	STL	r3,3*SZL(r3)
-	STL	r4,4*SZL(r3)
-	STL	r5,5*SZL(r3)
-	STL	r6,6*SZL(r3)
-	STL	r7,7*SZL(r3)
-	STL	r8,8*SZL(r3)
-	STL	r9,9*SZL(r3)
-	STL	r10,10*SZL(r3)
-	STL	r11,11*SZL(r3)
-	STL	r12,12*SZL(r3)
-	STL	r13,13*SZL(r3)
-	STL	r14,14*SZL(r3)
-	STL	r15,15*SZL(r3)
-	STL	r16,16*SZL(r3)
-	STL	r17,17*SZL(r3)
-	STL	r18,18*SZL(r3)
-	STL	r19,19*SZL(r3)
-	STL	r20,20*SZL(r3)
-	STL	r21,21*SZL(r3)
-	STL	r22,22*SZL(r3)
-	STL	r23,23*SZL(r3)
-	STL	r24,24*SZL(r3)
-	STL	r25,25*SZL(r3)
-	STL	r26,26*SZL(r3)
-	STL	r27,27*SZL(r3)
-	STL	r28,28*SZL(r3)
-	STL	r29,29*SZL(r3)
-	STL	r30,30*SZL(r3)
-	STL	r31,31*SZL(r3)
+	PPC_STL	r0,0*SZL(r3)
+	PPC_STL	r2,2*SZL(r3)
+	PPC_STL	r3,3*SZL(r3)
+	PPC_STL	r4,4*SZL(r3)
+	PPC_STL	r5,5*SZL(r3)
+	PPC_STL	r6,6*SZL(r3)
+	PPC_STL	r7,7*SZL(r3)
+	PPC_STL	r8,8*SZL(r3)
+	PPC_STL	r9,9*SZL(r3)
+	PPC_STL	r10,10*SZL(r3)
+	PPC_STL	r11,11*SZL(r3)
+	PPC_STL	r12,12*SZL(r3)
+	PPC_STL	r13,13*SZL(r3)
+	PPC_STL	r14,14*SZL(r3)
+	PPC_STL	r15,15*SZL(r3)
+	PPC_STL	r16,16*SZL(r3)
+	PPC_STL	r17,17*SZL(r3)
+	PPC_STL	r18,18*SZL(r3)
+	PPC_STL	r19,19*SZL(r3)
+	PPC_STL	r20,20*SZL(r3)
+	PPC_STL	r21,21*SZL(r3)
+	PPC_STL	r22,22*SZL(r3)
+	PPC_STL	r23,23*SZL(r3)
+	PPC_STL	r24,24*SZL(r3)
+	PPC_STL	r25,25*SZL(r3)
+	PPC_STL	r26,26*SZL(r3)
+	PPC_STL	r27,27*SZL(r3)
+	PPC_STL	r28,28*SZL(r3)
+	PPC_STL	r29,29*SZL(r3)
+	PPC_STL	r30,30*SZL(r3)
+	PPC_STL	r31,31*SZL(r3)
 	/* go up one stack frame for SP */
-	LDL	r4,0(r1)
-	STL	r4,1*SZL(r3)
+	PPC_LL	r4,0(r1)
+	PPC_STL	r4,1*SZL(r3)
 	/* get caller's LR */
-	LDL	r0,LRSAVE(r4)
-	STL	r0,_NIP-STACK_FRAME_OVERHEAD(r3)
-	STL	r0,_LINK-STACK_FRAME_OVERHEAD(r3)
+	PPC_LL	r0,LRSAVE(r4)
+	PPC_STL	r0,_NIP-STACK_FRAME_OVERHEAD(r3)
+	PPC_STL	r0,_LINK-STACK_FRAME_OVERHEAD(r3)
 	mfmsr	r0
-	STL	r0,_MSR-STACK_FRAME_OVERHEAD(r3)
+	PPC_STL	r0,_MSR-STACK_FRAME_OVERHEAD(r3)
 	mfctr	r0
-	STL	r0,_CTR-STACK_FRAME_OVERHEAD(r3)
+	PPC_STL	r0,_CTR-STACK_FRAME_OVERHEAD(r3)
 	mfxer	r0
-	STL	r0,_XER-STACK_FRAME_OVERHEAD(r3)
+	PPC_STL	r0,_XER-STACK_FRAME_OVERHEAD(r3)
 	mfcr	r0
-	STL	r0,_CCR-STACK_FRAME_OVERHEAD(r3)
+	PPC_STL	r0,_CCR-STACK_FRAME_OVERHEAD(r3)
 	li	r0,0
-	STL	r0,_TRAP-STACK_FRAME_OVERHEAD(r3)
+	PPC_STL	r0,_TRAP-STACK_FRAME_OVERHEAD(r3)
 	blr
diff --git a/arch/powerpc/xmon/start_32.c b/arch/powerpc/xmon/start_32.c
index 69b658c..c2464df 100644
--- a/arch/powerpc/xmon/start_32.c
+++ b/arch/powerpc/xmon/start_32.c
@@ -11,7 +11,6 @@
 #include <linux/cuda.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/sysrq.h>
 #include <linux/bitops.h>
 #include <asm/xmon.h>
 #include <asm/prom.h>
@@ -22,10 +21,11 @@
 #include <asm/processor.h>
 #include <asm/delay.h>
 #include <asm/btext.h>
+#include <asm/time.h>
+#include "nonstdio.h"
 
 static volatile unsigned char __iomem *sccc, *sccd;
 unsigned int TXRDY, RXRDY, DLAB;
-static int xmon_expect(const char *str, unsigned int timeout);
 
 static int use_serial;
 static int use_screen;
@@ -33,16 +33,6 @@
 static int xmon_use_sccb;
 static struct device_node *channel_node;
 
-#define TB_SPEED	25000000
-
-static inline unsigned int readtb(void)
-{
-	unsigned int ret;
-
-	asm volatile("mftb %0" : "=r" (ret) :);
-	return ret;
-}
-
 void buf_access(void)
 {
 	if (DLAB)
@@ -91,23 +81,7 @@
 }
 #endif /* CONFIG_PPC_CHRP */
 
-#ifdef CONFIG_MAGIC_SYSRQ
-static void sysrq_handle_xmon(int key, struct pt_regs *regs,
-			      struct tty_struct *tty)
-{
-	xmon(regs);
-}
-
-static struct sysrq_key_op sysrq_xmon_op =
-{
-	.handler =	sysrq_handle_xmon,
-	.help_msg =	"Xmon",
-	.action_msg =	"Entering xmon",
-};
-#endif
-
-void
-xmon_map_scc(void)
+void xmon_map_scc(void)
 {
 #ifdef CONFIG_PPC_MULTIPLATFORM
 	volatile unsigned char __iomem *base;
@@ -217,8 +191,6 @@
 	RXRDY = 1;
 	DLAB = 0x80;
 #endif /* platform */
-
-	register_sysrq_key('x', &sysrq_xmon_op);
 }
 
 static int scc_initialized = 0;
@@ -238,8 +210,7 @@
 #endif /* CONFIG_ADB_CUDA */
 }
 
-int
-xmon_write(void *handle, void *ptr, int nb)
+int xmon_write(void *ptr, int nb)
 {
 	char *p = ptr;
 	int i, c, ct;
@@ -311,8 +282,7 @@
 	"\0.\0*\0+\0\0\0\0\0/\r\0-\0"			/* 0x40 - 0x4f */
 	"\0\0000123456789\0\0\0";			/* 0x50 - 0x5f */
 
-static int
-xmon_get_adb_key(void)
+static int xmon_get_adb_key(void)
 {
 	int k, t, on;
 
@@ -350,32 +320,21 @@
 }
 #endif /* CONFIG_BOOTX_TEXT */
 
-int
-xmon_read(void *handle, void *ptr, int nb)
+int xmon_readchar(void)
 {
-    char *p = ptr;
-    int i;
-
 #ifdef CONFIG_BOOTX_TEXT
-    if (use_screen) {
-	for (i = 0; i < nb; ++i)
-	    *p++ = xmon_get_adb_key();
-	return i;
-    }
+	if (use_screen)
+		return xmon_get_adb_key();
 #endif
-    if (!scc_initialized)
-	xmon_init_scc();
-    for (i = 0; i < nb; ++i) {
+	if (!scc_initialized)
+		xmon_init_scc();
 	while ((*sccc & RXRDY) == 0)
-	    do_poll_adb();
+		do_poll_adb();
 	buf_access();
-	*p++ = *sccd;
-    }
-    return i;
+	return *sccd;
 }
 
-int
-xmon_read_poll(void)
+int xmon_read_poll(void)
 {
 	if ((*sccc & RXRDY) == 0) {
 		do_poll_adb();
@@ -395,8 +354,7 @@
     3,  0xc1,		/* rx enable, 8 bits */
 };
 
-void
-xmon_init_scc(void)
+void xmon_init_scc(void)
 {
 	if ( _machine == _MACH_chrp )
 	{
@@ -410,6 +368,7 @@
 	else if ( _machine == _MACH_Pmac )
 	{
 		int i, x;
+		unsigned long timeout;
 
 		if (channel_node != 0)
 			pmac_call_feature(
@@ -424,8 +383,12 @@
 				PMAC_FTR_MODEM_ENABLE,
 				channel_node, 0, 1);
 			printk(KERN_INFO "Modem powered up by debugger !\n");
-			t0 = readtb();
-			while (readtb() - t0 < 3*TB_SPEED)
+			t0 = get_tbl();
+			timeout = 3 * tb_ticks_per_sec;
+			if (timeout == 0)
+				/* assume 25MHz if tb_ticks_per_sec not set */
+				timeout = 75000000;
+			while (get_tbl() - t0 < timeout)
 				eieio();
 		}
 		/* use the B channel if requested */
@@ -447,164 +410,19 @@
 	scc_initialized = 1;
 	if (via_modem) {
 		for (;;) {
-			xmon_write(NULL, "ATE1V1\r", 7);
+			xmon_write("ATE1V1\r", 7);
 			if (xmon_expect("OK", 5)) {
-				xmon_write(NULL, "ATA\r", 4);
+				xmon_write("ATA\r", 4);
 				if (xmon_expect("CONNECT", 40))
 					break;
 			}
-			xmon_write(NULL, "+++", 3);
+			xmon_write("+++", 3);
 			xmon_expect("OK", 3);
 		}
 	}
 }
 
-void *xmon_stdin;
-void *xmon_stdout;
-void *xmon_stderr;
-
-int xmon_putc(int c, void *f)
-{
-    char ch = c;
-
-    if (c == '\n')
-	xmon_putc('\r', f);
-    return xmon_write(f, &ch, 1) == 1? c: -1;
-}
-
-int xmon_putchar(int c)
-{
-	return xmon_putc(c, xmon_stdout);
-}
-
-int xmon_fputs(char *str, void *f)
-{
-	int n = strlen(str);
-
-	return xmon_write(f, str, n) == n? 0: -1;
-}
-
-int
-xmon_readchar(void)
-{
-	char ch;
-
-	for (;;) {
-		switch (xmon_read(xmon_stdin, &ch, 1)) {
-		case 1:
-			return ch;
-		case -1:
-			xmon_printf("read(stdin) returned -1\r\n", 0, 0);
-			return -1;
-		}
-	}
-}
-
-static char line[256];
-static char *lineptr;
-static int lineleft;
-
-int xmon_expect(const char *str, unsigned int timeout)
-{
-	int c;
-	unsigned int t0;
-
-	timeout *= TB_SPEED;
-	t0 = readtb();
-	do {
-		lineptr = line;
-		for (;;) {
-			c = xmon_read_poll();
-			if (c == -1) {
-				if (readtb() - t0 > timeout)
-					return 0;
-				continue;
-			}
-			if (c == '\n')
-				break;
-			if (c != '\r' && lineptr < &line[sizeof(line) - 1])
-				*lineptr++ = c;
-		}
-		*lineptr = 0;
-	} while (strstr(line, str) == NULL);
-	return 1;
-}
-
-int
-xmon_getchar(void)
-{
-    int c;
-
-    if (lineleft == 0) {
-	lineptr = line;
-	for (;;) {
-	    c = xmon_readchar();
-	    if (c == -1 || c == 4)
-		break;
-	    if (c == '\r' || c == '\n') {
-		*lineptr++ = '\n';
-		xmon_putchar('\n');
-		break;
-	    }
-	    switch (c) {
-	    case 0177:
-	    case '\b':
-		if (lineptr > line) {
-		    xmon_putchar('\b');
-		    xmon_putchar(' ');
-		    xmon_putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    case 'U' & 0x1F:
-		while (lineptr > line) {
-		    xmon_putchar('\b');
-		    xmon_putchar(' ');
-		    xmon_putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    default:
-		if (lineptr >= &line[sizeof(line) - 1])
-		    xmon_putchar('\a');
-		else {
-		    xmon_putchar(c);
-		    *lineptr++ = c;
-		}
-	    }
-	}
-	lineleft = lineptr - line;
-	lineptr = line;
-    }
-    if (lineleft == 0)
-	return -1;
-    --lineleft;
-    return *lineptr++;
-}
-
-char *
-xmon_fgets(char *str, int nb, void *f)
-{
-    char *p;
-    int c;
-
-    for (p = str; p < str + nb - 1; ) {
-	c = xmon_getchar();
-	if (c == -1) {
-	    if (p == str)
-		return NULL;
-	    break;
-	}
-	*p++ = c;
-	if (c == '\n')
-	    break;
-    }
-    *p = 0;
-    return str;
-}
-
-void
-xmon_enter(void)
+void xmon_enter(void)
 {
 #ifdef CONFIG_ADB_PMU
 	if (_machine == _MACH_Pmac) {
@@ -613,8 +431,7 @@
 #endif
 }
 
-void
-xmon_leave(void)
+void xmon_leave(void)
 {
 #ifdef CONFIG_ADB_PMU
 	if (_machine == _MACH_Pmac) {
diff --git a/arch/powerpc/xmon/start_64.c b/arch/powerpc/xmon/start_64.c
index e50c158..712552c 100644
--- a/arch/powerpc/xmon/start_64.c
+++ b/arch/powerpc/xmon/start_64.c
@@ -6,182 +6,29 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  */
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/sysrq.h>
-#include <linux/init.h>
 #include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/prom.h>
-#include <asm/processor.h>
 #include <asm/udbg.h>
-#include <asm/system.h>
 #include "nonstdio.h"
 
-#ifdef CONFIG_MAGIC_SYSRQ
-
-static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs,
-			      struct tty_struct *tty) 
+void xmon_map_scc(void)
 {
-	/* ensure xmon is enabled */
-	xmon_init(1);
-	debugger(pt_regs);
 }
 
-static struct sysrq_key_op sysrq_xmon_op = 
-{
-	.handler =	sysrq_handle_xmon,
-	.help_msg =	"Xmon",
-	.action_msg =	"Entering xmon",
-};
-
-static int __init setup_xmon_sysrq(void)
-{
-	register_sysrq_key('x', &sysrq_xmon_op);
-	return 0;
-}
-__initcall(setup_xmon_sysrq);
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-int
-xmon_write(void *handle, void *ptr, int nb)
+int xmon_write(void *ptr, int nb)
 {
 	return udbg_write(ptr, nb);
 }
 
-int
-xmon_read(void *handle, void *ptr, int nb)
+int xmon_readchar(void)
 {
-	return udbg_read(ptr, nb);
+	if (udbg_getc)
+		return udbg_getc();
+	return -1;
 }
 
-int
-xmon_read_poll(void)
+int xmon_read_poll(void)
 {
 	if (udbg_getc_poll)
 		return udbg_getc_poll();
 	return -1;
 }
- 
-FILE *xmon_stdin;
-FILE *xmon_stdout;
-
-int
-xmon_putc(int c, void *f)
-{
-	char ch = c;
-
-	if (c == '\n')
-		xmon_putc('\r', f);
-	return xmon_write(f, &ch, 1) == 1? c: -1;
-}
-
-int
-xmon_putchar(int c)
-{
-	return xmon_putc(c, xmon_stdout);
-}
-
-int
-xmon_fputs(char *str, void *f)
-{
-	int n = strlen(str);
-
-	return xmon_write(f, str, n) == n? 0: -1;
-}
-
-int
-xmon_readchar(void)
-{
-	char ch;
-
-	for (;;) {
-		switch (xmon_read(xmon_stdin, &ch, 1)) {
-		case 1:
-			return ch;
-		case -1:
-			xmon_printf("read(stdin) returned -1\r\n", 0, 0);
-			return -1;
-		}
-	}
-}
-
-static char line[256];
-static char *lineptr;
-static int lineleft;
-
-int
-xmon_getchar(void)
-{
-	int c;
-
-	if (lineleft == 0) {
-		lineptr = line;
-		for (;;) {
-			c = xmon_readchar();
-			if (c == -1 || c == 4)
-				break;
-			if (c == '\r' || c == '\n') {
-				*lineptr++ = '\n';
-				xmon_putchar('\n');
-				break;
-			}
-			switch (c) {
-			case 0177:
-			case '\b':
-				if (lineptr > line) {
-					xmon_putchar('\b');
-					xmon_putchar(' ');
-					xmon_putchar('\b');
-					--lineptr;
-				}
-				break;
-			case 'U' & 0x1F:
-				while (lineptr > line) {
-					xmon_putchar('\b');
-					xmon_putchar(' ');
-					xmon_putchar('\b');
-					--lineptr;
-				}
-				break;
-			default:
-				if (lineptr >= &line[sizeof(line) - 1])
-					xmon_putchar('\a');
-				else {
-					xmon_putchar(c);
-					*lineptr++ = c;
-				}
-			}
-		}
-		lineleft = lineptr - line;
-		lineptr = line;
-	}
-	if (lineleft == 0)
-		return -1;
-	--lineleft;
-	return *lineptr++;
-}
-
-char *
-xmon_fgets(char *str, int nb, void *f)
-{
-	char *p;
-	int c;
-
-	for (p = str; p < str + nb - 1; ) {
-		c = xmon_getchar();
-		if (c == -1) {
-			if (p == str)
-				return NULL;
-			break;
-		}
-		*p++ = c;
-		if (c == '\n')
-			break;
-	}
-	*p = 0;
-	return str;
-}
diff --git a/arch/powerpc/xmon/start_8xx.c b/arch/powerpc/xmon/start_8xx.c
index a48bd59..4c17b04 100644
--- a/arch/powerpc/xmon/start_8xx.c
+++ b/arch/powerpc/xmon/start_8xx.c
@@ -15,273 +15,30 @@
 #include <asm/8xx_immap.h>
 #include <asm/mpc8xx.h>
 #include <asm/commproc.h>
+#include "nonstdio.h"
 
-extern void xmon_printf(const char *fmt, ...);
 extern int xmon_8xx_write(char *str, int nb);
 extern int xmon_8xx_read_poll(void);
 extern int xmon_8xx_read_char(void);
-void prom_drawhex(uint);
-void prom_drawstring(const char *str);
 
-static int use_screen = 1; /* default */
-
-#define TB_SPEED	25000000
-
-static inline unsigned int readtb(void)
+void xmon_map_scc(void)
 {
-	unsigned int ret;
-
-	asm volatile("mftb %0" : "=r" (ret) :);
-	return ret;
-}
-
-void buf_access(void)
-{
-}
-
-void
-xmon_map_scc(void)
-{
-
 	cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
-	use_screen = 0;
-	
-	prom_drawstring("xmon uses serial port\n");
 }
 
-static int scc_initialized = 0;
-
 void xmon_init_scc(void);
 
-int
-xmon_write(void *handle, void *ptr, int nb)
+int xmon_write(void *ptr, int nb)
 {
-	char *p = ptr;
-	int i, c, ct;
-
-	if (!scc_initialized)
-		xmon_init_scc();
-
 	return(xmon_8xx_write(ptr, nb));
 }
 
-int xmon_wants_key;
-
-int
-xmon_read(void *handle, void *ptr, int nb)
+int xmon_readchar(void)
 {
-	char *p = ptr;
-	int i;
-
-	if (!scc_initialized)
-		xmon_init_scc();
-
-	for (i = 0; i < nb; ++i) {
-		*p++ = xmon_8xx_read_char();
-	}
-	return i;
+	return xmon_8xx_read_char();
 }
 
-int
-xmon_read_poll(void)
+int xmon_read_poll(void)
 {
 	return(xmon_8xx_read_poll());
 }
-
-void
-xmon_init_scc()
-{
-	scc_initialized = 1;
-}
-
-#if 0
-extern int (*prom_entry)(void *);
-
-int
-xmon_exit(void)
-{
-    struct prom_args {
-	char *service;
-    } args;
-
-    for (;;) {
-	args.service = "exit";
-	(*prom_entry)(&args);
-    }
-}
-#endif
-
-void *xmon_stdin;
-void *xmon_stdout;
-void *xmon_stderr;
-
-void
-xmon_init(void)
-{
-}
-
-int
-xmon_putc(int c, void *f)
-{
-    char ch = c;
-
-    if (c == '\n')
-	xmon_putc('\r', f);
-    return xmon_write(f, &ch, 1) == 1? c: -1;
-}
-
-int
-xmon_putchar(int c)
-{
-    return xmon_putc(c, xmon_stdout);
-}
-
-int
-xmon_fputs(char *str, void *f)
-{
-    int n = strlen(str);
-
-    return xmon_write(f, str, n) == n? 0: -1;
-}
-
-int
-xmon_readchar(void)
-{
-    char ch;
-
-    for (;;) {
-	switch (xmon_read(xmon_stdin, &ch, 1)) {
-	case 1:
-	    return ch;
-	case -1:
-	    xmon_printf("read(stdin) returned -1\r\n", 0, 0);
-	    return -1;
-	}
-    }
-}
-
-static char line[256];
-static char *lineptr;
-static int lineleft;
-
-#if 0
-int xmon_expect(const char *str, unsigned int timeout)
-{
-	int c;
-	unsigned int t0;
-
-	timeout *= TB_SPEED;
-	t0 = readtb();
-	do {
-		lineptr = line;
-		for (;;) {
-			c = xmon_read_poll();
-			if (c == -1) {
-				if (readtb() - t0 > timeout)
-					return 0;
-				continue;
-			}
-			if (c == '\n')
-				break;
-			if (c != '\r' && lineptr < &line[sizeof(line) - 1])
-				*lineptr++ = c;
-		}
-		*lineptr = 0;
-	} while (strstr(line, str) == NULL);
-	return 1;
-}
-#endif
-
-int
-xmon_getchar(void)
-{
-    int c;
-
-    if (lineleft == 0) {
-	lineptr = line;
-	for (;;) {
-	    c = xmon_readchar();
-	    if (c == -1 || c == 4)
-		break;
-	    if (c == '\r' || c == '\n') {
-		*lineptr++ = '\n';
-		xmon_putchar('\n');
-		break;
-	    }
-	    switch (c) {
-	    case 0177:
-	    case '\b':
-		if (lineptr > line) {
-		    xmon_putchar('\b');
-		    xmon_putchar(' ');
-		    xmon_putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    case 'U' & 0x1F:
-		while (lineptr > line) {
-		    xmon_putchar('\b');
-		    xmon_putchar(' ');
-		    xmon_putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    default:
-		if (lineptr >= &line[sizeof(line) - 1])
-		    xmon_putchar('\a');
-		else {
-		    xmon_putchar(c);
-		    *lineptr++ = c;
-		}
-	    }
-	}
-	lineleft = lineptr - line;
-	lineptr = line;
-    }
-    if (lineleft == 0)
-	return -1;
-    --lineleft;
-    return *lineptr++;
-}
-
-char *
-xmon_fgets(char *str, int nb, void *f)
-{
-    char *p;
-    int c;
-
-    for (p = str; p < str + nb - 1; ) {
-	c = xmon_getchar();
-	if (c == -1) {
-	    if (p == str)
-		return 0;
-	    break;
-	}
-	*p++ = c;
-	if (c == '\n')
-	    break;
-    }
-    *p = 0;
-    return str;
-}
-
-void
-prom_drawhex(uint val)
-{
-	unsigned char buf[10];
-
-	int i;
-	for (i = 7;  i >= 0;  i--)
-	{
-		buf[i] = "0123456789abcdef"[val & 0x0f];
-		val >>= 4;
-	}
-	buf[8] = '\0';
-	xmon_fputs(buf, xmon_stdout);
-}
-
-void
-prom_drawstring(const char *str)
-{
-	xmon_fputs(str, xmon_stdout);
-}
diff --git a/arch/powerpc/xmon/subr_prf.c b/arch/powerpc/xmon/subr_prf.c
deleted file mode 100644
index b48738c..0000000
--- a/arch/powerpc/xmon/subr_prf.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Written by Cort Dougan to replace the version originally used
- * by Paul Mackerras, which came from NetBSD and thus had copyright
- * conflicts with Linux.
- *
- * This file makes liberal use of the standard linux utility
- * routines to reduce the size of the binary.  We assume we can
- * trust some parts of Linux inside the debugger.
- *   -- Cort (cort@cs.nmt.edu)
- *
- * Copyright (C) 1999 Cort Dougan.
- *
- *      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/kernel.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <stdarg.h>
-#include "nonstdio.h"
-
-extern int xmon_write(void *, void *, int);
-
-void xmon_vfprintf(void *f, const char *fmt, va_list ap)
-{
-	static char xmon_buf[2048];
-	int n;
-
-	n = vsprintf(xmon_buf, fmt, ap);
-	xmon_write(f, xmon_buf, n);
-}
-
-void xmon_printf(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	xmon_vfprintf(stdout, fmt, ap);
-	va_end(ap);
-}
-EXPORT_SYMBOL(xmon_printf);
-
-void xmon_fprintf(void *f, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	xmon_vfprintf(f, fmt, ap);
-	va_end(ap);
-}
-
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 1124f11..ef4356b2 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -1,7 +1,7 @@
 /*
  * Routines providing a simple monitor for use on the PowerMac.
  *
- * Copyright (C) 1996 Paul Mackerras.
+ * Copyright (C) 1996-2005 Paul Mackerras.
  *
  *      This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -18,6 +18,7 @@
 #include <linux/kallsyms.h>
 #include <linux/cpumask.h>
 #include <linux/module.h>
+#include <linux/sysrq.h>
 
 #include <asm/ptrace.h>
 #include <asm/string.h>
@@ -144,15 +145,10 @@
 static const char *getvecname(unsigned long vec);
 
 extern int print_insn_powerpc(unsigned long, unsigned long, int);
-extern void printf(const char *fmt, ...);
-extern void xmon_vfprintf(void *f, const char *fmt, va_list ap);
-extern int xmon_putc(int c, void *f);
-extern int putchar(int ch);
 
 extern void xmon_enter(void);
 extern void xmon_leave(void);
 
-extern int xmon_read_poll(void);
 extern long setjmp(long *);
 extern void longjmp(long *, long);
 extern void xmon_save_regs(struct pt_regs *);
@@ -748,7 +744,6 @@
 		printf("%x:", smp_processor_id());
 #endif /* CONFIG_SMP */
 		printf("mon> ");
-		fflush(stdout);
 		flush_input();
 		termch = 0;
 		cmd = skipbl();
@@ -1472,17 +1467,23 @@
 {
 	unsigned int instrs[2];
 	unsigned long (*code)(void);
-	unsigned long opd[3];
 	unsigned long ret = -1UL;
+#ifdef CONFIG_PPC64
+	unsigned long opd[3];
 
-	instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
-	instrs[1] = 0x4e800020;
 	opd[0] = (unsigned long)instrs;
 	opd[1] = 0;
 	opd[2] = 0;
+	code = (unsigned long (*)(void)) opd;
+#else
+	code = (unsigned long (*)(void)) instrs;
+#endif
+
+	/* mfspr r3,n; blr */
+	instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
+	instrs[1] = 0x4e800020;
 	store_inst(instrs);
 	store_inst(instrs+1);
-	code = (unsigned long (*)(void)) opd;
 
 	if (setjmp(bus_error_jmp) == 0) {
 		catch_memory_errors = 1;
@@ -1504,16 +1505,21 @@
 {
 	unsigned int instrs[2];
 	unsigned long (*code)(unsigned long);
+#ifdef CONFIG_PPC64
 	unsigned long opd[3];
 
-	instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
-	instrs[1] = 0x4e800020;
 	opd[0] = (unsigned long)instrs;
 	opd[1] = 0;
 	opd[2] = 0;
+	code = (unsigned long (*)(unsigned long)) opd;
+#else
+	code = (unsigned long (*)(unsigned long)) instrs;
+#endif
+
+	instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
+	instrs[1] = 0x4e800020;
 	store_inst(instrs);
 	store_inst(instrs+1);
-	code = (unsigned long (*)(unsigned long)) opd;
 
 	if (setjmp(bus_error_jmp) == 0) {
 		catch_memory_errors = 1;
@@ -1797,7 +1803,7 @@
 	for(;;){
 		if (!mnoread)
 			n = mread(adrs, val, size);
-		printf("%.16x%c", adrs, brev? 'r': ' ');
+		printf(REG"%c", adrs, brev? 'r': ' ');
 		if (!mnoread) {
 			if (brev)
 				byterev(val, size);
@@ -1976,17 +1982,18 @@
 		nr = mread(adrs, temp, r);
 		adrs += nr;
 		for (m = 0; m < r; ++m) {
-		        if ((m & 7) == 0 && m > 0)
-			    putchar(' ');
+		        if ((m & (sizeof(long) - 1)) == 0 && m > 0)
+				putchar(' ');
 			if (m < nr)
 				printf("%.2x", temp[m]);
 			else
 				printf("%s", fault_chars[fault_type]);
 		}
-		if (m <= 8)
-			printf(" ");
-		for (; m < 16; ++m)
+		for (; m < 16; ++m) {
+		        if ((m & (sizeof(long) - 1)) == 0)
+				putchar(' ');
 			printf("  ");
+		}
 		printf("  |");
 		for (m = 0; m < r; ++m) {
 			if (m < nr) {
@@ -2151,7 +2158,6 @@
 		ok = mread(a, &v, 1);
 		if (ok && !ook) {
 			printf("%.8x .. ", a);
-			fflush(stdout);
 		} else if (!ok && ook)
 			printf("%.8x\n", a - mskip);
 		ook = ok;
@@ -2372,7 +2378,7 @@
 inchar(void)
 {
 	if (lineptr == NULL || *lineptr == 0) {
-		if (fgets(line, sizeof(line), stdin) == NULL) {
+		if (xmon_gets(line, sizeof(line)) == NULL) {
 			lineptr = NULL;
 			return EOF;
 		}
@@ -2526,4 +2532,29 @@
 		__debugger_dabr_match = NULL;
 		__debugger_fault_handler = NULL;
 	}
+	xmon_map_scc();
 }
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs,
+			      struct tty_struct *tty) 
+{
+	/* ensure xmon is enabled */
+	xmon_init(1);
+	debugger(pt_regs);
+}
+
+static struct sysrq_key_op sysrq_xmon_op = 
+{
+	.handler =	sysrq_handle_xmon,
+	.help_msg =	"Xmon",
+	.action_msg =	"Entering xmon",
+};
+
+static int __init setup_xmon_sysrq(void)
+{
+	register_sysrq_key('x', &sysrq_xmon_op);
+	return 0;
+}
+__initcall(setup_xmon_sysrq);
+#endif /* CONFIG_MAGIC_SYSRQ */
diff --git a/arch/ppc/boot/include/of1275.h b/arch/ppc/boot/include/of1275.h
index 69173df..4ed88ac 100644
--- a/arch/ppc/boot/include/of1275.h
+++ b/arch/ppc/boot/include/of1275.h
@@ -19,6 +19,9 @@
 
 /* function declarations */
 
+int	call_prom(const char *service, int nargs, int nret, ...);
+int	call_prom_ret(const char *service, int nargs, int nret,
+		      unsigned int *rets, ...);
 void *	claim(unsigned int virt, unsigned int size, unsigned int align);
 int	map(unsigned int phys, unsigned int virt, unsigned int size);
 void	enter(void);
diff --git a/arch/ppc/boot/of1275/Makefile b/arch/ppc/boot/of1275/Makefile
index 02e6f23..0b979c0 100644
--- a/arch/ppc/boot/of1275/Makefile
+++ b/arch/ppc/boot/of1275/Makefile
@@ -3,4 +3,4 @@
 #
 
 lib-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o	\
-	 ofstdio.o read.o release.o write.o map.o
+	 ofstdio.o read.o release.o write.o map.o call_prom.o
diff --git a/arch/ppc/boot/of1275/call_prom.c b/arch/ppc/boot/of1275/call_prom.c
new file mode 100644
index 0000000..9479a3a
--- /dev/null
+++ b/arch/ppc/boot/of1275/call_prom.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * 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 "of1275.h"
+#include <stdarg.h>
+
+int call_prom(const char *service, int nargs, int nret, ...)
+{
+	int i;
+	struct prom_args {
+		const char *service;
+		int nargs;
+		int nret;
+		unsigned int args[12];
+	} args;
+	va_list list;
+
+	args.service = service;
+	args.nargs = nargs;
+	args.nret = nret;
+
+	va_start(list, nret);
+	for (i = 0; i < nargs; i++)
+		args.args[i] = va_arg(list, unsigned int);
+	va_end(list);
+
+	for (i = 0; i < nret; i++)
+		args.args[nargs+i] = 0;
+
+	if (of_prom_entry(&args) < 0)
+		return -1;
+
+	return (nret > 0)? args.args[nargs]: 0;
+}
+
+int call_prom_ret(const char *service, int nargs, int nret,
+		  unsigned int *rets, ...)
+{
+	int i;
+	struct prom_args {
+		const char *service;
+		int nargs;
+		int nret;
+		unsigned int args[12];
+	} args;
+	va_list list;
+
+	args.service = service;
+	args.nargs = nargs;
+	args.nret = nret;
+
+	va_start(list, rets);
+	for (i = 0; i < nargs; i++)
+		args.args[i] = va_arg(list, unsigned int);
+	va_end(list);
+
+	for (i = 0; i < nret; i++)
+		args.args[nargs+i] = 0;
+
+	if (of_prom_entry(&args) < 0)
+		return -1;
+
+	if (rets != (void *) 0)
+		for (i = 1; i < nret; ++i)
+			rets[i-1] = args.args[nargs+i];
+
+	return (nret > 0)? args.args[nargs]: 0;
+}
diff --git a/arch/ppc/boot/of1275/claim.c b/arch/ppc/boot/of1275/claim.c
index 13169a5..1ed3aee 100644
--- a/arch/ppc/boot/of1275/claim.c
+++ b/arch/ppc/boot/of1275/claim.c
@@ -9,27 +9,84 @@
  */
 
 #include "of1275.h"
+#include "nonstdio.h"
 
-void *
-claim(unsigned int virt, unsigned int size, unsigned int align)
+/*
+ * Older OF's require that when claiming a specific range of addresses,
+ * we claim the physical space in the /memory node and the virtual
+ * space in the chosen mmu node, and then do a map operation to
+ * map virtual to physical.
+ */
+static int need_map = -1;
+static ihandle chosen_mmu;
+static phandle memory;
+
+/* returns true if s2 is a prefix of s1 */
+static int string_match(const char *s1, const char *s2)
 {
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	unsigned int virt;
-	unsigned int size;
-	unsigned int align;
-	void *ret;
-    } args;
+	for (; *s2; ++s2)
+		if (*s1++ != *s2)
+			return 0;
+	return 1;
+}
 
-    args.service = "claim";
-    args.nargs = 3;
-    args.nret = 1;
-    args.virt = virt;
-    args.size = size;
-    args.align = align;
-    args.ret = (void *) 0;
-    (*of_prom_entry)(&args);
-    return args.ret;
+static int check_of_version(void)
+{
+	phandle oprom, chosen;
+	char version[64];
+
+	oprom = finddevice("/openprom");
+	if (oprom == OF_INVALID_HANDLE)
+		return 0;
+	if (getprop(oprom, "model", version, sizeof(version)) <= 0)
+		return 0;
+	version[sizeof(version)-1] = 0;
+	printf("OF version = '%s'\n", version);
+	if (!string_match(version, "Open Firmware, 1.")
+	    && !string_match(version, "FirmWorks,3."))
+		return 0;
+	chosen = finddevice("/chosen");
+	if (chosen == OF_INVALID_HANDLE) {
+		chosen = finddevice("/chosen@0");
+		if (chosen == OF_INVALID_HANDLE) {
+			printf("no chosen\n");
+			return 0;
+		}
+	}
+	if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
+		printf("no mmu\n");
+		return 0;
+	}
+	memory = (ihandle) call_prom("open", 1, 1, "/memory");
+	if (memory == OF_INVALID_HANDLE) {
+		memory = (ihandle) call_prom("open", 1, 1, "/memory@0");
+		if (memory == OF_INVALID_HANDLE) {
+			printf("no memory node\n");
+			return 0;
+		}
+	}
+	printf("old OF detected\n");
+	return 1;
+}
+
+void *claim(unsigned int virt, unsigned int size, unsigned int align)
+{
+	int ret;
+	unsigned int result;
+
+	if (need_map < 0)
+		need_map = check_of_version();
+	if (align || !need_map)
+		return (void *) call_prom("claim", 3, 1, virt, size, align);
+	
+	ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
+			    align, size, virt);
+	if (ret != 0 || result == -1)
+		return (void *) -1;
+	ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
+			    align, size, virt);
+	/* 0x12 == coherent + read/write */
+	ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
+			0x12, size, virt, virt);
+	return virt;
 }
diff --git a/arch/ppc/boot/of1275/finddevice.c b/arch/ppc/boot/of1275/finddevice.c
index 2c0f7cb..0dcb120 100644
--- a/arch/ppc/boot/of1275/finddevice.c
+++ b/arch/ppc/boot/of1275/finddevice.c
@@ -10,22 +10,7 @@
 
 #include "of1275.h"
 
-phandle
-finddevice(const char *name)
+phandle finddevice(const char *name)
 {
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	const char *devspec;
-	phandle device;
-    } args;
-
-    args.service = "finddevice";
-    args.nargs = 1;
-    args.nret = 1;
-    args.devspec = name;
-    args.device = OF_INVALID_HANDLE;
-    (*of_prom_entry)(&args);
-    return args.device;
+	return (phandle) call_prom("finddevice", 1, 1, name);
 }
diff --git a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile
index 0341523..83a6433 100644
--- a/arch/ppc/boot/openfirmware/Makefile
+++ b/arch/ppc/boot/openfirmware/Makefile
@@ -80,8 +80,7 @@
 	$(call if_changed,mknote)
 
 
-$(obj)/coffcrt0.o: EXTRA_AFLAGS := -traditional -DXCOFF
-$(obj)/crt0.o:     EXTRA_AFLAGS := -traditional
+$(obj)/coffcrt0.o: EXTRA_AFLAGS := -DXCOFF
 targets += coffcrt0.o crt0.o
 $(obj)/coffcrt0.o $(obj)/crt0.o: $(common)/crt0.S FORCE
 	$(call if_changed_dep,as_o_S)
diff --git a/arch/ppc/configs/mpc834x_sys_defconfig b/arch/ppc/configs/mpc834x_sys_defconfig
index 4a5522c..673dc64 100644
--- a/arch/ppc/configs/mpc834x_sys_defconfig
+++ b/arch/ppc/configs/mpc834x_sys_defconfig
@@ -1,16 +1,17 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Thu Feb 17 16:12:23 2005
+# Linux kernel version: 2.6.14
+# Mon Nov  7 15:38:29 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
 CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 
 #
 # Code maturity level options
@@ -18,23 +19,28 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=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_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 # CONFIG_EPOLL is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -44,6 +50,7 @@
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -59,34 +66,84 @@
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
+# CONFIG_E200 is not set
 # CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
+# CONFIG_KEXEC is not set
 # CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
 CONFIG_PPC_GEN550=y
-CONFIG_83xx=y
-
-#
-# Freescale 83xx options
-#
-CONFIG_MPC834x_SYS=y
-CONFIG_MPC834x=y
 CONFIG_PPC_STD_MMU=y
 
 #
 # Platform options
 #
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_CHESTNUT is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
+# CONFIG_EV64260 is not set
+# CONFIG_LOPEC 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_RADSTONE_PPC7D is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+CONFIG_MPC834x_SYS=y
+# CONFIG_EV64360 is not set
+CONFIG_83xx=y
+CONFIG_MPC834x=y
 # CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
 # 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_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_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # 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_GENERIC_ISA_DMA=y
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_MPC83xx_PCI2 is not set
+CONFIG_PCI_LEGACY_PROC=y
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -94,10 +151,6 @@
 # CONFIG_PCCARD is not set
 
 #
-# PC-card bridges
-#
-
-#
 # Advanced setup
 #
 # CONFIG_ADVANCED_OPTIONS is not set
@@ -112,6 +165,75 @@
 CONFIG_BOOT_LOAD=0x00800000
 
 #
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_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_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
+# CONFIG_IPV6 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
+# 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_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE 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
 #
 
@@ -123,6 +245,11 @@
 # CONFIG_FW_LOADER is not set
 
 #
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
 # Memory Technology Devices (MTD)
 #
 # CONFIG_MTD is not set
@@ -140,15 +267,19 @@
 # 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_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 # CONFIG_CDROM_PKTCDVD is not set
 
@@ -159,6 +290,11 @@
 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_ATA_OVER_ETH is not set
 
 #
@@ -169,6 +305,7 @@
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
 
 #
@@ -179,85 +316,25 @@
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
 #
+# CONFIG_I2O is not set
 
 #
 # Macintosh device drivers
 #
 
 #
-# Networking support
+# Network device support
 #
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV 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_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_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP 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_NET_DIVERT 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
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -265,24 +342,90 @@
 # CONFIG_TUN is not set
 
 #
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY 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=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 is not set
+CONFIG_E100=y
+# 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_TLAN 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 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_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
 CONFIG_GIANFAR=y
 # CONFIG_GFAR_NAPI is not set
 
 #
 # Ethernet (10000 Mbit)
 #
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
 
 #
 # Token Ring devices
 #
+# CONFIG_TR is not set
 
 #
 # Wireless LAN (non-hamradio)
@@ -293,10 +436,14 @@
 # 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_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -323,14 +470,6 @@
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
 # Input Device Drivers
 #
 # CONFIG_INPUT_KEYBOARD is not set
@@ -340,6 +479,12 @@
 # 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
@@ -358,6 +503,7 @@
 #
 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
@@ -376,6 +522,7 @@
 # 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
@@ -385,6 +532,12 @@
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=y
@@ -400,48 +553,41 @@
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_ISA is not set
+# 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_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X 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
 
 #
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
 #
-# CONFIG_I2C_SENSOR 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_ASB100 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_GL518SM 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_MAX1619 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other 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_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -453,10 +599,55 @@
 # CONFIG_W1 is not set
 
 #
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID 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_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D 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
+
+#
 # Misc devices
 #
 
 #
+# Multimedia Capabilities Port drivers
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -479,11 +670,12 @@
 #
 # USB support
 #
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 #
 
 #
@@ -502,10 +694,15 @@
 # CONFIG_INFINIBAND is not set
 
 #
+# SN Devices
+#
+
+#
 # 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
@@ -515,17 +712,16 @@
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS 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 is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -546,12 +742,10 @@
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -580,6 +774,7 @@
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -588,6 +783,7 @@
 # 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
@@ -614,6 +810,7 @@
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 
@@ -625,7 +822,9 @@
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SERIAL_TEXT_DEBUG is not set
 
 #
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 76a55a4..17a4da6 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -12,7 +12,7 @@
 extra-$(CONFIG_POWER4)		+= idle_power4.o
 extra-y				+= vmlinux.lds
 
-obj-y				:= entry.o traps.o irq.o idle.o time.o misc.o \
+obj-y				:= entry.o traps.o idle.o time.o misc.o \
 					process.o align.o \
 					setup.o \
 					ppc_htab.o
@@ -38,8 +38,7 @@
 # These are here while we do the architecture merge
 
 else
-obj-y				:= irq.o idle.o \
-					align.o
+obj-y				:= idle.o align.o
 obj-$(CONFIG_6xx)		+= l2cr.o cpu_setup_6xx.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o
 obj-$(CONFIG_MODULES)		+= module.o
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
index 968261d..fe0e767 100644
--- a/arch/ppc/kernel/asm-offsets.c
+++ b/arch/ppc/kernel/asm-offsets.c
@@ -25,6 +25,7 @@
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
+#include <asm/vdso_datapage.h>
 
 #define DEFINE(sym, val) \
 	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -143,5 +144,32 @@
 
 	DEFINE(TASK_SIZE, TASK_SIZE);
 	DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
+
+	/* datapage offsets for use by vdso */
+	DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct vdso_data, tb_orig_stamp));
+	DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct vdso_data, tb_ticks_per_sec));
+	DEFINE(CFG_TB_TO_XS, offsetof(struct vdso_data, tb_to_xs));
+	DEFINE(CFG_STAMP_XSEC, offsetof(struct vdso_data, stamp_xsec));
+	DEFINE(CFG_TB_UPDATE_COUNT, offsetof(struct vdso_data, tb_update_count));
+	DEFINE(CFG_TZ_MINUTEWEST, offsetof(struct vdso_data, tz_minuteswest));
+	DEFINE(CFG_TZ_DSTTIME, offsetof(struct vdso_data, tz_dsttime));
+	DEFINE(CFG_SYSCALL_MAP32, offsetof(struct vdso_data, syscall_map_32));
+	DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec));
+	DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
+	DEFINE(TVAL32_TV_SEC, offsetof(struct timeval, tv_sec));
+	DEFINE(TVAL32_TV_USEC, offsetof(struct timeval, tv_usec));
+	DEFINE(TSPEC32_TV_SEC, offsetof(struct timespec, tv_sec));
+	DEFINE(TSPEC32_TV_NSEC, offsetof(struct timespec, tv_nsec));
+
+	/* timeval/timezone offsets for use by vdso */
+	DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest));
+	DEFINE(TZONE_TZ_DSTTIME, offsetof(struct timezone, tz_dsttime));
+
+	/* Other bits used by the vdso */
+	DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
+	DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
+	DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
+	DEFINE(CLOCK_REALTIME_RES, TICK_NSEC);
+
 	return 0;
 }
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h
index aeb349b..f3d274c 100644
--- a/arch/ppc/kernel/head_booke.h
+++ b/arch/ppc/kernel/head_booke.h
@@ -358,6 +358,6 @@
 	NORMAL_EXCEPTION_PROLOG;					      \
 	bne	load_up_fpu;		/* if from user, just load it up */   \
 	addi	r3,r1,STACK_FRAME_OVERHEAD;				      \
-	EXC_XFER_EE_LITE(0x800, KernelFP)
+	EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
 
 #endif /* __HEAD_BOOKE_H__ */
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index 11e5b44..821a75e 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -53,10 +53,6 @@
 		}
 #endif
 	}
-	if (need_resched())
-		schedule();
-	if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
-		cpu_die();
 }
 
 /*
@@ -64,11 +60,22 @@
  */
 void cpu_idle(void)
 {
-	for (;;)
-		if (ppc_md.idle != NULL)
-			ppc_md.idle();
-		else
-			default_idle();
+	int cpu = smp_processor_id();
+
+	for (;;) {
+		while (!need_resched()) {
+			if (ppc_md.idle != NULL)
+				ppc_md.idle();
+			else
+				default_idle();
+		}
+
+		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
+			cpu_die();
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+	}
 }
 
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx)
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
deleted file mode 100644
index fbb2b9f..0000000
--- a/arch/ppc/kernel/irq.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- *  arch/ppc/kernel/irq.c
- *
- *  Derived from arch/i386/kernel/irq.c
- *    Copyright (C) 1992 Linus Torvalds
- *  Adapted from arch/i386 by Gary Thomas
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
- *    Copyright (C) 1996-2001 Cort Dougan
- *  Adapted for Power Macintosh by Paul Mackerras
- *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
- *
- * This file contains the code used by various IRQ handling routines:
- * asking for different IRQ's should be done through these routines
- * instead of just grabbing them. Thus setups with different IRQ numbers
- * shouldn't result in any weird surprises, and installing new handlers
- * should be easier.
- *
- * The MPC8xx has an interrupt mask in the SIU.  If a bit is set, the
- * interrupt is _enabled_.  As expected, IRQ0 is bit 0 in the 32-bit
- * mask register (of which only 16 are defined), hence the weird shifting
- * and complement of the cached_irq_mask.  I want to be able to stuff
- * this right into the SIU SMASK register.
- * Many of the prep/chrp functions are conditional compiled on CONFIG_8xx
- * to reduce code space and undefined function references.
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/threads.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/timex.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/proc_fs.h>
-#include <linux/random.h>
-#include <linux/seq_file.h>
-#include <linux/cpumask.h>
-#include <linux/profile.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/cache.h>
-#include <asm/prom.h>
-#include <asm/ptrace.h>
-#include <asm/machdep.h>
-
-#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
-
-extern atomic_t ipi_recv;
-extern atomic_t ipi_sent;
-
-#define MAXCOUNT 10000000
-
-int ppc_spurious_interrupts = 0;
-struct irqaction *ppc_irq_action[NR_IRQS];
-unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
-unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
-atomic_t ppc_n_lost_interrupts;
-
-#ifdef CONFIG_TAU_INT
-extern int tau_initialized;
-extern int tau_interrupts(int);
-#endif
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-	int i = *(loff_t *) v, j;
-	struct irqaction * action;
-	unsigned long flags;
-
-	if (i == 0) {
-		seq_puts(p, "           ");
-		for (j=0; j<NR_CPUS; j++)
-			if (cpu_online(j))
-				seq_printf(p, "CPU%d       ", j);
-		seq_putc(p, '\n');
-	}
-
-	if (i < NR_IRQS) {
-		spin_lock_irqsave(&irq_desc[i].lock, flags);
-		action = irq_desc[i].action;
-		if ( !action || !action->handler )
-			goto skip;
-		seq_printf(p, "%3d: ", i);
-#ifdef CONFIG_SMP
-		for (j = 0; j < NR_CPUS; j++)
-			if (cpu_online(j))
-				seq_printf(p, "%10u ",
-					   kstat_cpu(j).irqs[i]);
-#else
-		seq_printf(p, "%10u ", kstat_irqs(i));
-#endif /* CONFIG_SMP */
-		if (irq_desc[i].handler)
-			seq_printf(p, " %s ", irq_desc[i].handler->typename);
-		else
-			seq_puts(p, "  None      ");
-		seq_printf(p, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge  ");
-		seq_printf(p, "    %s", action->name);
-		for (action = action->next; action; action = action->next)
-			seq_printf(p, ", %s", action->name);
-		seq_putc(p, '\n');
-skip:
-		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
-	} else if (i == NR_IRQS) {
-#ifdef CONFIG_TAU_INT
-		if (tau_initialized){
-			seq_puts(p, "TAU: ");
-			for (j = 0; j < NR_CPUS; j++)
-				if (cpu_online(j))
-					seq_printf(p, "%10u ", tau_interrupts(j));
-			seq_puts(p, "  PowerPC             Thermal Assist (cpu temp)\n");
-		}
-#endif
-#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
-		/* should this be per processor send/receive? */
-		seq_printf(p, "IPI (recv/sent): %10u/%u\n",
-				atomic_read(&ipi_recv), atomic_read(&ipi_sent));
-#endif
-		seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts);
-	}
-	return 0;
-}
-
-void do_IRQ(struct pt_regs *regs)
-{
-	int irq, first = 1;
-        irq_enter();
-
-	/*
-	 * Every platform is required to implement ppc_md.get_irq.
-	 * This function will either return an irq number or -1 to
-	 * indicate there are no more pending.  But the first time
-	 * through the loop this means there wasn't and IRQ pending.
-	 * The value -2 is for buggy hardware and means that this IRQ
-	 * has already been handled. -- Tom
-	 */
-	while ((irq = ppc_md.get_irq(regs)) >= 0) {
-		__do_IRQ(irq, regs);
-		first = 0;
-	}
-	if (irq != -2 && first)
-		/* That's not SMP safe ... but who cares ? */
-		ppc_spurious_interrupts++;
-        irq_exit();
-}
-
-void __init init_IRQ(void)
-{
-	ppc_md.init_IRQ();
-}
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index ae6af29..5e61124 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -497,9 +497,9 @@
  * and invalidate the corresponding instruction cache blocks.
  * This is a no-op on the 601.
  *
- * flush_icache_range(unsigned long start, unsigned long stop)
+ * __flush_icache_range(unsigned long start, unsigned long stop)
  */
-_GLOBAL(flush_icache_range)
+_GLOBAL(__flush_icache_range)
 BEGIN_FTR_SECTION
 	blr				/* for 601, do nothing */
 END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index e8f4e57..48ed58f 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -62,20 +62,6 @@
 static int pci_bus_count;
 
 static void
-fixup_rev1_53c810(struct pci_dev* dev)
-{
-	/* rev 1 ncr53c810 chips don't set the class at all which means
-	 * they don't get their resources remapped. Fix that here.
-	 */
-
-	if ((dev->class == PCI_CLASS_NOT_DEFINED)) {
-		printk("NCR 53c810 rev 1 detected, setting PCI class.\n");
-		dev->class = PCI_CLASS_STORAGE_SCSI;
-	}
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	fixup_rev1_53c810);
-
-static void
 fixup_broken_pcnet32(struct pci_dev* dev)
 {
 	if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index e0ca61b..66073f7 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -46,6 +46,7 @@
 #include <asm/btext.h>
 #include <asm/div64.h>
 #include <asm/xmon.h>
+#include <asm/signal.h>
 
 #ifdef  CONFIG_8xx
 #include <asm/commproc.h>
@@ -57,7 +58,6 @@
 extern void alignment_exception(struct pt_regs *regs);
 extern void program_check_exception(struct pt_regs *regs);
 extern void single_step_exception(struct pt_regs *regs);
-extern int do_signal(sigset_t *, struct pt_regs *);
 extern int pmac_newworld;
 extern int sys_sigreturn(struct pt_regs *regs);
 
@@ -78,7 +78,6 @@
 EXPORT_SYMBOL(single_step_exception);
 EXPORT_SYMBOL(sys_sigreturn);
 EXPORT_SYMBOL(ppc_n_lost_interrupts);
-EXPORT_SYMBOL(ppc_lost_interrupts);
 
 EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
 EXPORT_SYMBOL(DMA_MODE_READ);
@@ -176,6 +175,7 @@
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_NOT_COHERENT_CACHE
+extern void flush_dcache_all(void);
 EXPORT_SYMBOL(flush_dcache_all);
 #endif
 
@@ -217,9 +217,6 @@
 EXPORT_SYMBOL(cuda_request);
 EXPORT_SYMBOL(cuda_poll);
 #endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_PPC_MULTIPLATFORM
-EXPORT_SYMBOL(_machine);
-#endif
 #ifdef CONFIG_PPC_PMAC
 EXPORT_SYMBOL(sys_ctrler);
 EXPORT_SYMBOL(pmac_newworld);
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 6bcb85d..dc55e1a 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -76,6 +76,7 @@
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
 int _machine = 0;
+EXPORT_SYMBOL(_machine);
 
 extern void prep_init(unsigned long r3, unsigned long r4,
 		unsigned long r5, unsigned long r6, unsigned long r7);
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index bc5bf11..43b8fc2 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -341,6 +341,7 @@
 	cpu = smp_processor_id();
         smp_store_cpu_info(cpu);
 	set_dec(tb_ticks_per_jiffy);
+	preempt_disable();
 	cpu_callin_map[cpu] = 1;
 
 	printk("CPU %d done callin...\n", cpu);
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
index 79b3f53..98edc75 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.c
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -51,6 +51,9 @@
 
 #include <syslib/ppc83xx_setup.h>
 
+static const char *GFAR_PHY_0 = "phy0:0";
+static const char *GFAR_PHY_1 = "phy0:1";
+
 #ifndef CONFIG_PCI
 unsigned long isa_io_base = 0;
 unsigned long isa_mem_base = 0;
@@ -97,6 +100,7 @@
 	bd_t *binfo = (bd_t *) __res;
 	unsigned int freq;
 	struct gianfar_platform_data *pdata;
+	struct gianfar_mdio_data *mdata;
 
 	/* get the core frequency */
 	freq = binfo->bi_intfreq;
@@ -111,24 +115,27 @@
 #endif
 	mpc83xx_early_serial_map();
 
+	/* setup the board related info for the MDIO bus */
+	mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC83xx_MDIO);
+
+	mdata->irq[0] = MPC83xx_IRQ_EXT1;
+	mdata->irq[1] = MPC83xx_IRQ_EXT2;
+	mdata->irq[2] = -1;
+	mdata->irq[31] = -1;
+	mdata->paddr += binfo->bi_immr_base;
+
 	/* setup the board related information for the enet controllers */
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->interruptPHY = MPC83xx_IRQ_EXT1;
-		pdata->phyid = 0;
-		/* fixup phy address */
-		pdata->phy_reg_addr += binfo->bi_immr_base;
+		pdata->bus_id = GFAR_PHY_0;
 		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->interruptPHY = MPC83xx_IRQ_EXT2;
-		pdata->phyid = 1;
-		/* fixup phy address */
-		pdata->phy_reg_addr += binfo->bi_immr_base;
+		pdata->bus_id = GFAR_PHY_1;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 	}
 
diff --git a/arch/ppc/platforms/85xx/stx_gp3.h b/arch/ppc/platforms/85xx/stx_gp3.h
index 95fdf4b..7bcc6c3 100644
--- a/arch/ppc/platforms/85xx/stx_gp3.h
+++ b/arch/ppc/platforms/85xx/stx_gp3.h
@@ -21,6 +21,7 @@
 
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/seq_file.h>
 #include <asm/ppcboot.h>
 
 #define BOARD_CCSRBAR		((uint)0xe0000000)
diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c
index 9f2d95e..4742bf6 100644
--- a/arch/ppc/platforms/pmac_pic.c
+++ b/arch/ppc/platforms/pmac_pic.c
@@ -75,6 +75,9 @@
 #define GATWICK_IRQ_POOL_SIZE        10
 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
 
+#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
+static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
+
 /*
  * Mark an irq as "lost".  This is only used on the pmac
  * since it can lose interrupts (see pmac_set_irq_mask).
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
index 067d7d5..4415748 100644
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -61,6 +61,15 @@
 #include <asm/pci-bridge.h>
 #include <asm/todc.h>
 
+/* prep registers for L2 */
+#define CACHECRBA       0x80000823      /* Cache configuration register address */
+#define L2CACHE_MASK	0x03	/* Mask for 2 L2 Cache bits */
+#define L2CACHE_512KB	0x00	/* 512KB */
+#define L2CACHE_256KB	0x01	/* 256KB */
+#define L2CACHE_1MB	0x02	/* 1MB */
+#define L2CACHE_NONE	0x03	/* NONE */
+#define L2CACHE_PARITY  0x08    /* Mask for L2 Cache Parity Protected bit */
+
 TODC_ALLOC();
 
 unsigned char ucSystemType;
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 5bd33ba..5b7f2b8 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -33,7 +33,6 @@
 obj-$(CONFIG_PPC4xx_EDMA)	+= ppc4xx_sgdma.o
 ifeq ($(CONFIG_40x),y)
 obj-$(CONFIG_PCI)		+= pci_auto.o ppc405_pci.o
-obj-$(CONFIG_RAPIDIO)		+= ppc85xx_rio.o
 endif
 endif
 obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \
@@ -96,6 +95,7 @@
 ifeq ($(CONFIG_85xx),y)
 obj-$(CONFIG_PCI)		+= pci_auto.o
 endif
+obj-$(CONFIG_RAPIDIO)		+= ppc85xx_rio.o
 obj-$(CONFIG_83xx)		+= ipic.o ppc83xx_setup.o ppc_sys.o \
 					mpc83xx_sys.o mpc83xx_devices.o
 ifeq ($(CONFIG_83xx),y)
diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c
index c867be6..29d95d41 100644
--- a/arch/ppc/syslib/cpm2_pic.c
+++ b/arch/ppc/syslib/cpm2_pic.c
@@ -37,7 +37,7 @@
 static	u_char	irq_to_siubit[] = {
 	 0, 15, 14, 13, 12, 11, 10,  9,
 	 8,  7,  6,  5,  4,  3,  2,  1,
-	 2,  1, 15, 14, 13, 12, 11, 10,
+	 2,  1,  0, 14, 13, 12, 11, 10,
 	 9,  8,  7,  6,  5,  4,  3,  0,
 	31, 30, 29, 28, 27, 26, 25, 24,
 	23, 22, 21, 20, 19, 18, 17, 16,
diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c
index dbf8aca..f43fbf9 100644
--- a/arch/ppc/syslib/mpc83xx_devices.c
+++ b/arch/ppc/syslib/mpc83xx_devices.c
@@ -27,18 +27,20 @@
  * what IMMRBAR is, will get fixed up by mach_mpc83xx_fixup
  */
 
+struct gianfar_mdio_data mpc83xx_mdio_pdata = {
+	.paddr = 0x24520,
+};
+
 static struct gianfar_platform_data mpc83xx_tsec1_pdata = {
 	.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
 	    FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
 	    FSL_GIANFAR_DEV_HAS_MULTI_INTR,
-	.phy_reg_addr = 0x24000,
 };
 
 static struct gianfar_platform_data mpc83xx_tsec2_pdata = {
 	.device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
 	    FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
 	    FSL_GIANFAR_DEV_HAS_MULTI_INTR,
-	.phy_reg_addr = 0x24000,
 };
 
 static struct fsl_i2c_platform_data mpc83xx_fsl_i2c1_pdata = {
@@ -220,6 +222,12 @@
 			},
 		},
 	},
+	[MPC83xx_MDIO] = {
+		.name = "fsl-gianfar_mdio",
+		.id = 0,
+		.dev.platform_data = &mpc83xx_mdio_pdata,
+		.num_resources = 0,
+	},
 };
 
 static int __init mach_mpc83xx_fixup(struct platform_device *pdev)
diff --git a/arch/ppc/syslib/mpc83xx_sys.c b/arch/ppc/syslib/mpc83xx_sys.c
index 29aa633..da74344 100644
--- a/arch/ppc/syslib/mpc83xx_sys.c
+++ b/arch/ppc/syslib/mpc83xx_sys.c
@@ -24,72 +24,72 @@
 		.ppc_sys_name	= "8349E",
 		.mask 		= 0xFFFF0000,
 		.value 		= 0x80500000,
-		.num_devices	= 8,
+		.num_devices	= 9,
 		.device_list	= (enum ppc_sys_devices[])
 		{
 			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
 			MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
-			MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+			MPC83xx_USB2_DR, MPC83xx_USB2_MPH, MPC83xx_MDIO
 		},
 	},
 	{
 		.ppc_sys_name	= "8349",
 		.mask 		= 0xFFFF0000,
 		.value 		= 0x80510000,
-		.num_devices	= 7,
+		.num_devices	= 8,
 		.device_list	= (enum ppc_sys_devices[])
 		{
 			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
 			MPC83xx_IIC2, MPC83xx_DUART,
-			MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+			MPC83xx_USB2_DR, MPC83xx_USB2_MPH, MPC83xx_MDIO
 		},
 	},
 	{
 		.ppc_sys_name	= "8347E",
 		.mask 		= 0xFFFF0000,
 		.value 		= 0x80520000,
-		.num_devices	= 8,
+		.num_devices	= 9,
 		.device_list	= (enum ppc_sys_devices[])
 		{
 			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
 			MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
-			MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+			MPC83xx_USB2_DR, MPC83xx_USB2_MPH, MPC83xx_MDIO
 		},
 	},
 	{
 		.ppc_sys_name	= "8347",
 		.mask 		= 0xFFFF0000,
 		.value 		= 0x80530000,
-		.num_devices	= 7,
+		.num_devices	= 8,
 		.device_list	= (enum ppc_sys_devices[])
 		{
 			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
 			MPC83xx_IIC2, MPC83xx_DUART,
-			MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+			MPC83xx_USB2_DR, MPC83xx_USB2_MPH, MPC83xx_MDIO
 		},
 	},
 	{
 		.ppc_sys_name	= "8343E",
 		.mask 		= 0xFFFF0000,
 		.value 		= 0x80540000,
-		.num_devices	= 7,
+		.num_devices	= 8,
 		.device_list	= (enum ppc_sys_devices[])
 		{
 			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
 			MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
-			MPC83xx_USB2_DR,
+			MPC83xx_USB2_DR, MPC83xx_MDIO
 		},
 	},
 	{
 		.ppc_sys_name	= "8343",
 		.mask 		= 0xFFFF0000,
 		.value 		= 0x80550000,
-		.num_devices	= 6,
+		.num_devices	= 7,
 		.device_list	= (enum ppc_sys_devices[])
 		{
 			MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
 			MPC83xx_IIC2, MPC83xx_DUART,
-			MPC83xx_USB2_DR,
+			MPC83xx_USB2_DR, MPC83xx_MDIO
 		},
 	},
 	{	/* default match */
diff --git a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c
index 03b1fc9..af4deac 100644
--- a/arch/ppc/syslib/prom.c
+++ b/arch/ppc/syslib/prom.c
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/threads.h>
 #include <linux/spinlock.h>
 #include <linux/ioport.h>
diff --git a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c
index 7f15136..df14422 100644
--- a/arch/ppc/syslib/prom_init.c
+++ b/arch/ppc/syslib/prom_init.c
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/threads.h>
 #include <linux/spinlock.h>
 #include <linux/ioport.h>
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
index 2955234..9d10c12 100644
--- a/arch/ppc64/Kconfig
+++ b/arch/ppc64/Kconfig
@@ -279,17 +279,12 @@
        def_bool y
        depends on !NUMA
 
-config ARCH_DISCONTIGMEM_ENABLE
-	def_bool y
-	depends on SMP && PPC_PSERIES
-
-config ARCH_DISCONTIGMEM_DEFAULT
-	def_bool y
-	depends on ARCH_DISCONTIGMEM_ENABLE
-
 config ARCH_SPARSEMEM_ENABLE
 	def_bool y
-	depends on ARCH_DISCONTIGMEM_ENABLE
+
+config ARCH_SPARSEMEM_DEFAULT
+	def_bool y
+	depends on NUMA
 
 source "mm/Kconfig"
 
@@ -297,6 +292,10 @@
 	def_bool y
 	depends on NEED_MULTIPLE_NODES
 
+config ARCH_MEMORY_PROBE
+	def_bool y
+	depends on MEMORY_HOTPLUG
+
 # Some NUMA nodes have memory ranges that span
 # other nodes.  Even though a pfn is valid and
 # between a node's start and end pfns, it may not
diff --git a/arch/ppc64/boot/addRamDisk.c b/arch/ppc64/boot/addRamDisk.c
index 7f2c094..c02a999 100644
--- a/arch/ppc64/boot/addRamDisk.c
+++ b/arch/ppc64/boot/addRamDisk.c
@@ -5,11 +5,59 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <string.h>
+#include <elf.h>
 
 #define ElfHeaderSize  (64 * 1024)
 #define ElfPages  (ElfHeaderSize / 4096)
 #define KERNELBASE (0xc000000000000000)
+#define _ALIGN_UP(addr,size)	(((addr)+((size)-1))&(~((size)-1)))
 
+struct addr_range {
+	unsigned long long addr;
+	unsigned long memsize;
+	unsigned long offset;
+};
+
+static int check_elf64(void *p, int size, struct addr_range *r)
+{
+	Elf64_Ehdr *elf64 = p;
+	Elf64_Phdr *elf64ph;
+
+	if (elf64->e_ident[EI_MAG0] != ELFMAG0 ||
+	    elf64->e_ident[EI_MAG1] != ELFMAG1 ||
+	    elf64->e_ident[EI_MAG2] != ELFMAG2 ||
+	    elf64->e_ident[EI_MAG3] != ELFMAG3 ||
+	    elf64->e_ident[EI_CLASS] != ELFCLASS64 ||
+	    elf64->e_ident[EI_DATA] != ELFDATA2MSB ||
+	    elf64->e_type != ET_EXEC || elf64->e_machine != EM_PPC64)
+		return 0;
+
+	if ((elf64->e_phoff + sizeof(Elf64_Phdr)) > size)
+		return 0;
+
+	elf64ph = (Elf64_Phdr *) ((unsigned long)elf64 +
+				  (unsigned long)elf64->e_phoff);
+
+	r->memsize = (unsigned long)elf64ph->p_memsz;
+	r->offset = (unsigned long)elf64ph->p_offset;
+	r->addr = (unsigned long long)elf64ph->p_vaddr;
+
+#ifdef DEBUG
+	printf("PPC64 ELF file, ph:\n");
+	printf("p_type   0x%08x\n", elf64ph->p_type);
+	printf("p_flags  0x%08x\n", elf64ph->p_flags);
+	printf("p_offset 0x%016llx\n", elf64ph->p_offset);
+	printf("p_vaddr  0x%016llx\n", elf64ph->p_vaddr);
+	printf("p_paddr  0x%016llx\n", elf64ph->p_paddr);
+	printf("p_filesz 0x%016llx\n", elf64ph->p_filesz);
+	printf("p_memsz  0x%016llx\n", elf64ph->p_memsz);
+	printf("p_align  0x%016llx\n", elf64ph->p_align);
+	printf("... skipping 0x%08lx bytes of ELF header\n",
+	       (unsigned long)elf64ph->p_offset);
+#endif
+
+	return 64;
+}
 void get4k(FILE *file, char *buf )
 {
 	unsigned j;
@@ -34,97 +82,92 @@
 int main(int argc, char **argv)
 {
 	char inbuf[4096];
-	FILE *ramDisk = NULL;
-	FILE *sysmap = NULL;
-	FILE *inputVmlinux = NULL;
-	FILE *outputVmlinux = NULL;
-  
-	unsigned i = 0;
-	unsigned long ramFileLen = 0;
-	unsigned long ramLen = 0;
-	unsigned long roundR = 0;
-  
-	unsigned long sysmapFileLen = 0;
-	unsigned long sysmapLen = 0;
-	unsigned long sysmapPages = 0;
-	char* ptr_end = NULL; 
-	unsigned long offset_end = 0;
+	struct addr_range vmlinux;
+	FILE *ramDisk;
+	FILE *inputVmlinux;
+	FILE *outputVmlinux;
 
-	unsigned long kernelLen = 0;
-	unsigned long actualKernelLen = 0;
-	unsigned long round = 0;
-	unsigned long roundedKernelLen = 0;
-	unsigned long ramStartOffs = 0;
-	unsigned long ramPages = 0;
-	unsigned long roundedKernelPages = 0;
-	unsigned long hvReleaseData = 0;
+	char *rd_name, *lx_name, *out_name;
+
+	size_t i;
+	unsigned long ramFileLen;
+	unsigned long ramLen;
+	unsigned long roundR;
+	unsigned long offset_end;
+
+	unsigned long kernelLen;
+	unsigned long actualKernelLen;
+	unsigned long round;
+	unsigned long roundedKernelLen;
+	unsigned long ramStartOffs;
+	unsigned long ramPages;
+	unsigned long roundedKernelPages;
+	unsigned long hvReleaseData;
 	u_int32_t eyeCatcher = 0xc8a5d9c4;
-	unsigned long naca = 0;
-	unsigned long xRamDisk = 0;
-	unsigned long xRamDiskSize = 0;
-	long padPages = 0;
+	unsigned long naca;
+	unsigned long xRamDisk;
+	unsigned long xRamDiskSize;
+	long padPages;
   
   
 	if (argc < 2) {
 		fprintf(stderr, "Name of RAM disk file missing.\n");
 		exit(1);
 	}
+	rd_name = argv[1];
 
 	if (argc < 3) {
-		fprintf(stderr, "Name of System Map input file is missing.\n");
-		exit(1);
-	}
-  
-	if (argc < 4) {
 		fprintf(stderr, "Name of vmlinux file missing.\n");
 		exit(1);
 	}
+	lx_name = argv[2];
 
-	if (argc < 5) {
+	if (argc < 4) {
 		fprintf(stderr, "Name of vmlinux output file missing.\n");
 		exit(1);
 	}
+	out_name = argv[3];
 
 
-	ramDisk = fopen(argv[1], "r");
+	ramDisk = fopen(rd_name, "r");
 	if ( ! ramDisk ) {
-		fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", argv[1]);
+		fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", rd_name);
 		exit(1);
 	}
 
-	sysmap = fopen(argv[2], "r");
-	if ( ! sysmap ) {
-		fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[2]);
-		exit(1);
-	}
-  
-	inputVmlinux = fopen(argv[3], "r");
+	inputVmlinux = fopen(lx_name, "r");
 	if ( ! inputVmlinux ) {
-		fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[3]);
+		fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", lx_name);
 		exit(1);
 	}
   
-	outputVmlinux = fopen(argv[4], "w+");
+	outputVmlinux = fopen(out_name, "w+");
 	if ( ! outputVmlinux ) {
-		fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[4]);
+		fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", out_name);
 		exit(1);
 	}
-  
-  
-  
+
+	i = fread(inbuf, 1, sizeof(inbuf), inputVmlinux);
+	if (i != sizeof(inbuf)) {
+		fprintf(stderr, "can not read vmlinux file %s: %u\n", lx_name, i);
+		exit(1);
+	}
+
+	i = check_elf64(inbuf, sizeof(inbuf), &vmlinux);
+	if (i == 0) {
+		fprintf(stderr, "You must have a linux kernel specified as argv[2]\n");
+		exit(1);
+	}
+
 	/* Input Vmlinux file */
 	fseek(inputVmlinux, 0, SEEK_END);
 	kernelLen = ftell(inputVmlinux);
 	fseek(inputVmlinux, 0, SEEK_SET);
-	printf("kernel file size = %d\n", kernelLen);
-	if ( kernelLen == 0 ) {
-		fprintf(stderr, "You must have a linux kernel specified as argv[3]\n");
-		exit(1);
-	}
+	printf("kernel file size = %lu\n", kernelLen);
 
 	actualKernelLen = kernelLen - ElfHeaderSize;
 
-	printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen);
+	printf("actual kernel length (minus ELF header) = %lu\n", actualKernelLen);
 
 	round = actualKernelLen % 4096;
 	roundedKernelLen = actualKernelLen;
@@ -134,39 +177,7 @@
 	roundedKernelPages = roundedKernelLen / 4096;
 	printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages, roundedKernelPages);
 
-
-
-	/* Input System Map file */
-	/* (needs to be processed simply to determine if we need to add pad pages due to the static variables not being included in the vmlinux) */
-	fseek(sysmap, 0, SEEK_END);
-	sysmapFileLen = ftell(sysmap);
-	fseek(sysmap, 0, SEEK_SET);
-	printf("%s file size = %ld/0x%lx \n", argv[2], sysmapFileLen, sysmapFileLen);
-
-	sysmapLen = sysmapFileLen;
-
-	roundR = 4096 - (sysmapLen % 4096);
-	if (roundR) {
-		printf("Rounding System Map file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR);
-		sysmapLen += roundR;
-	}
-	printf("Rounded System Map size is %ld/0x%lx \n", sysmapLen, sysmapLen);
-  
-	/* Process the Sysmap file to determine where _end is */
-	sysmapPages = sysmapLen / 4096;
-	/* read the whole file line by line, expect that it doesn't fail */
-	while ( fgets(inbuf, 4096, sysmap) )  ;
-	/* search for _end in the last page of the system map */
-	ptr_end = strstr(inbuf, " _end");
-	if (!ptr_end) {
-		fprintf(stderr, "Unable to find _end in the sysmap file \n");
-		fprintf(stderr, "inbuf: \n");
-		fprintf(stderr, "%s \n", inbuf);
-		exit(1);
-	}
-	printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10);
-	/* convert address of _end in system map to hex offset. */
-	offset_end = (unsigned int)strtol(ptr_end-10, NULL, 16);
+	offset_end = _ALIGN_UP(vmlinux.memsize, 4096);
 	/* calc how many pages we need to insert between the vmlinux and the start of the ram disk */
 	padPages = offset_end/4096 - roundedKernelPages;
 
@@ -194,7 +205,7 @@
 	fseek(ramDisk, 0, SEEK_END);
 	ramFileLen = ftell(ramDisk);
 	fseek(ramDisk, 0, SEEK_SET);
-	printf("%s file size = %ld/0x%lx \n", argv[1], ramFileLen, ramFileLen);
+	printf("%s file size = %ld/0x%lx \n", rd_name, ramFileLen, ramFileLen);
 
 	ramLen = ramFileLen;
 
@@ -248,19 +259,19 @@
 	/* fseek to the hvReleaseData pointer */
 	fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET);
 	if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) {
-		death("Could not read hvReleaseData pointer\n", outputVmlinux, argv[4]);
+		death("Could not read hvReleaseData pointer\n", outputVmlinux, out_name);
 	}
 	hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
-	printf("hvReleaseData is at %08x\n", hvReleaseData);
+	printf("hvReleaseData is at %08lx\n", hvReleaseData);
 
 	/* fseek to the hvReleaseData */
 	fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET);
 	if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) {
-		death("Could not read hvReleaseData\n", outputVmlinux, argv[4]);
+		death("Could not read hvReleaseData\n", outputVmlinux, out_name);
 	}
 	/* Check hvReleaseData sanity */
 	if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
-		death("hvReleaseData is invalid\n", outputVmlinux, argv[4]);
+		death("hvReleaseData is invalid\n", outputVmlinux, out_name);
 	}
 	/* Get the naca pointer */
 	naca = ntohl(*((u_int32_t*) &inbuf[0x0C])) - KERNELBASE;
@@ -269,13 +280,13 @@
 	/* fseek to the naca */
 	fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
 	if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) {
-		death("Could not read naca\n", outputVmlinux, argv[4]);
+		death("Could not read naca\n", outputVmlinux, out_name);
 	}
 	xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c]));
 	xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14]));
 	/* Make sure a RAM disk isn't already present */
 	if ((xRamDisk != 0) || (xRamDiskSize != 0)) {
-		death("RAM disk is already attached to this kernel\n", outputVmlinux, argv[4]);
+		death("RAM disk is already attached to this kernel\n", outputVmlinux, out_name);
 	}
 	/* Fill in the values */
 	*((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
@@ -285,15 +296,15 @@
 	fflush(outputVmlinux);
 	fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
 	if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) {
-		death("Could not write naca\n", outputVmlinux, argv[4]);
+		death("Could not write naca\n", outputVmlinux, out_name);
 	}
-	printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08x\n",
+	printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08lx\n",
 	       ramPages, ramStartOffs);
 
 	/* Done */
 	fclose(outputVmlinux);
 	/* Set permission to executable */
-	chmod(argv[4], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
+	chmod(out_name, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
 
 	return 0;
 }
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
index c441aeb..dac4cc2 100644
--- a/arch/ppc64/kernel/Makefile
+++ b/arch/ppc64/kernel/Makefile
@@ -11,13 +11,10 @@
 
 endif
 
-obj-y               +=	irq.o idle.o dma.o \
-			align.o pacaData.o \
-			udbg.o ioctl32.o \
+obj-y               +=	idle.o dma.o \
+			align.o \
 			rtc.o \
-			cpu_setup_power4.o \
-			iommu.o sysfs.o vdso.o firmware.o
-obj-y += vdso32/ vdso64/
+			iommu.o
 
 pci-obj-$(CONFIG_PPC_MULTIPLATFORM)	+= pci_dn.o pci_direct_iommu.o
 
@@ -28,32 +25,19 @@
 obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o
 endif
 
-obj-$(CONFIG_PPC_PSERIES) += udbg_16550.o
-
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o
-obj-$(CONFIG_EEH)		+= eeh.o
-obj-$(CONFIG_PROC_FS)		+= proc_ppc64.o
 obj-$(CONFIG_MODULES)		+= module.o
 ifneq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
 endif
-obj-$(CONFIG_PPC_RTAS)		+= rtas_pci.o
-obj-$(CONFIG_SCANLOG)		+= scanlog.o
-obj-$(CONFIG_LPARCFG)		+= lparcfg.o
 obj-$(CONFIG_HVC_CONSOLE)	+= hvconsole.o
 ifneq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 endif
 obj-$(CONFIG_HVCS)		+= hvcserver.o
 
-obj-$(CONFIG_PPC_PMAC)		+= udbg_scc.o
-
-obj-$(CONFIG_PPC_MAPLE)		+= udbg_16550.o
-
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 
-CFLAGS_ioctl32.o += -Ifs/
-
 ifneq ($(CONFIG_PPC_MERGE),y)
 ifeq ($(CONFIG_PPC_ISERIES),y)
 arch/ppc64/kernel/head.o: arch/powerpc/kernel/lparmap.s
diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c
index bce9065..84ab5c1 100644
--- a/arch/ppc64/kernel/asm-offsets.c
+++ b/arch/ppc64/kernel/asm-offsets.c
@@ -74,7 +74,6 @@
 	DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size));
 	DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size));
 	DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page));
-	DEFINE(PLATFORM, offsetof(struct systemcfg, platform));
 	DEFINE(PLATFORM_LPAR, PLATFORM_LPAR);
 
 	/* paca */
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index 9e8050e..1c869ea 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -28,7 +28,6 @@
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
-#include <asm/systemcfg.h>
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/bug.h>
@@ -1701,21 +1700,9 @@
 	HMT_MEDIUM			/* Set thread priority to MEDIUM */
 
 	ld	r2,PACATOC(r13)
-	li	r6,0
-	stb	r6,PACAPROCENABLED(r13)
 
-#ifndef CONFIG_PPC_ISERIES
-	/* Initialize the page table pointer register. */
-	LOADADDR(r6,_SDR1)
-	ld	r6,0(r6)		/* get the value of _SDR1	 */
-	mtspr	SPRN_SDR1,r6			/* set the htab location	 */
-#endif
-	/* Initialize the first segment table (or SLB) entry		 */
-	ld	r3,PACASTABVIRT(r13)	/* get addr of segment table	 */
-BEGIN_FTR_SECTION
-	bl	.stab_initialize
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
-	bl	.slb_initialize
+	/* Do early setup for that CPU */
+	bl	.early_setup_secondary
 
 	/* Initialize the kernel stack.  Just a repeat for iSeries.	 */
 	LOADADDR(r3,current_set)
@@ -1724,37 +1711,6 @@
 	addi	r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
 	std	r1,PACAKSAVE(r13)
 
-	ld	r3,PACASTABREAL(r13)	/* get raddr of segment table	 */
-	ori	r4,r3,1			/* turn on valid bit		 */
-
-#ifdef CONFIG_PPC_ISERIES
-	li	r0,-1			/* hypervisor call */
-	li	r3,1
-	sldi	r3,r3,63		/* 0x8000000000000000 */
-	ori	r3,r3,4			/* 0x8000000000000004 */
-	sc				/* HvCall_setASR */
-#else
-	/* set the ASR */
-	ld	r3,systemcfg@got(r2)	/* r3 = ptr to systemcfg	 */
-	ld	r3,0(r3)
-	lwz	r3,PLATFORM(r3)		/* r3 = platform flags		 */
-	andi.	r3,r3,PLATFORM_LPAR	/* Test if bit 0 is set (LPAR bit) */
-	beq	98f			/* branch if result is 0  */
-	mfspr	r3,SPRN_PVR
-	srwi	r3,r3,16
-	cmpwi	r3,0x37			/* SStar  */
-	beq	97f
-	cmpwi	r3,0x36			/* IStar  */
-	beq	97f
-	cmpwi	r3,0x34			/* Pulsar */
-	bne	98f
-97:	li	r3,H_SET_ASR		/* hcall = H_SET_ASR */
-	HVSC				/* Invoking hcall */
-	b	99f
-98:					/* !(rpa hypervisor) || !(star)  */
-	mtasr	r4			/* set the stab location	 */
-99:
-#endif
 	li	r7,0
 	mtlr	r7
 
@@ -1896,40 +1852,6 @@
 	mr	r3,r31
  	bl	.early_setup
 
-	/* set the ASR */
-	ld	r3,PACASTABREAL(r13)
-	ori	r4,r3,1			/* turn on valid bit		 */
-	ld	r3,systemcfg@got(r2)	/* r3 = ptr to systemcfg */
-	ld	r3,0(r3)
-	lwz	r3,PLATFORM(r3)		/* r3 = platform flags */
-	andi.	r3,r3,PLATFORM_LPAR	/* Test if bit 0 is set (LPAR bit) */
-	beq	98f			/* branch if result is 0  */
-	mfspr	r3,SPRN_PVR
-	srwi	r3,r3,16
-	cmpwi	r3,0x37			/* SStar */
-	beq	97f
-	cmpwi	r3,0x36			/* IStar  */
-	beq	97f
-	cmpwi	r3,0x34			/* Pulsar */
-	bne	98f
-97:	li	r3,H_SET_ASR		/* hcall = H_SET_ASR */
-	HVSC				/* Invoking hcall */
-	b	99f
-98:					/* !(rpa hypervisor) || !(star) */
-	mtasr	r4			/* set the stab location	*/
-99:
-	/* Set SDR1 (hash table pointer) */
-	ld	r3,systemcfg@got(r2)	/* r3 = ptr to systemcfg */
-	ld	r3,0(r3)
-	lwz	r3,PLATFORM(r3)		/* r3 = platform flags */
-	/* Test if bit 0 is set (LPAR bit) */
-	andi.	r3,r3,PLATFORM_LPAR
-	bne	98f			/* branch if result is !0  */
-	LOADADDR(r6,_SDR1)		/* Only if NOT LPAR */
-	sub	r6,r6,r26
-	ld	r6,0(r6)		/* get the value of _SDR1 */
-	mtspr	SPRN_SDR1,r6			/* set the htab location  */
-98: 
 	LOADADDR(r3,.start_here_common)
 	SET_REG_TO_CONST(r4, MSR_KERNEL)
 	mtspr	SPRN_SRR0,r3
diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
index 8fec274..b879d30 100644
--- a/arch/ppc64/kernel/idle.c
+++ b/arch/ppc64/kernel/idle.c
@@ -26,7 +26,6 @@
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/time.h>
-#include <asm/systemcfg.h>
 #include <asm/machdep.h>
 #include <asm/smp.h>
 
@@ -34,15 +33,11 @@
 
 void default_idle(void)
 {
-	long oldval;
 	unsigned int cpu = smp_processor_id();
+	set_thread_flag(TIF_POLLING_NRFLAG);
 
 	while (1) {
-		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
-		if (!oldval) {
-			set_thread_flag(TIF_POLLING_NRFLAG);
-
+		if (!need_resched()) {
 			while (!need_resched() && !cpu_is_offline(cpu)) {
 				ppc64_runlatch_off();
 
@@ -55,13 +50,12 @@
 			}
 
 			HMT_medium();
-			clear_thread_flag(TIF_POLLING_NRFLAG);
-		} else {
-			set_need_resched();
 		}
 
 		ppc64_runlatch_on();
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
 			cpu_die();
 	}
@@ -77,7 +71,9 @@
 
 		if (need_resched()) {
 			ppc64_runlatch_on();
+			preempt_enable_no_resched();
 			schedule();
+			preempt_disable();
 		}
 
 		if (cpu_is_offline(smp_processor_id()) &&
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index 914632e..5e089de 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -78,12 +78,12 @@
 	mtlr	r0
 	blr
 
-_GLOBAL(call_handle_IRQ_event)
+_GLOBAL(call___do_IRQ)
 	mflr	r0
 	std	r0,16(r1)
-	stdu	r1,THREAD_SIZE-112(r6)
-	mr	r1,r6
-	bl	.handle_IRQ_event
+	stdu	r1,THREAD_SIZE-112(r5)
+	mr	r1,r5
+	bl	.__do_IRQ
 	ld	r1,0(r1)
 	ld	r0,16(r1)
 	mtlr	r0
@@ -186,7 +186,8 @@
 	bdnz	2b
 	isync
 	blr
-	.previous .text
+
+	.text
 /*
  * Like above, but only do the D-cache.
  *
diff --git a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c
index 4fb1a9f..c0fcd29 100644
--- a/arch/ppc64/kernel/nvram.c
+++ b/arch/ppc64/kernel/nvram.c
@@ -31,7 +31,6 @@
 #include <asm/rtas.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
-#include <asm/systemcfg.h>
 
 #undef DEBUG_NVRAM
 
@@ -167,7 +166,7 @@
 	case IOC_NVRAM_GET_OFFSET: {
 		int part, offset;
 
-		if (systemcfg->platform != PLATFORM_POWERMAC)
+		if (_machine != PLATFORM_POWERMAC)
 			return -EINVAL;
 		if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
 			return -EFAULT;
@@ -450,7 +449,7 @@
 	 * in our nvram, as Apple defined partitions use pretty much
 	 * all of the space
 	 */
-	if (systemcfg->platform == PLATFORM_POWERMAC)
+	if (_machine == PLATFORM_POWERMAC)
 		return -ENOSPC;
 
 	/* see if we have an OS partition that meets our needs.
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
index 30247ff..3cef1b8 100644
--- a/arch/ppc64/kernel/pci.c
+++ b/arch/ppc64/kernel/pci.c
@@ -548,6 +548,11 @@
 	if (ppc64_isabridge_dev != NULL)
 		printk("ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
 
+#ifdef CONFIG_PPC_MULTIPLATFORM
+	/* map in PCI I/O space */
+	phbs_remap_io();
+#endif
+
 	printk("PCI: Probing PCI hardware done\n");
 
 	return 0;
@@ -1277,12 +1282,9 @@
 	 * G5 machines... So when something asks for bus 0 io base
 	 * (bus 0 is HT root), we return the AGP one instead.
 	 */
-#ifdef CONFIG_PPC_PMAC
-	if (systemcfg->platform == PLATFORM_POWERMAC &&
-	    machine_is_compatible("MacRISC4"))
+	if (machine_is_compatible("MacRISC4"))
 		if (in_bus == 0)
 			in_bus = 0xf0;
-#endif /* CONFIG_PPC_PMAC */
 
 	/* That syscall isn't quite compatible with PCI domains, but it's
 	 * used on pre-domains setup. We return the first match
diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c
index 1a443a7..12c4c9e 100644
--- a/arch/ppc64/kernel/pci_dn.c
+++ b/arch/ppc64/kernel/pci_dn.c
@@ -43,7 +43,7 @@
 	u32 *regs;
 	struct pci_dn *pdn;
 
-	if (phb->is_dynamic)
+	if (mem_init_done)
 		pdn = kmalloc(sizeof(*pdn), GFP_KERNEL);
 	else
 		pdn = alloc_bootmem(sizeof(*pdn));
@@ -120,6 +120,14 @@
 	return NULL;
 }
 
+/** 
+ * pci_devs_phb_init_dynamic - setup pci devices under this PHB
+ * phb: pci-to-host bridge (top-level bridge connecting to cpu)
+ *
+ * This routine is called both during boot, (before the memory
+ * subsystem is set up, before kmalloc is valid) and during the 
+ * dynamic lpar operation of adding a PHB to a running system.
+ */
 void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
 {
 	struct device_node * dn = (struct device_node *) phb->arch_data;
@@ -201,9 +209,14 @@
 	.notifier_call = pci_dn_reconfig_notifier,
 };
 
-/*
- * Actually initialize the phbs.
- * The buswalk on this phb has not happened yet.
+/** 
+ * pci_devs_phb_init - Initialize phbs and pci devs under them.
+ * 
+ * This routine walks over all phb's (pci-host bridges) on the
+ * system, and sets up assorted pci-related structures 
+ * (including pci info in the device node structs) for each
+ * pci device found underneath.  This routine runs once,
+ * early in the boot sequence.
  */
 void __init pci_devs_phb_init(void)
 {
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index 3402fbe..fbad2c3 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -318,7 +318,7 @@
 		}
 
 		/* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
-		if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) {
+		if (_machine == PLATFORM_POWERMAC && ic && ic->parent) {
 			char *name = get_property(ic->parent, "name", NULL);
 			if (name && !strcmp(name, "u3"))
 				np->intrs[intrcount].line += 128;
@@ -1065,7 +1065,7 @@
 	prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL);
 	if (prop == NULL)
 		return 0;
-	systemcfg->platform = *prop;
+	_machine = *prop;
 
 	/* check if iommu is forced on or off */
 	if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
@@ -1230,11 +1230,8 @@
 	of_scan_flat_dt(early_init_dt_scan_memory, NULL);
 	lmb_enforce_memory_limit(memory_limit);
 	lmb_analyze();
-	systemcfg->physicalMemorySize = lmb_phys_mem_size();
 	lmb_reserve(0, __pa(klimit));
 
-	DBG("Phys. mem: %lx\n", systemcfg->physicalMemorySize);
-
 	/* Reserve LMB regions used by kernel, initrd, dt, etc... */
 	early_reserve_mem();
 
@@ -1753,7 +1750,7 @@
 	/* We don't support that function on PowerMac, at least
 	 * not yet
 	 */
-	if (systemcfg->platform == PLATFORM_POWERMAC)
+	if (_machine == PLATFORM_POWERMAC)
 		return -ENODEV;
 
 	/* fix up new node's linux_phandle field */
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c
index e4c880da..6375f40 100644
--- a/arch/ppc64/kernel/prom_init.c
+++ b/arch/ppc64/kernel/prom_init.c
@@ -1934,7 +1934,8 @@
 	/*
 	 * On pSeries, inform the firmware about our capabilities
 	 */
-	if (RELOC(of_platform) & PLATFORM_PSERIES)
+	if (RELOC(of_platform) == PLATFORM_PSERIES ||
+	    RELOC(of_platform) == PLATFORM_PSERIES_LPAR)
 		prom_send_capabilities();
 
 	/*
diff --git a/arch/ppc64/kernel/vdso.c b/arch/ppc64/kernel/vdso.c
index 4aacf52..1bbacac 100644
--- a/arch/ppc64/kernel/vdso.c
+++ b/arch/ppc64/kernel/vdso.c
@@ -34,6 +34,7 @@
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
+#include <asm/systemcfg.h>
 #include <asm/vdso.h>
 
 #undef DEBUG
@@ -179,7 +180,7 @@
 	 * Last page is systemcfg.
 	 */
 	if ((vma->vm_end - address) <= PAGE_SIZE)
-		pg = virt_to_page(systemcfg);
+		pg = virt_to_page(_systemcfg);
 	else
 		pg = virt_to_page(vbase + offset);
 
@@ -604,7 +605,7 @@
 		get_page(pg);
 	}
 
-	get_page(virt_to_page(systemcfg));
+	get_page(virt_to_page(_systemcfg));
 }
 
 int in_gate_area_no_task(unsigned long addr)
diff --git a/arch/ppc64/kernel/vdso32/gettimeofday.S b/arch/ppc64/kernel/vdso32/gettimeofday.S
deleted file mode 100644
index e243c1d..0000000
--- a/arch/ppc64/kernel/vdso32/gettimeofday.S
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Userland implementation of gettimeofday() for 32 bits processes in a
- * ppc64 kernel for use in the vDSO
- *
- * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/ppc_asm.h>
-#include <asm/vdso.h>
-#include <asm/asm-offsets.h>
-#include <asm/unistd.h>
-
-	.text
-/*
- * Exact prototype of gettimeofday
- *
- * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
- *
- */
-V_FUNCTION_BEGIN(__kernel_gettimeofday)
-  .cfi_startproc
-	mflr	r12
-  .cfi_register lr,r12
-
-	mr	r10,r3			/* r10 saves tv */
-	mr	r11,r4			/* r11 saves tz */
-	bl	__get_datapage@local	/* get data page */
-	mr	r9, r3			/* datapage ptr in r9 */
-	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
-	bne-	2f			/* out of line -> do syscall */
-
-	/* seconds are xsec >> 20 */
-	rlwinm	r5,r4,12,20,31
-	rlwimi	r5,r3,12,0,19
-	stw	r5,TVAL32_TV_SEC(r10)
-
-	/* get remaining xsec and convert to usec. we scale
-	 * up remaining xsec by 12 bits and get the top 32 bits
-	 * of the multiplication
-	 */
-	rlwinm	r5,r4,12,0,19
-	lis	r6,1000000@h
-	ori	r6,r6,1000000@l
-	mulhwu	r5,r5,r6
-	stw	r5,TVAL32_TV_USEC(r10)
-
-	cmpli	cr0,r11,0		/* check if tz is NULL */
-	beq	1f
-	lwz	r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */
-	lwz	r5,CFG_TZ_DSTTIME(r9)
-	stw	r4,TZONE_TZ_MINWEST(r11)
-	stw	r5,TZONE_TZ_DSTTIME(r11)
-
-1:	mtlr	r12
-	li	r3,0
-	blr
-
-2:	mr	r3,r10
-	mr	r4,r11
-	li	r0,__NR_gettimeofday
-	sc
-	b	1b
-  .cfi_endproc
-V_FUNCTION_END(__kernel_gettimeofday)
-
-/*
- * This is the core of gettimeofday(), it returns the xsec
- * value in r3 & r4 and expects the datapage ptr (non clobbered)
- * in r9. clobbers r0,r4,r5,r6,r7,r8
-*/
-__do_get_xsec:
-  .cfi_startproc
-	/* Check for update count & load values. We use the low
-	 * order 32 bits of the update count
-	 */
-1:	lwz	r8,(CFG_TB_UPDATE_COUNT+4)(r9)
-	andi.	r0,r8,1			/* pending update ? loop */
-	bne-	1b
-	xor	r0,r8,r8		/* create dependency */
-	add	r9,r9,r0
-
-	/* Load orig stamp (offset to TB) */
-	lwz	r5,CFG_TB_ORIG_STAMP(r9)
-	lwz	r6,(CFG_TB_ORIG_STAMP+4)(r9)
-
-	/* Get a stable TB value */
-2:	mftbu	r3
-	mftbl	r4
-	mftbu	r0
-	cmpl	cr0,r3,r0
-	bne-	2b
-
-	/* Substract tb orig stamp. If the high part is non-zero, we jump to the
-	 * slow path which call the syscall. If it's ok, then we have our 32 bits
-	 * tb_ticks value in r7
-	 */
-	subfc	r7,r6,r4
-	subfe.	r0,r5,r3
-	bne-	3f
-
-	/* Load scale factor & do multiplication */
-	lwz	r5,CFG_TB_TO_XS(r9)	/* load values */
-	lwz	r6,(CFG_TB_TO_XS+4)(r9)
-	mulhwu	r4,r7,r5
-	mulhwu	r6,r7,r6
-	mullw	r0,r7,r5
-	addc	r6,r6,r0
-
-	/* At this point, we have the scaled xsec value in r4 + XER:CA
-	 * we load & add the stamp since epoch
-	 */
-	lwz	r5,CFG_STAMP_XSEC(r9)
-	lwz	r6,(CFG_STAMP_XSEC+4)(r9)
-	adde	r4,r4,r6
-	addze	r3,r5
-
-	/* We now have our result in r3,r4. We create a fake dependency
-	 * on that result and re-check the counter
-	 */
-	xor	r0,r4,r4
-	add	r9,r9,r0
-	lwz	r0,(CFG_TB_UPDATE_COUNT+4)(r9)
-        cmpl    cr0,r8,r0		/* check if updated */
-	bne-	1b
-
-	/* Warning ! The caller expects CR:EQ to be set to indicate a
-	 * successful calculation (so it won't fallback to the syscall
-	 * method). We have overriden that CR bit in the counter check,
-	 * but fortunately, the loop exit condition _is_ CR:EQ set, so
-	 * we can exit safely here. If you change this code, be careful
-	 * of that side effect.
-	 */
-3:	blr
-  .cfi_endproc
diff --git a/arch/ppc64/kernel/vdso64/gettimeofday.S b/arch/ppc64/kernel/vdso64/gettimeofday.S
deleted file mode 100644
index f6df802..0000000
--- a/arch/ppc64/kernel/vdso64/gettimeofday.S
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Userland implementation of gettimeofday() for 64 bits processes in a
- * ppc64 kernel for use in the vDSO
- *
- * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
- *                    IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/ppc_asm.h>
-#include <asm/vdso.h>
-#include <asm/asm-offsets.h>
-
-	.text
-/*
- * Exact prototype of gettimeofday
- *
- * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
- *
- */
-V_FUNCTION_BEGIN(__kernel_gettimeofday)
-  .cfi_startproc
-	mflr	r12
-  .cfi_register lr,r12
-
-	mr	r11,r3			/* r11 holds tv */
-	mr	r10,r4			/* r10 holds tz */
-	bl	V_LOCAL_FUNC(__get_datapage)		/* get data page */
-	bl	V_LOCAL_FUNC(__do_get_xsec)		/* get xsec from tb & kernel */
-	lis     r7,15			/* r7 = 1000000 = USEC_PER_SEC */
-	ori     r7,r7,16960
-	rldicl  r5,r4,44,20		/* r5 = sec = xsec / XSEC_PER_SEC */
-	rldicr  r6,r5,20,43		/* r6 = sec * XSEC_PER_SEC */
-	std	r5,TVAL64_TV_SEC(r11)	/* store sec in tv */
-	subf	r0,r6,r4		/* r0 = xsec = (xsec - r6) */
-	mulld   r0,r0,r7		/* usec = (xsec * USEC_PER_SEC) / XSEC_PER_SEC */
-	rldicl  r0,r0,44,20
-	cmpldi	cr0,r10,0		/* check if tz is NULL */
-	std	r0,TVAL64_TV_USEC(r11)	/* store usec in tv */
-	beq	1f
-	lwz	r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */
-	lwz	r5,CFG_TZ_DSTTIME(r3)
-	stw	r4,TZONE_TZ_MINWEST(r10)
-	stw	r5,TZONE_TZ_DSTTIME(r10)
-1:	mtlr	r12
-	li	r3,0			/* always success */
-	blr
-  .cfi_endproc
-V_FUNCTION_END(__kernel_gettimeofday)
-
-
-/*
- * This is the core of gettimeofday(), it returns the xsec
- * value in r4 and expects the datapage ptr (non clobbered)
- * in r3. clobbers r0,r4,r5,r6,r7,r8
-*/
-V_FUNCTION_BEGIN(__do_get_xsec)
-  .cfi_startproc
-	/* check for update count & load values */
-1:	ld	r7,CFG_TB_UPDATE_COUNT(r3)
-	andi.	r0,r4,1			/* pending update ? loop */
-	bne-	1b
-	xor	r0,r4,r4		/* create dependency */
-	add	r3,r3,r0
-
-	/* Get TB & offset it */
-	mftb	r8
-	ld	r9,CFG_TB_ORIG_STAMP(r3)
-	subf	r8,r9,r8
-
-	/* Scale result */
-	ld	r5,CFG_TB_TO_XS(r3)
-	mulhdu	r8,r8,r5
-
-	/* Add stamp since epoch */
-	ld	r6,CFG_STAMP_XSEC(r3)
-	add	r4,r6,r8
-
-	xor	r0,r4,r4
-	add	r3,r3,r0
-	ld	r0,CFG_TB_UPDATE_COUNT(r3)
-        cmpld   cr0,r0,r7		/* check if updated */
-	bne-	1b
-	blr
-  .cfi_endproc
-V_FUNCTION_END(__do_get_xsec)
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index c9f2f60..dee6ab54 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -592,12 +592,15 @@
  */
 void appldata_unregister_ops(struct appldata_ops *ops)
 {
+	void *table;
 	spin_lock(&appldata_ops_lock);
-	unregister_sysctl_table(ops->sysctl_header);
 	list_del(&ops->list);
-	kfree(ops->ctl_table);
+	/* at that point any incoming access will fail */
+	table = ops->ctl_table;
 	ops->ctl_table = NULL;
 	spin_unlock(&appldata_ops_lock);
+	unregister_sysctl_table(ops->sysctl_header);
+	kfree(table);
 	P_INFO("%s-ops unregistered!\n", ops->name);
 }
 /********************** module-ops management <END> **************************/
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index bc59282..896d39d 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -486,7 +486,7 @@
  * - goto next entry in p_info
  */
 
-extern inline int
+static inline int
 debug_next_entry(file_private_info_t *p_info)
 {
 	debug_info_t *id;
@@ -800,7 +800,7 @@
  * - set active entry to next in the ring buffer
  */
 
-extern inline void
+static inline void
 proceed_active_entry(debug_info_t * id)
 {
 	if ((id->active_entries[id->active_area] += id->entry_size)
@@ -817,7 +817,7 @@
  * - set active area to next in the ring buffer
  */
 
-extern inline void
+static inline void
 proceed_active_area(debug_info_t * id)
 {
 	id->active_area++;
@@ -828,7 +828,7 @@
  * get_active_entry:
  */
 
-extern inline debug_entry_t*
+static inline debug_entry_t*
 get_active_entry(debug_info_t * id)
 {
 	return (debug_entry_t *) (((char *) id->areas[id->active_area]
@@ -841,7 +841,7 @@
  * - set timestamp, caller address, cpu number etc.
  */
 
-extern inline void
+static inline void
 debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
 			int exception)
 {
@@ -971,7 +971,7 @@
  * counts arguments in format string for sprintf view
  */
 
-extern inline int
+static inline int
 debug_count_numargs(char *string)
 {
 	int numargs=0;
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 9f3dff6..78b64fe5 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -99,15 +99,15 @@
 {
 	int cpu, rc;
 
-	local_irq_disable();
-        if (need_resched()) {
-		local_irq_enable();
-                schedule();
-                return;
-        }
-
 	/* CPU is going idle. */
 	cpu = smp_processor_id();
+
+	local_irq_disable();
+	if (need_resched()) {
+		local_irq_enable();
+		return;
+	}
+
 	rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu);
 	if (rc != NOTIFY_OK && rc != NOTIFY_DONE)
 		BUG();
@@ -120,7 +120,7 @@
 	__ctl_set_bit(8, 15);
 
 #ifdef CONFIG_HOTPLUG_CPU
-	if (cpu_is_offline(smp_processor_id()))
+	if (cpu_is_offline(cpu))
 		cpu_die();
 #endif
 
@@ -139,8 +139,14 @@
 
 void cpu_idle(void)
 {
-	for (;;)
-		default_idle();
+	for (;;) {
+		while (!need_resched())
+			default_idle();
+
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+	}
 }
 
 void show_regs(struct pt_regs *regs)
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index e13c87b..5856b3f 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -533,6 +533,7 @@
 {
         /* Setup the cpu */
         cpu_init();
+	preempt_disable();
         /* init per CPU timer */
         init_cpu_timer();
 #ifdef CONFIG_VIRT_TIMER
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 64e32da..fb2607c 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -160,7 +160,7 @@
  *   11       Page translation     ->  Not present       (nullification)
  *   3b       Region third trans.  ->  Not present       (nullification)
  */
-extern inline void
+static inline void
 do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
 {
         struct task_struct *tsk;
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 6dce9d0..fd4f240 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -51,28 +51,24 @@
 
 EXPORT_SYMBOL(enable_hlt);
 
-void default_idle(void)
+void cpu_idle(void)
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
 		if (hlt_counter) {
-			while (1)
-				if (need_resched())
-					break;
+			while (!need_resched())
+				cpu_relax();
 		} else {
 			while (!need_resched())
 				cpu_sleep();
 		}
 
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
-void cpu_idle(void)
-{
-	default_idle();
-}
-
 void machine_restart(char * __unused)
 {
 	/* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 5ecefc0..59e49b1 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -112,7 +112,9 @@
 
 int start_secondary(void *unused)
 {
-	unsigned int cpu = smp_processor_id();
+	unsigned int cpu;
+
+	cpu = smp_processor_id();
 
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
@@ -120,6 +122,7 @@
 	smp_store_cpu_info(cpu);
 
 	__smp_slave_init(cpu);
+	preempt_disable();
 	per_cpu_trap_init();
 	
 	atomic_inc(&cpus_booted);
diff --git a/arch/sh64/kernel/process.c b/arch/sh64/kernel/process.c
index efde41c..b95d041 100644
--- a/arch/sh64/kernel/process.c
+++ b/arch/sh64/kernel/process.c
@@ -307,23 +307,19 @@
 
 static inline void hlt(void)
 {
-	if (hlt_counter)
-		return;
-
 	__asm__ __volatile__ ("sleep" : : : "memory");
 }
 
 /*
  * The idle loop on a uniprocessor SH..
  */
-void default_idle(void)
+void cpu_idle(void)
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
 		if (hlt_counter) {
-			while (1)
-				if (need_resched())
-					break;
+			while (!need_resched())
+				cpu_relax();
 		} else {
 			local_irq_disable();
 			while (!need_resched()) {
@@ -334,13 +330,11 @@
 			}
 			local_irq_enable();
 		}
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
-}
 
-void cpu_idle(void)
-{
-	default_idle();
 }
 
 void machine_restart(char * __unused)
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
index 6a4ebc6..d7bfc61 100644
--- a/arch/sparc/kernel/cpu.c
+++ b/arch/sparc/kernel/cpu.c
@@ -75,7 +75,7 @@
   { 9, 3, "Fujitsu or Weitek on-chip FPU"},
 };
 
-#define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
+#define NSPARCFPU  ARRAY_SIZE(linux_sparc_fpu)
 
 struct cpu_iu_info linux_sparc_chips[] = {
   /* Sun4/100, 4/200, SLC */
@@ -120,7 +120,7 @@
   { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
 };
 
-#define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
+#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)
 
 char *sparc_cpu_type;
 char *sparc_fpu_type;
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 25e31d5..cccfc12 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -143,7 +143,7 @@
  * as several PROMs may be installed on the same physical board.
  */
 #define SN2L_INIT(name, map)	\
-  { name, map, sizeof(map)/sizeof(struct pcic_ca2irq) }
+  { name, map, ARRAY_SIZE(map) }
 
 static struct pcic_sn2list pcic_known_sysnames[] = {
 	SN2L_INIT("SUNW,JavaEngine1", pcic_i_je1a),	/* JE1, PROM 2.32 */
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 29e72b5..ea86474 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -67,13 +67,6 @@
 struct task_struct *last_task_used_math = NULL;
 struct thread_info *current_set[NR_CPUS];
 
-/*
- * default_idle is new in 2.5. XXX Review, currently stolen from sparc64.
- */
-void default_idle(void)
-{
-}
-
 #ifndef CONFIG_SMP
 
 #define SUN4C_FAULT_HIGH 100
@@ -92,12 +85,11 @@
 			static unsigned long fps;
 			unsigned long now;
 			unsigned long faults;
-			unsigned long flags;
 
 			extern unsigned long sun4c_kernel_faults;
 			extern void sun4c_grow_kernel_ring(void);
 
-			local_irq_save(flags);
+			local_irq_disable();
 			now = jiffies;
 			count -= (now - last_jiffies);
 			last_jiffies = now;
@@ -113,14 +105,19 @@
 					sun4c_grow_kernel_ring();
 				}
 			}
-			local_irq_restore(flags);
+			local_irq_enable();
 		}
 
-		while((!need_resched()) && pm_idle) {
-			(*pm_idle)();
+		if (pm_idle) {
+			while (!need_resched())
+				(*pm_idle)();
+		} else {
+			while (!need_resched())
+				cpu_relax();
 		}
-
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 		check_pgt_cache();
 	}
 }
@@ -130,13 +127,15 @@
 /* This is being executed in task 0 'user space'. */
 void cpu_idle(void)
 {
+        set_thread_flag(TIF_POLLING_NRFLAG);
 	/* endless idle loop with no priority at all */
 	while(1) {
-		if(need_resched()) {
-			schedule();
-			check_pgt_cache();
-		}
-		barrier(); /* or else gcc optimizes... */
+		while (!need_resched())
+			cpu_relax();
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+		check_pgt_cache();
 	}
 }
 
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 2bbd53f..9eeed33 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -33,8 +33,6 @@
 #include <asm/kdebug.h>
 #include <asm/uaccess.h>
 
-#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
-
 extern int prom_node_root;
 
 /* At boot time we determine these two values necessary for setting
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 77ef5df..00eed88 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -43,7 +43,7 @@
   { 0x3e, 0x22, 0, "UltraSparc IIIi+ integrated FPU"},
 };
 
-#define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
+#define NSPARCFPU  ARRAY_SIZE(linux_sparc_fpu)
 
 struct cpu_iu_info linux_sparc_chips[] = {
   { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
@@ -59,7 +59,7 @@
   { 0x3e, 0x22, "TI UltraSparc IIIi+ (Serrano)"},
 };
 
-#define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
+#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)
 
 char *sparc_cpu_type = "cpu-oops";
 char *sparc_fpu_type = "fpu-oops";
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 92e2630..e622143 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -92,10 +92,8 @@
 	return sys_ioctl (fd, FBIOSCURSOR, (unsigned long)p);
 }
 
-typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
-
 #define COMPATIBLE_IOCTL(cmd)		HANDLE_IOCTL((cmd),sys_ioctl)
-#define HANDLE_IOCTL(cmd,handler)	{ (cmd), (ioctl32_handler_t)(handler), NULL },
+#define HANDLE_IOCTL(cmd,handler)	{ (cmd), (ioctl_trans_handler_t)(handler), NULL },
 #define IOCTL_TABLE_START \
 	struct ioctl_trans ioctl_start[] = {
 #define IOCTL_TABLE_END \
@@ -116,8 +114,6 @@
 COMPATIBLE_IOCTL(FBIOGCURMAX)
 /* Little k */
 /* Little v, the video4linux ioctls */
-COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
-COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
 /* And these ioctls need translation */
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
 HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap)
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 7d10b03..02f9dec 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -74,7 +74,9 @@
 		while (!need_resched())
 			barrier();
 
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 		check_pgt_cache();
 	}
 }
@@ -83,21 +85,31 @@
 
 /*
  * the idle loop on a UltraMultiPenguin...
+ *
+ * TIF_POLLING_NRFLAG is set because we do not sleep the cpu
+ * inside of the idler task, so an interrupt is not needed
+ * to get a clean fast response.
+ *
+ * XXX Reverify this assumption... -DaveM
+ *
+ * Addendum: We do want it to do something for the signal
+ *           delivery case, we detect that by just seeing
+ *           if we are trying to send this to an idler or not.
  */
-#define idle_me_harder()	(cpu_data(smp_processor_id()).idle_volume += 1)
-#define unidle_me()		(cpu_data(smp_processor_id()).idle_volume = 0)
 void cpu_idle(void)
 {
+	cpuinfo_sparc *cpuinfo = &local_cpu_data();
 	set_thread_flag(TIF_POLLING_NRFLAG);
+
 	while(1) {
 		if (need_resched()) {
-			unidle_me();
-			clear_thread_flag(TIF_POLLING_NRFLAG);
+			cpuinfo->idle_volume = 0;
+			preempt_enable_no_resched();
 			schedule();
-			set_thread_flag(TIF_POLLING_NRFLAG);
+			preempt_disable();
 			check_pgt_cache();
 		}
-		idle_me_harder();
+		cpuinfo->idle_volume++;
 
 		/* The store ordering is so that IRQ handlers on
 		 * other cpus see our increasing idleness for the buddy
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index e09ddf9..96b8250 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -790,7 +790,7 @@
 
 #undef bogon
 
-#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
+#define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets)
 
 /* Convert Interrupt Mapping register pointer to associated
  * Interrupt Clear register pointer, SYSIO specific version.
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index bf1849d..4818053 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -587,6 +587,8 @@
 unsigned int dcache_parity_tl1_occurred;
 unsigned int icache_parity_tl1_occurred;
 
+static int ncpus_probed;
+
 static int show_cpuinfo(struct seq_file *m, void *__unused)
 {
 	seq_printf(m, 
@@ -595,8 +597,8 @@
 		   "promlib\t\t: Version 3 Revision %d\n"
 		   "prom\t\t: %d.%d.%d\n"
 		   "type\t\t: sun4u\n"
-		   "ncpus probed\t: %ld\n"
-		   "ncpus active\t: %ld\n"
+		   "ncpus probed\t: %d\n"
+		   "ncpus active\t: %d\n"
 		   "D$ parity tl1\t: %u\n"
 		   "I$ parity tl1\t: %u\n"
 #ifndef CONFIG_SMP
@@ -610,8 +612,8 @@
 		   prom_prev >> 16,
 		   (prom_prev >> 8) & 0xff,
 		   prom_prev & 0xff,
-		   (long)num_possible_cpus(),
-		   (long)num_online_cpus(),
+		   ncpus_probed,
+		   num_online_cpus(),
 		   dcache_parity_tl1_occurred,
 		   icache_parity_tl1_occurred
 #ifndef CONFIG_SMP
@@ -677,6 +679,15 @@
 	int i, err;
 
 	err = -ENOMEM;
+
+	/* Count the number of physically present processors in
+	 * the machine, even on uniprocessor, so that /proc/cpuinfo
+	 * output is consistent with 2.4.x
+	 */
+	ncpus_probed = 0;
+	while (!cpu_find_by_instance(ncpus_probed, NULL, NULL))
+		ncpus_probed++;
+
 	for (i = 0; i < NR_CPUS; i++) {
 		if (cpu_possible(i)) {
 			struct cpu *p = kmalloc(sizeof(*p), GFP_KERNEL);
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 5d90ee9..6efc03df 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -39,7 +39,6 @@
 #include <asm/starfire.h>
 #include <asm/tlb.h>
 
-extern int linux_num_cpus;
 extern void calibrate_delay(void);
 
 /* Please don't make this stuff initdata!!!  --DaveM */
@@ -168,6 +167,9 @@
 		rmb();
 
 	cpu_set(cpuid, cpu_online_map);
+
+	/* idle thread is expected to have preempt disabled */
+	preempt_disable();
 }
 
 void cpu_panic(void)
@@ -1149,20 +1151,9 @@
 	       (bogosum/(5000/HZ))%100);
 }
 
-/* This needn't do anything as we do not sleep the cpu
- * inside of the idler task, so an interrupt is not needed
- * to get a clean fast response.
- *
- * XXX Reverify this assumption... -DaveM
- *
- * Addendum: We do want it to do something for the signal
- *           delivery case, we detect that by just seeing
- *           if we are trying to send this to an idler or not.
- */
 void smp_send_reschedule(int cpu)
 {
-	if (cpu_data(cpu).idle_volume == 0)
-		smp_receive_signal(cpu);
+	smp_receive_signal(cpu);
 }
 
 /* This is a nop because we capture all other cpus
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 31fbc67..6f0539a 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -30,8 +30,6 @@
 #include <asm/sections.h>
 #include <asm/kdebug.h>
 
-#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
-
 /*
  * To debug kernel to catch accesses to certain virtual/physical addresses.
  * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
@@ -109,7 +107,7 @@
  * this. Additionally, to prevent kswapd from ripping ptes from
  * under us, raise interrupts around the time that we look at the
  * pte, kswapd will have to wait to get his smp ipi response from
- * us. This saves us having to get page_table_lock.
+ * us. vmtruncate likewise. This saves us having to get pte lock.
  */
 static unsigned int get_user_insn(unsigned long tpc)
 {
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index fe865d9..84c73a3 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -243,34 +243,18 @@
 	return err;
 }
 
-static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static void uml_net_get_drvinfo(struct net_device *dev,
+				struct ethtool_drvinfo *info)
 {
-	static const struct ethtool_drvinfo info = {
-		.cmd     = ETHTOOL_GDRVINFO,
-		.driver  = DRIVER_NAME,
-		.version = "42",
-	};
-	void *useraddr;
-	u32 ethcmd;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		useraddr = ifr->ifr_data;
-		if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-			return -EFAULT;
-		switch (ethcmd) {
-		case ETHTOOL_GDRVINFO:
-			if (copy_to_user(useraddr, &info, sizeof(info)))
-				return -EFAULT;
-			return 0;
-		default:
-			return -EOPNOTSUPP;
-		}
-	default:
-		return -EINVAL;
-	}
+	strcpy(info->driver, DRIVER_NAME);
+	strcpy(info->version, "42");
 }
 
+static struct ethtool_ops uml_net_ethtool_ops = {
+	.get_drvinfo	= uml_net_get_drvinfo,
+	.get_link	= ethtool_op_get_link,
+};
+
 void uml_net_user_timer_expire(unsigned long _conn)
 {
 #ifdef undef
@@ -284,9 +268,10 @@
 static DEFINE_SPINLOCK(devices_lock);
 static struct list_head devices = LIST_HEAD_INIT(devices);
 
-static struct device_driver uml_net_driver = {
-	.name  = DRIVER_NAME,
-	.bus   = &platform_bus_type,
+static struct platform_driver uml_net_driver = {
+	.driver = {
+		.name  = DRIVER_NAME,
+	},
 };
 static int driver_registered;
 
@@ -333,7 +318,7 @@
 
 	/* sysfs register */
 	if (!driver_registered) {
-		driver_register(&uml_net_driver);
+		platform_driver_register(&uml_net_driver);
 		driver_registered = 1;
 	}
 	device->pdev.id = n;
@@ -359,7 +344,7 @@
 	dev->tx_timeout = uml_net_tx_timeout;
 	dev->set_mac_address = uml_net_set_mac;
 	dev->change_mtu = uml_net_change_mtu;
-	dev->do_ioctl = uml_net_ioctl;
+	dev->ethtool_ops = &uml_net_ethtool_ops;
 	dev->watchdog_timeo = (HZ >> 1);
 	dev->irq = UM_ETH_IRQ;
 
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index b2c8625..9389891 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -823,9 +823,10 @@
 
 __initcall(ubd_mc_init);
 
-static struct device_driver ubd_driver = {
-	.name  = DRIVER_NAME,
-	.bus   = &platform_bus_type,
+static struct platform_driver ubd_driver = {
+	.driver = {
+		.name  = DRIVER_NAME,
+	},
 };
 
 int ubd_init(void)
@@ -850,7 +851,7 @@
 		if (register_blkdev(fake_major, "ubd"))
 			return -1;
 	}
-	driver_register(&ubd_driver);
+	platform_driver_register(&ubd_driver);
 	for (i = 0; i < MAX_DEV; i++) 
 		ubd_add(i);
 	return 0;
diff --git a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c
index 9c708c3..39cf247 100644
--- a/arch/v850/kernel/process.c
+++ b/arch/v850/kernel/process.c
@@ -36,11 +36,8 @@
 /* The idle loop.  */
 void default_idle (void)
 {
-	while (1) {
-		while (! need_resched ())
-			asm ("halt; nop; nop; nop; nop; nop" ::: "cc");
-		schedule ();
-	}
+	while (! need_resched ())
+		asm ("halt; nop; nop; nop; nop; nop" ::: "cc");
 }
 
 void (*idle)(void) = default_idle;
@@ -54,7 +51,14 @@
 void cpu_idle (void)
 {
 	/* endless idle loop with no priority at all */
-	(*idle) ();
+	while (1) {
+		while (!need_resched())
+			(*idle) ();
+
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+	}
 }
 
 /*
diff --git a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c
index 4ba0e29..e335bd0 100644
--- a/arch/x86_64/ia32/ia32_ioctl.c
+++ b/arch/x86_64/ia32/ia32_ioctl.c
@@ -64,12 +64,6 @@
 #include <linux/compat_ioctl.h>
 #define DECLARES
 #include "compat_ioctl.c"
-COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
-COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
-COMPATIBLE_IOCTL(BLKRASET)
-COMPATIBLE_IOCTL(0x4B50)   /* KDGHWCLK - not in the kernel, but don't complain */
-COMPATIBLE_IOCTL(0x4B51)   /* KDSHWCLK - not in the kernel, but don't complain */
-COMPATIBLE_IOCTL(FIOQSIZE)
 
 /* And these ioctls need translation */
 /* realtime device */
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index b5a89c0..59be85d 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -86,12 +86,22 @@
  */
 void default_idle(void)
 {
+	local_irq_enable();
+
 	if (!atomic_read(&hlt_counter)) {
-		local_irq_disable();
-		if (!need_resched())
-			safe_halt();
-		else
-			local_irq_enable();
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+		smp_mb__after_clear_bit();
+		while (!need_resched()) {
+			local_irq_disable();
+			if (!need_resched())
+				safe_halt();
+			else
+				local_irq_enable();
+		}
+		set_thread_flag(TIF_POLLING_NRFLAG);
+	} else {
+		while (!need_resched())
+			cpu_relax();
 	}
 }
 
@@ -102,30 +112,16 @@
  */
 static void poll_idle (void)
 {
-	int oldval;
-
 	local_irq_enable();
 
-	/*
-	 * Deal with another CPU just having chosen a thread to
-	 * run here:
-	 */
-	oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
-	if (!oldval) {
-		set_thread_flag(TIF_POLLING_NRFLAG); 
-		asm volatile(
-			"2:"
-			"testl %0,%1;"
-			"rep; nop;"
-			"je 2b;"
-			: :
-			"i" (_TIF_NEED_RESCHED), 
-			"m" (current_thread_info()->flags));
-		clear_thread_flag(TIF_POLLING_NRFLAG);
-	} else {
-		set_need_resched();
-	}
+	asm volatile(
+		"2:"
+		"testl %0,%1;"
+		"rep; nop;"
+		"je 2b;"
+		: :
+		"i" (_TIF_NEED_RESCHED),
+		"m" (current_thread_info()->flags));
 }
 
 void cpu_idle_wait(void)
@@ -187,6 +183,8 @@
  */
 void cpu_idle (void)
 {
+	set_thread_flag(TIF_POLLING_NRFLAG);
+
 	/* endless idle loop with no priority at all */
 	while (1) {
 		while (!need_resched()) {
@@ -204,7 +202,9 @@
 			idle();
 		}
 
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
@@ -219,15 +219,12 @@
 {
 	local_irq_enable();
 
-	if (!need_resched()) {
-		set_thread_flag(TIF_POLLING_NRFLAG);
-		do {
-			__monitor((void *)&current_thread_info()->flags, 0, 0);
-			if (need_resched())
-				break;
-			__mwait(0, 0);
-		} while (!need_resched());
-		clear_thread_flag(TIF_POLLING_NRFLAG);
+	while (!need_resched()) {
+		__monitor((void *)&current_thread_info()->flags, 0, 0);
+		smp_mb();
+		if (need_resched())
+			break;
+		__mwait(0, 0);
 	}
 }
 
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index 4b5b088..c4e59bb 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -472,6 +472,7 @@
 	 * things done here to the most necessary things.
 	 */
 	cpu_init();
+	preempt_disable();
 	smp_callin();
 
 	/* otherwise gcc will move up the smp_processor_id before the cpu_init */
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 08ef6d8..6a44b54 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -96,8 +96,9 @@
 	while (1) {
 		while (!need_resched())
 			platform_idle();
-		preempt_enable();
+		preempt_enable_no_resched();
 		schedule();
+		preempt_disable();
 	}
 }
 
diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c
index 0682ffd..0dc55cc 100644
--- a/arch/xtensa/platform-iss/network.c
+++ b/arch/xtensa/platform-iss/network.c
@@ -611,46 +611,15 @@
 	return -EINVAL;
 }
 
-static int iss_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-#if 0
-	static const struct ethtool_drvinfo info = {
-		.cmd     = ETHTOOL_GDRVINFO,
-		.driver  = DRIVER_NAME,
-		.version = "42",
-	};
-	void *useraddr;
-	u32 ethcmd;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		useraddr = ifr->ifr_data;
-		if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-			return -EFAULT;
-
-		switch (ethcmd) {
-			case ETHTOOL_GDRVINFO:
-				if (copy_to_user(useraddr, &info, sizeof(info)))
-					return -EFAULT;
-				return 0;
-			default:
-				return -EOPNOTSUPP;
-		}
-	default:
-		return -EINVAL;
-	}
-#endif
-	return -EINVAL;
-}
-
 void iss_net_user_timer_expire(unsigned long _conn)
 {
 }
 
 
-static struct device_driver iss_net_driver = {
-	.name  = DRIVER_NAME,
-	.bus   = &platform_bus_type,
+static struct platform_driver iss_net_driver = {
+	.driver = {
+		.name  = DRIVER_NAME,
+	},
 };
 
 static int driver_registered;
@@ -701,7 +670,7 @@
 	/* sysfs register */
 
 	if (!driver_registered) {
-		driver_register(&iss_net_driver);
+		platform_driver_register(&iss_net_driver);
 		driver_registered = 1;
 	}
 
@@ -730,7 +699,6 @@
 	dev->tx_timeout = iss_net_tx_timeout;
 	dev->set_mac_address = iss_net_set_mac;
 	dev->change_mtu = iss_net_change_mtu;
-	dev->do_ioctl = iss_net_ioctl;
 	dev->watchdog_timeo = (HZ >> 1);
 	dev->irq = -1;
 
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 3937adf..aa99371 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -203,6 +203,7 @@
 	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 {
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 161db4a..573b6a97 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -167,6 +167,19 @@
 	return;
 }
 
+static void acpi_safe_halt(void)
+{
+	int polling = test_thread_flag(TIF_POLLING_NRFLAG);
+	if (polling) {
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+		smp_mb__after_clear_bit();
+	}
+	if (!need_resched())
+		safe_halt();
+	if (polling)
+		set_thread_flag(TIF_POLLING_NRFLAG);
+}
+
 static atomic_t c3_cpu_count;
 
 static void acpi_processor_idle(void)
@@ -177,7 +190,7 @@
 	int sleep_ticks = 0;
 	u32 t1, t2 = 0;
 
-	pr = processors[raw_smp_processor_id()];
+	pr = processors[smp_processor_id()];
 	if (!pr)
 		return;
 
@@ -197,8 +210,13 @@
 	}
 
 	cx = pr->power.state;
-	if (!cx)
-		goto easy_out;
+	if (!cx) {
+		if (pm_idle_save)
+			pm_idle_save();
+		else
+			acpi_safe_halt();
+		return;
+	}
 
 	/*
 	 * Check BM Activity
@@ -278,7 +296,8 @@
 		if (pm_idle_save)
 			pm_idle_save();
 		else
-			safe_halt();
+			acpi_safe_halt();
+
 		/*
 		 * TBD: Can't get time duration while in C1, as resumes
 		 *      go to an ISR rather than here.  Need to instrument
@@ -414,16 +433,6 @@
 	 */
 	if (next_state != pr->power.state)
 		acpi_processor_power_activate(pr, next_state);
-
-	return;
-
-      easy_out:
-	/* do C1 instead of busy loop */
-	if (pm_idle_save)
-		pm_idle_save();
-	else
-		safe_halt();
-	return;
 }
 
 static int acpi_processor_set_power_policy(struct acpi_processor *pr)
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index 0cded04..821c81e 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -1511,8 +1511,8 @@
     // a.k.a. prepare the channel and remember that we have done so.
     
     tx_ch_desc * tx_desc = &memmap->tx_descs[tx_channel];
-    u16 rd_ptr;
-    u16 wr_ptr;
+    u32 rd_ptr;
+    u32 wr_ptr;
     u16 channel = vcc->channel;
     
     unsigned long flags;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 6d4736e..8827daf 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -20,6 +20,8 @@
 
 #include "base.h"
 
+#define to_platform_driver(drv)	(container_of((drv), struct platform_driver, driver))
+
 struct device platform_bus = {
 	.bus_id		= "platform",
 };
@@ -354,6 +356,77 @@
 	return ERR_PTR(retval);
 }
 
+static int platform_drv_probe(struct device *_dev)
+{
+	struct platform_driver *drv = to_platform_driver(_dev->driver);
+	struct platform_device *dev = to_platform_device(_dev);
+
+	return drv->probe(dev);
+}
+
+static int platform_drv_remove(struct device *_dev)
+{
+	struct platform_driver *drv = to_platform_driver(_dev->driver);
+	struct platform_device *dev = to_platform_device(_dev);
+
+	return drv->remove(dev);
+}
+
+static void platform_drv_shutdown(struct device *_dev)
+{
+	struct platform_driver *drv = to_platform_driver(_dev->driver);
+	struct platform_device *dev = to_platform_device(_dev);
+
+	drv->shutdown(dev);
+}
+
+static int platform_drv_suspend(struct device *_dev, pm_message_t state)
+{
+	struct platform_driver *drv = to_platform_driver(_dev->driver);
+	struct platform_device *dev = to_platform_device(_dev);
+
+	return drv->suspend(dev, state);
+}
+
+static int platform_drv_resume(struct device *_dev)
+{
+	struct platform_driver *drv = to_platform_driver(_dev->driver);
+	struct platform_device *dev = to_platform_device(_dev);
+
+	return drv->resume(dev);
+}
+
+/**
+ *	platform_driver_register
+ *	@drv: platform driver structure
+ */
+int platform_driver_register(struct platform_driver *drv)
+{
+	drv->driver.bus = &platform_bus_type;
+	if (drv->probe)
+		drv->driver.probe = platform_drv_probe;
+	if (drv->remove)
+		drv->driver.remove = platform_drv_remove;
+	if (drv->shutdown)
+		drv->driver.shutdown = platform_drv_shutdown;
+	if (drv->suspend)
+		drv->driver.suspend = platform_drv_suspend;
+	if (drv->resume)
+		drv->driver.resume = platform_drv_resume;
+	return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(platform_driver_register);
+
+/**
+ *	platform_driver_unregister
+ *	@drv: platform driver structure
+ */
+void platform_driver_unregister(struct platform_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(platform_driver_unregister);
+
 
 /**
  *	platform_match - bind platform device to platform driver.
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index 0e1f34f..5d2d649 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -58,7 +58,6 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <scsi/scsi.h> /* for SCSI_IOCTL_GET_IDLUN */
-typedef void Scsi_Device; /* hack to avoid including scsi.h */
 #include <scsi/scsi_ioctl.h>
 #include <linux/hdreg.h> /* for HDIO_GETGEO */
 #include <linux/blkpg.h>
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 1468e8c..0acbfff 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1816,7 +1816,6 @@
 }
 
 #ifdef MODULE
-#include <linux/version.h>
 
 int init_module(void)
 {
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index a97c80b..e239a6c 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -148,6 +148,7 @@
 static ctlr_info_t *hba[MAX_CTLR];
 
 static void do_cciss_request(request_queue_t *q);
+static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs);
 static int cciss_open(struct inode *inode, struct file *filep);
 static int cciss_release(struct inode *inode, struct file *filep);
 static int cciss_ioctl(struct inode *inode, struct file *filep, 
@@ -1583,6 +1584,24 @@
 		}
 	} else if (cmd_type == TYPE_MSG) {
 		switch (cmd) {
+		case 0: /* ABORT message */
+			c->Request.CDBLen = 12;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_WRITE;
+			c->Request.Timeout = 0;
+			c->Request.CDB[0] = cmd; /* abort */
+			c->Request.CDB[1] = 0;   /* abort a command */
+			/* buff contains the tag of the command to abort */
+			memcpy(&c->Request.CDB[4], buff, 8);
+			break;
+		case 1: /* RESET message */
+			c->Request.CDBLen = 12;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_WRITE;
+			c->Request.Timeout = 0;
+			memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
+			c->Request.CDB[0] = cmd;  /* reset */
+			c->Request.CDB[1] = 0x04; /* reset a LUN */
 		case 3:	/* No-Op message */
 			c->Request.CDBLen = 1;
 			c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1869,6 +1888,52 @@
 	/* Invalid address to tell caller we ran out of time */
 	return 1;
 }
+
+static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
+{
+	/* We get in here if sendcmd() is polling for completions
+	   and gets some command back that it wasn't expecting -- 
+	   something other than that which it just sent down.  
+	   Ordinarily, that shouldn't happen, but it can happen when 
+	   the scsi tape stuff gets into error handling mode, and
+	   starts using sendcmd() to try to abort commands and 
+	   reset tape drives.  In that case, sendcmd may pick up
+	   completions of commands that were sent to logical drives
+	   through the block i/o system, or cciss ioctls completing, etc. 
+	   In that case, we need to save those completions for later
+	   processing by the interrupt handler.
+	*/
+
+#ifdef CONFIG_CISS_SCSI_TAPE
+	struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;	
+
+	/* If it's not the scsi tape stuff doing error handling, (abort */
+	/* or reset) then we don't expect anything weird. */
+	if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) {
+#endif
+		printk( KERN_WARNING "cciss cciss%d: SendCmd "
+		      "Invalid command list address returned! (%lx)\n",
+			ctlr, complete);
+		/* not much we can do. */
+#ifdef CONFIG_CISS_SCSI_TAPE
+		return 1;
+	}
+
+	/* We've sent down an abort or reset, but something else
+	   has completed */
+	if (srl->ncompletions >= (NR_CMDS + 2)) {
+		/* Uh oh.  No room to save it for later... */
+		printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, "
+			"reject list overflow, command lost!\n", ctlr);
+		return 1;
+	}
+	/* Save it for later */
+	srl->complete[srl->ncompletions] = complete;
+	srl->ncompletions++;
+#endif
+	return 0;
+}
+
 /*
  * Send a command to the controller, and wait for it to complete.  
  * Only used at init time. 
@@ -1891,7 +1956,7 @@
 	unsigned long complete;
 	ctlr_info_t *info_p= hba[ctlr];
 	u64bit buff_dma_handle;
-	int status;
+	int status, done = 0;
 
 	if ((c = cmd_alloc(info_p, 1)) == NULL) {
 		printk(KERN_WARNING "cciss: unable to get memory");
@@ -1913,7 +1978,9 @@
         info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
 	
 	/* Make sure there is room in the command FIFO */
-        /* Actually it should be completely empty at this time. */
+        /* Actually it should be completely empty at this time */
+	/* unless we are in here doing error handling for the scsi */
+	/* tape side of the driver. */
         for (i = 200000; i > 0; i--) 
 	{
 		/* if fifo isn't full go */
@@ -1930,13 +1997,25 @@
          * Send the cmd
          */
         info_p->access.submit_command(info_p, c);
-        complete = pollcomplete(ctlr);
+	done = 0;
+	do {
+		complete = pollcomplete(ctlr);
 
 #ifdef CCISS_DEBUG
-	printk(KERN_DEBUG "cciss: command completed\n");
+		printk(KERN_DEBUG "cciss: command completed\n");
 #endif /* CCISS_DEBUG */
 
-	if (complete != 1) {
+		if (complete == 1) {
+			printk( KERN_WARNING
+				"cciss cciss%d: SendCmd Timeout out, "
+				"No command list address returned!\n",
+				ctlr);
+			status = IO_ERROR;
+			done = 1;
+			break;
+		}
+
+		/* This will need to change for direct lookup completions */
 		if ( (complete & CISS_ERROR_BIT)
 		     && (complete & ~CISS_ERROR_BIT) == c->busaddr)
 		     {
@@ -1976,6 +2055,10 @@
 						status = IO_ERROR;
 						goto cleanup1;
 					}
+				} else if (c->err_info->CommandStatus == CMD_UNABORTABLE) {
+					printk(KERN_WARNING "cciss%d: command could not be aborted.\n", ctlr);
+					status = IO_ERROR;
+					goto cleanup1;
 				}
 				printk(KERN_WARNING "ciss ciss%d: sendcmd"
 				" Error %x \n", ctlr, 
@@ -1990,20 +2073,15 @@
 				goto cleanup1;
 			}
 		}
+		/* This will need changing for direct lookup completions */
                 if (complete != c->busaddr) {
-                        printk( KERN_WARNING "cciss cciss%d: SendCmd "
-                      "Invalid command list address returned! (%lx)\n",
-                                ctlr, complete);
-			status = IO_ERROR;
-			goto cleanup1;
-                }
-        } else {
-                printk( KERN_WARNING
-                        "cciss cciss%d: SendCmd Timeout out, "
-                        "No command list address returned!\n",
-                        ctlr);
-		status = IO_ERROR;
-        }
+			if (add_sendcmd_reject(cmd, ctlr, complete) != 0) {
+				BUG(); /* we are pretty much hosed if we get here. */
+			}
+			continue;
+                } else
+			done = 1;
+        } while (!done);
 		
 cleanup1:	
 	/* unlock the data buffer from DMA */
@@ -2011,6 +2089,11 @@
 	buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
 	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
 				c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+#ifdef CONFIG_CISS_SCSI_TAPE
+	/* if we saved some commands for later, process them now. */
+	if (info_p->scsi_rejects.ncompletions > 0)
+		do_cciss_intr(0, info_p, NULL);
+#endif
 	cmd_free(info_p, c, 1);
 	return (status);
 } 
@@ -2335,6 +2418,48 @@
 	start_io(h);
 }
 
+static inline unsigned long get_next_completion(ctlr_info_t *h)
+{
+#ifdef CONFIG_CISS_SCSI_TAPE
+	/* Any rejects from sendcmd() lying around? Process them first */
+	if (h->scsi_rejects.ncompletions == 0)
+		return h->access.command_completed(h);
+	else {
+		struct sendcmd_reject_list *srl;
+		int n;
+		srl = &h->scsi_rejects;
+		n = --srl->ncompletions;
+		/* printk("cciss%d: processing saved reject\n", h->ctlr); */
+		printk("p");
+		return srl->complete[n];
+	}
+#else
+	return h->access.command_completed(h);
+#endif
+}
+
+static inline int interrupt_pending(ctlr_info_t *h)
+{
+#ifdef CONFIG_CISS_SCSI_TAPE
+	return ( h->access.intr_pending(h) 
+		|| (h->scsi_rejects.ncompletions > 0));
+#else
+	return h->access.intr_pending(h);
+#endif
+}
+
+static inline long interrupt_not_for_us(ctlr_info_t *h)
+{
+#ifdef CONFIG_CISS_SCSI_TAPE
+	return (((h->access.intr_pending(h) == 0) || 
+		 (h->interrupts_enabled == 0)) 
+	      && (h->scsi_rejects.ncompletions == 0));
+#else
+	return (((h->access.intr_pending(h) == 0) || 
+		 (h->interrupts_enabled == 0)));
+#endif
+}
+
 static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	ctlr_info_t *h = dev_id;
@@ -2344,19 +2469,15 @@
 	int j;
 	int start_queue = h->next_to_run;
 
-	/* Is this interrupt for us? */
-	if (( h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0))
+	if (interrupt_not_for_us(h))
 		return IRQ_NONE;
-
 	/*
 	 * If there are completed commands in the completion queue,
 	 * we had better do something about it.
 	 */
 	spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
-	while( h->access.intr_pending(h))
-	{
-		while((a = h->access.command_completed(h)) != FIFO_EMPTY) 
-		{
+	while (interrupt_pending(h)) {
+		while((a = get_next_completion(h)) != FIFO_EMPTY) {
 			a1 = a;
 			if ((a & 0x04)) {
 				a2 = (a >> 3);
@@ -2963,7 +3084,15 @@
                 printk( KERN_ERR "cciss: out of memory");
 		goto clean4;
 	}
-
+#ifdef CONFIG_CISS_SCSI_TAPE
+	hba[i]->scsi_rejects.complete = 
+		kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) * 
+			(NR_CMDS + 5), GFP_KERNEL);
+	if (hba[i]->scsi_rejects.complete == NULL) {
+                printk( KERN_ERR "cciss: out of memory");
+		goto clean4;
+	}
+#endif
 	spin_lock_init(&hba[i]->lock);
 
 	/* Initialize the pdev driver private data. 
@@ -3031,6 +3160,10 @@
 	return(1);
 
 clean4:
+#ifdef CONFIG_CISS_SCSI_TAPE
+	if(hba[i]->scsi_rejects.complete)
+		kfree(hba[i]->scsi_rejects.complete);
+#endif
 	kfree(hba[i]->cmd_pool_bits);
 	if(hba[i]->cmd_pool)
 		pci_free_consistent(hba[i]->pdev,
@@ -3103,6 +3236,9 @@
 	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
 		hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
 	kfree(hba[i]->cmd_pool_bits);
+#ifdef CONFIG_CISS_SCSI_TAPE
+	kfree(hba[i]->scsi_rejects.complete);
+#endif
  	release_io_mem(hba[i]);
 	free_hba(i);
 }	
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index ef277ba..3b0858c 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -44,6 +44,14 @@
 				  */
 } drive_info_struct;
 
+#ifdef CONFIG_CISS_SCSI_TAPE
+
+struct sendcmd_reject_list {
+	int ncompletions;
+	unsigned long *complete; /* array of NR_CMDS tags */
+};
+
+#endif
 struct ctlr_info 
 {
 	int	ctlr;
@@ -100,6 +108,9 @@
 	struct gendisk   *gendisk[NWD];
 #ifdef CONFIG_CISS_SCSI_TAPE
 	void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
+	/* list of block side commands the scsi error handling sucked up */
+	/* and saved for later processing */
+	struct sendcmd_reject_list scsi_rejects;
 #endif
 	unsigned char alive;
 };
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index ec27976..3226aa1 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -42,6 +42,9 @@
 
 #include "cciss_scsi.h"
 
+#define CCISS_ABORT_MSG 0x00
+#define CCISS_RESET_MSG 0x01
+
 /* some prototypes... */ 
 static int sendcmd(
 	__u8	cmd,
@@ -67,6 +70,8 @@
 
 static int cciss_scsi_queue_command (struct scsi_cmnd *cmd,
 		void (* done)(struct scsi_cmnd *));
+static int cciss_eh_device_reset_handler(struct scsi_cmnd *);
+static int cciss_eh_abort_handler(struct scsi_cmnd *);
 
 static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = {
 	{ .name = "cciss0", .ndevices = 0 },
@@ -90,6 +95,9 @@
 	.sg_tablesize		= MAXSGENTRIES,
 	.cmd_per_lun		= 1,
 	.use_clustering		= DISABLE_CLUSTERING,
+	/* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */
+	.eh_device_reset_handler= cciss_eh_device_reset_handler,
+	.eh_abort_handler	= cciss_eh_abort_handler,
 };
 
 #pragma pack(1)
@@ -247,7 +255,7 @@
 #define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
 	"Unknown" : scsi_device_types[n]
 
-#if 0
+#if 1
 static int xmargin=8;
 static int amargin=60;
 
@@ -1448,6 +1456,78 @@
 	*pos += size; *len += size;
 }
 
+/* Need at least one of these error handlers to keep ../scsi/hosts.c from 
+ * complaining.  Doing a host- or bus-reset can't do anything good here. 
+ * Despite what it might say in scsi_error.c, there may well be commands
+ * on the controller, as the cciss driver registers twice, once as a block
+ * device for the logical drives, and once as a scsi device, for any tape
+ * drives.  So we know there are no commands out on the tape drives, but we
+ * don't know there are no commands on the controller, and it is likely 
+ * that there probably are, as the cciss block device is most commonly used
+ * as a boot device (embedded controller on HP/Compaq systems.)
+*/
+
+static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
+{
+	int rc;
+	CommandList_struct *cmd_in_trouble;
+	ctlr_info_t **c;
+	int ctlr;
+
+	/* find the controller to which the command to be aborted was sent */
+	c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];	
+	if (c == NULL) /* paranoia */
+		return FAILED;
+	ctlr = (*c)->ctlr;
+	printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr);
+
+	/* find the command that's giving us trouble */
+	cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble;
+	if (cmd_in_trouble == NULL) { /* paranoia */
+		return FAILED;
+	}
+	/* send a reset to the SCSI LUN which the command was sent to */
+	rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, 
+		(unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 
+		TYPE_MSG);
+	/* sendcmd turned off interrputs on the board, turn 'em back on. */
+	(*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
+	if (rc == 0)
+		return SUCCESS;
+	printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr);
+	return FAILED;
+}
+
+static int  cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
+{
+	int rc;
+	CommandList_struct *cmd_to_abort;
+	ctlr_info_t **c;
+	int ctlr;
+
+	/* find the controller to which the command to be aborted was sent */
+	c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];	
+	if (c == NULL) /* paranoia */
+		return FAILED;
+	ctlr = (*c)->ctlr;
+	printk(KERN_WARNING "cciss%d: aborting tardy SCSI cmd\n", ctlr);
+
+	/* find the command to be aborted */
+	cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble;
+	if (cmd_to_abort == NULL) /* paranoia */
+		return FAILED;
+	rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, 
+		0, 2, 0, 0, 
+		(unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], 
+		TYPE_MSG);
+	/* sendcmd turned off interrputs on the board, turn 'em back on. */
+	(*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
+	if (rc == 0)
+		return SUCCESS;
+	return FAILED;
+
+}
+
 #else /* no CONFIG_CISS_SCSI_TAPE */
 
 /* If no tape support, then these become defined out of existence */
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 77cfd69..13b8a9b 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3714,6 +3714,12 @@
 		USETF(FD_VERIFY);
 	}
 
+	/* set underlying gendisk policy to reflect real ro/rw status */
+	if (UTESTF(FD_DISK_WRITABLE))
+		inode->i_bdev->bd_disk->policy = 0;
+	else
+		inode->i_bdev->bd_disk->policy = 1;
+
 	if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
 		goto out2;
 
@@ -3770,8 +3776,7 @@
 	/* Allow ioctls if we have write-permissions even if read-only open.
 	 * Needed so that programs such as fdrawcmd still can work on write
 	 * protected disks */
-	if (filp->f_mode & 2
-	    || permission(filp->f_dentry->d_inode, 2, NULL) == 0)
+	if ((filp->f_mode & FMODE_WRITE) || !file_permission(filp, MAY_WRITE))
 		filp->private_data = (void *)8;
 
 	if (UFDCS->rawcmd == 1)
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index a280e67..59e5982 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -511,14 +511,11 @@
  */
 static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
 {
-	request_queue_t *q;
 
 	if (atomic_read(&pd->iosched.attention) == 0)
 		return;
 	atomic_set(&pd->iosched.attention, 0);
 
-	q = bdev_get_queue(pd->bdev);
-
 	for (;;) {
 		struct bio *bio;
 		int reads_queued, writes_queued;
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index ecbeb7e..3947963 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -84,8 +84,8 @@
 
 struct hci_vendor_hdr {
 	__u8	type;
-	__u16	snum;
-	__u16	dlen;
+	__le16	snum;
+	__le16	dlen;
 } __attribute__ ((packed));
 
 static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count)
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index f510b25..057cb2b 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -65,6 +65,7 @@
 #endif
 
 static int ignore = 0;
+static int ignore_dga = 0;
 static int ignore_csr = 0;
 static int ignore_sniffer = 0;
 static int reset = 0;
@@ -841,6 +842,9 @@
 	if (ignore || id->driver_info & HCI_IGNORE)
 		return -ENODEV;
 
+	if (ignore_dga && id->driver_info & HCI_DIGIANSWER)
+		return -ENODEV;
+
 	if (ignore_csr && id->driver_info & HCI_CSR)
 		return -ENODEV;
 
@@ -1070,6 +1074,9 @@
 module_param(ignore, bool, 0644);
 MODULE_PARM_DESC(ignore, "Ignore devices from the matching table");
 
+module_param(ignore_dga, bool, 0644);
+MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001");
+
 module_param(ignore_csr, bool, 0644);
 MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001");
 
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index ba54b58..b02fc22 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -389,7 +389,6 @@
 MODULE_DEVICE_TABLE(pci, agp_ali_pci_table);
 
 static struct pci_driver agp_ali_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-ali",
 	.id_table	= agp_ali_pci_table,
 	.probe		= agp_ali_probe,
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 40fcd88b2..1f77665 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -515,7 +515,6 @@
 MODULE_DEVICE_TABLE(pci, agp_amdk7_pci_table);
 
 static struct pci_driver agp_amdk7_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-amdk7",
 	.id_table	= agp_amdk7_pci_table,
 	.probe		= agp_amdk7_probe,
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 8f748fd..78ce98a 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -703,7 +703,6 @@
 MODULE_DEVICE_TABLE(pci, agp_amd64_pci_table);
 
 static struct pci_driver agp_amd64_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-amd64",
 	.id_table	= agp_amd64_pci_table,
 	.probe		= agp_amd64_probe,
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index fbd4155..53372a8 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -521,7 +521,6 @@
 MODULE_DEVICE_TABLE(pci, agp_ati_pci_table);
 
 static struct pci_driver agp_ati_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-ati",
 	.id_table	= agp_ati_pci_table,
 	.probe		= agp_ati_probe,
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 73f333f..27bca34 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -147,6 +147,7 @@
 			printk(KERN_ERR PFX "unable to get memory for scratch page.\n");
 			return -ENOMEM;
 		}
+		flush_agp_mappings();
 
 		bridge->scratch_page_real = virt_to_gart(addr);
 		bridge->scratch_page =
@@ -187,9 +188,11 @@
 	return 0;
 
 err_out:
-	if (bridge->driver->needs_scratch_page)
+	if (bridge->driver->needs_scratch_page) {
 		bridge->driver->agp_destroy_page(
 				gart_to_virt(bridge->scratch_page_real));
+		flush_agp_mappings();
+	}
 	if (got_gatt)
 		bridge->driver->free_gatt_table(bridge);
 	if (got_keylist) {
@@ -211,9 +214,11 @@
 	bridge->key_list = NULL;
 
 	if (bridge->driver->agp_destroy_page &&
-	    bridge->driver->needs_scratch_page)
+	    bridge->driver->needs_scratch_page) {
 		bridge->driver->agp_destroy_page(
 				gart_to_virt(bridge->scratch_page_real));
+		flush_agp_mappings();
+	}
 }
 
 /* When we remove the global variable agp_bridge from all drivers
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index d41e0a6..e7aea77 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -429,7 +429,6 @@
 MODULE_DEVICE_TABLE(pci, agp_efficeon_pci_table);
 
 static struct pci_driver agp_efficeon_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-efficeon",
 	.id_table	= agp_efficeon_pci_table,
 	.probe		= agp_efficeon_probe,
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index c4a3871..5567ce8 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -57,7 +57,8 @@
 {
 	int i;
 	i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE);
-	global_flush_tlb();
+	/* Caller's responsibility to call global_flush_tlb() for
+	 * performance reasons */
 	return i;
 }
 EXPORT_SYMBOL_GPL(map_page_into_agp);
@@ -66,7 +67,8 @@
 {
 	int i;
 	i = change_page_attr(page, 1, PAGE_KERNEL);
-	global_flush_tlb();
+	/* Caller's responsibility to call global_flush_tlb() for
+	 * performance reasons */
 	return i;
 }
 EXPORT_SYMBOL_GPL(unmap_page_from_agp);
@@ -153,6 +155,7 @@
 		for (i = 0; i < curr->page_count; i++) {
 			curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]));
 		}
+		flush_agp_mappings();
 	}
 	agp_free_key(curr->key);
 	vfree(curr->memory);
@@ -210,7 +213,7 @@
 		new->memory[i] = virt_to_gart(addr);
 		new->page_count++;
 	}
-       new->bridge = bridge;
+	new->bridge = bridge;
 
 	flush_agp_mappings();
 
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 58944cd..8ee19a4 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -111,8 +111,10 @@
 
 	if (i460.io_page_shift != I460_IO_PAGE_SHIFT) {
 		printk(KERN_ERR PFX
-		       "I/O (GART) page-size %ZuKB doesn't match expected size %ZuKB\n",
-		       1UL << (i460.io_page_shift - 10), 1UL << (I460_IO_PAGE_SHIFT));
+			"I/O (GART) page-size %luKB doesn't match expected "
+				"size %luKB\n",
+			1UL << (i460.io_page_shift - 10),
+			1UL << (I460_IO_PAGE_SHIFT));
 		return 0;
 	}
 
@@ -514,9 +516,10 @@
 {
 	void *page;
 
-	if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT)
+	if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
 		page = agp_generic_alloc_page(agp_bridge);
-	else
+		global_flush_tlb();
+	} else
 		/* Returning NULL would cause problems */
 		/* AK: really dubious code. */
 		page = (void *)~0UL;
@@ -525,8 +528,10 @@
 
 static void i460_destroy_page (void *page)
 {
-	if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT)
+	if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
 		agp_generic_destroy_page(page);
+		global_flush_tlb();
+	}
 }
 
 #endif /* I460_LARGE_IO_PAGES */
@@ -536,7 +541,7 @@
 {
 	/* Make sure the returned address is a valid GATT entry */
 	return bridge->driver->masks[0].mask
-		| (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xffffff000) >> 12);
+		| (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12);
 }
 
 struct agp_bridge_driver intel_i460_driver = {
@@ -617,7 +622,6 @@
 MODULE_DEVICE_TABLE(pci, agp_intel_i460_pci_table);
 
 static struct pci_driver agp_intel_i460_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-intel-i460",
 	.id_table	= agp_intel_i460_pci_table,
 	.probe		= agp_intel_i460_probe,
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index bf4cc9f..e7bed50 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -270,6 +270,7 @@
 
 	switch (pg_count) {
 	case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge);
+		global_flush_tlb();
 		break;
 	case 4:
 		/* kludge to get 4 physical pages for ARGB cursor */
@@ -330,9 +331,11 @@
 	if(curr->type == AGP_PHYS_MEMORY) {
 		if (curr->page_count == 4)
 			i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
-		else
+		else {
 			agp_bridge->driver->agp_destroy_page(
 				 gart_to_virt(curr->memory[0]));
+			global_flush_tlb();
+		}
 		vfree(curr->memory);
 	}
 	kfree(curr);
@@ -1824,7 +1827,6 @@
 MODULE_DEVICE_TABLE(pci, agp_intel_pci_table);
 
 static struct pci_driver agp_intel_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-intel",
 	.id_table	= agp_intel_pci_table,
 	.probe		= agp_intel_probe,
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 3aed0c5..80dafa3 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -398,7 +398,6 @@
 MODULE_DEVICE_TABLE(pci, agp_nvidia_pci_table);
 
 static struct pci_driver agp_nvidia_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-nvidia",
 	.id_table	= agp_nvidia_pci_table,
 	.probe		= agp_nvidia_probe,
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index a701361..ebc0555 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -332,7 +332,6 @@
 MODULE_DEVICE_TABLE(pci, agp_sis_pci_table);
 
 static struct pci_driver agp_sis_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-sis",
 	.id_table	= agp_sis_pci_table,
 	.probe		= agp_sis_probe,
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 5a5392d..3f8f7fa 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -545,7 +545,6 @@
 MODULE_DEVICE_TABLE(pci, agp_serverworks_pci_table);
 
 static struct pci_driver agp_serverworks_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-serverworks",
 	.id_table	= agp_serverworks_pci_table,
 	.probe		= agp_serverworks_probe,
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 183c50a..c825531 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -658,7 +658,6 @@
 MODULE_DEVICE_TABLE(pci, agp_uninorth_pci_table);
 
 static struct pci_driver agp_uninorth_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-uninorth",
 	.id_table	= agp_uninorth_pci_table,
 	.probe		= agp_uninorth_probe,
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 5d9a137..c847df5 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -518,7 +518,6 @@
 
 
 static struct pci_driver agp_via_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "agpgart-via",
 	.id_table	= agp_via_pci_table,
 	.probe		= agp_via_probe,
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index 6d3fec1..efff0ee 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -203,10 +203,10 @@
 
 		for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
 			if (gart_info->is_pcie)
-				*pci_gart = (cpu_to_le32(page_base) >> 8) | 0xc;
+				*pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
 			else
 				*pci_gart = cpu_to_le32(page_base);
-			*pci_gart++;
+			pci_gart++;
 			page_base += ATI_PCIGART_PAGE_SIZE;
 		}
 	}
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index b7a0e4d..407708a 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -3113,7 +3113,6 @@
 int __init init_PCI (void)
 {	/* Begin init_PCI */
 	memset (&epca_driver, 0, sizeof (epca_driver));
-	epca_driver.owner = THIS_MODULE;
 	epca_driver.name = "epca";
 	epca_driver.id_table = epca_pci_tbl;
 	epca_driver.probe = epca_init_one;
diff --git a/drivers/char/ip2.c b/drivers/char/ip2.c
index 6cd12f2..7cadfc6 100644
--- a/drivers/char/ip2.c
+++ b/drivers/char/ip2.c
@@ -7,7 +7,6 @@
 //
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/wait.h>
 
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index c1d06ba..d16bd4b 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -2648,7 +2648,7 @@
 	spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
 	if (!list_empty(&intf->waiting_msgs)) {
 		list_add_tail(&msg->link, &intf->waiting_msgs);
-		spin_unlock(&intf->waiting_msgs_lock);
+		spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
 		goto out;
 	}
 	spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
@@ -2657,9 +2657,9 @@
 	if (rv > 0) {
 		/* Could not handle the message now, just add it to a
                    list to handle later. */
-		spin_lock(&intf->waiting_msgs_lock);
+		spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
 		list_add_tail(&msg->link, &intf->waiting_msgs);
-		spin_unlock(&intf->waiting_msgs_lock);
+		spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
 	} else if (rv == 0) {
 		ipmi_free_smi_msg(msg);
 	}
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c
index d6c72e0..cc3e54d 100644
--- a/drivers/char/mwave/tp3780i.c
+++ b/drivers/char/mwave/tp3780i.c
@@ -46,7 +46,6 @@
 *	First release to the public
 */
 
-#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 3b965a6..26448f1 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -38,7 +38,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
index d724c0d..3df7a57 100644
--- a/drivers/char/s3c2410-rtc.c
+++ b/drivers/char/s3c2410-rtc.c
@@ -382,7 +382,7 @@
 	.proc	        = s3c2410_rtc_proc,
 };
 
-static void s3c2410_rtc_enable(struct device *dev, int en)
+static void s3c2410_rtc_enable(struct platform_device *pdev, int en)
 {
 	unsigned int tmp;
 
@@ -399,21 +399,21 @@
 		/* re-enable the device, and check it is ok */
 
 		if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
-			dev_info(dev, "rtc disabled, re-enabling\n");
+			dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
 
 			tmp = readb(S3C2410_RTCCON);
 			writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON);
 		}
 
 		if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
-			dev_info(dev, "removing S3C2410_RTCCON_CNTSEL\n");
+			dev_info(&pdev->dev, "removing S3C2410_RTCCON_CNTSEL\n");
 
 			tmp = readb(S3C2410_RTCCON);
 			writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON);
 		}
 
 		if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
-			dev_info(dev, "removing S3C2410_RTCCON_CLKRST\n");
+			dev_info(&pdev->dev, "removing S3C2410_RTCCON_CLKRST\n");
 
 			tmp = readb(S3C2410_RTCCON);
 			writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON);
@@ -421,7 +421,7 @@
 	}
 }
 
-static int s3c2410_rtc_remove(struct device *dev)
+static int s3c2410_rtc_remove(struct platform_device *dev)
 {
 	unregister_rtc(&s3c2410_rtcops);
 
@@ -438,25 +438,24 @@
 	return 0;
 }
 
-static int s3c2410_rtc_probe(struct device *dev)
+static int s3c2410_rtc_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *res;
 	int ret;
 
-	pr_debug("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev);
+	pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);
 
 	/* find the IRQs */
 
 	s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
 	if (s3c2410_rtc_tickno <= 0) {
-		dev_err(dev, "no irq for rtc tick\n");
+		dev_err(&pdev->dev, "no irq for rtc tick\n");
 		return -ENOENT;
 	}
 
 	s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
 	if (s3c2410_rtc_alarmno <= 0) {
-		dev_err(dev, "no irq for alarm\n");
+		dev_err(&pdev->dev, "no irq for alarm\n");
 		return -ENOENT;
 	}
 
@@ -467,7 +466,7 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL) {
-		dev_err(dev, "failed to get memory region resource\n");
+		dev_err(&pdev->dev, "failed to get memory region resource\n");
 		return -ENOENT;
 	}
 
@@ -475,14 +474,14 @@
 				     pdev->name);
 
 	if (s3c2410_rtc_mem == NULL) {
-		dev_err(dev, "failed to reserve memory region\n");
+		dev_err(&pdev->dev, "failed to reserve memory region\n");
 		ret = -ENOENT;
 		goto exit_err;
 	}
 
 	s3c2410_rtc_base = ioremap(res->start, res->end - res->start + 1);
 	if (s3c2410_rtc_base == NULL) {
-		dev_err(dev, "failed ioremap()\n");
+		dev_err(&pdev->dev, "failed ioremap()\n");
 		ret = -EINVAL;
 		goto exit_err;
 	}
@@ -494,7 +493,7 @@
 
 	/* check to see if everything is setup correctly */
 
-	s3c2410_rtc_enable(dev, 1);
+	s3c2410_rtc_enable(pdev, 1);
 
  	pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
 
@@ -506,7 +505,7 @@
 	return 0;
 
  exit_err:
-	dev_err(dev, "error %d during initialisation\n", ret);
+	dev_err(&pdev->dev, "error %d during initialisation\n", ret);
 
 	return ret;
 }
@@ -519,7 +518,7 @@
 
 static int ticnt_save;
 
-static int s3c2410_rtc_suspend(struct device *dev, pm_message_t state)
+static int s3c2410_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct rtc_time tm;
 	struct timespec time;
@@ -535,19 +534,19 @@
 	s3c2410_rtc_gettime(&tm);
 	rtc_tm_to_time(&tm, &time.tv_sec);
 	save_time_delta(&s3c2410_rtc_delta, &time);
-	s3c2410_rtc_enable(dev, 0);
+	s3c2410_rtc_enable(pdev, 0);
 
 	return 0;
 }
 
-static int s3c2410_rtc_resume(struct device *dev)
+static int s3c2410_rtc_resume(struct platform_device *pdev)
 {
 	struct rtc_time tm;
 	struct timespec time;
 
 	time.tv_nsec = 0;
 
-	s3c2410_rtc_enable(dev, 1);
+	s3c2410_rtc_enable(pdev, 1);
 	s3c2410_rtc_gettime(&tm);
 	rtc_tm_to_time(&tm, &time.tv_sec);
 	restore_time_delta(&s3c2410_rtc_delta, &time);
@@ -560,14 +559,15 @@
 #define s3c2410_rtc_resume  NULL
 #endif
 
-static struct device_driver s3c2410_rtcdrv = {
-	.name		= "s3c2410-rtc",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2410_rtcdrv = {
 	.probe		= s3c2410_rtc_probe,
 	.remove		= s3c2410_rtc_remove,
 	.suspend	= s3c2410_rtc_suspend,
 	.resume		= s3c2410_rtc_resume,
+	.driver		= {
+		.name	= "s3c2410-rtc",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static char __initdata banner[] = "S3C2410 RTC, (c) 2004 Simtec Electronics\n";
@@ -575,12 +575,12 @@
 static int __init s3c2410_rtc_init(void)
 {
 	printk(banner);
-	return driver_register(&s3c2410_rtcdrv);
+	return platform_driver_register(&s3c2410_rtcdrv);
 }
 
 static void __exit s3c2410_rtc_exit(void)
 {
-	driver_unregister(&s3c2410_rtcdrv);
+	platform_driver_unregister(&s3c2410_rtcdrv);
 }
 
 module_init(s3c2410_rtc_init);
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index d05067d..51a0737 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1168,7 +1168,7 @@
 #ifdef CONFIG_PM
 static int old_camera_power;
 
-static int sonypi_suspend(struct device *dev, pm_message_t state)
+static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
 {
 	old_camera_power = sonypi_device.camera_power;
 	sonypi_disable();
@@ -1176,26 +1176,27 @@
 	return 0;
 }
 
-static int sonypi_resume(struct device *dev)
+static int sonypi_resume(struct platform_device *dev)
 {
 	sonypi_enable(old_camera_power);
 	return 0;
 }
 #endif
 
-static void sonypi_shutdown(struct device *dev)
+static void sonypi_shutdown(struct platform_device *dev)
 {
 	sonypi_disable();
 }
 
-static struct device_driver sonypi_driver = {
-	.name		= "sonypi",
-	.bus		= &platform_bus_type,
+static struct platform_driver sonypi_driver = {
 #ifdef CONFIG_PM
 	.suspend	= sonypi_suspend,
 	.resume		= sonypi_resume,
 #endif
 	.shutdown	= sonypi_shutdown,
+	.driver		= {
+		.name	= "sonypi",
+	},
 };
 
 static int __devinit sonypi_create_input_devices(void)
@@ -1455,20 +1456,20 @@
 	if (!dmi_check_system(sonypi_dmi_table))
 		return -ENODEV;
 
-	ret = driver_register(&sonypi_driver);
+	ret = platform_driver_register(&sonypi_driver);
 	if (ret)
 		return ret;
 
 	ret = sonypi_probe();
 	if (ret)
-		driver_unregister(&sonypi_driver);
+		platform_driver_unregister(&sonypi_driver);
 
 	return ret;
 }
 
 static void __exit sonypi_exit(void)
 {
-	driver_unregister(&sonypi_driver);
+	platform_driver_unregister(&sonypi_driver);
 	sonypi_remove();
 }
 
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 352547e..0bbfce4 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -90,7 +90,6 @@
 #include <linux/fcntl.h>
 #include <linux/major.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 5d1ffa3..82c6abd 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -912,7 +912,6 @@
 MODULE_LICENSE("GPL");
 
 static struct pci_driver synclink_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "synclink",
 	.id_table	= synclink_pci_tbl,
 	.probe		= synclink_init_one,
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 7c063c5..ee5a40b 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -500,7 +500,6 @@
 MODULE_LICENSE("GPL");
 
 static struct pci_driver synclinkmp_pci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "synclinkmp",
 	.id_table	= synclinkmp_pci_tbl,
 	.probe		= synclinkmp_init_one,
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index feb2515..145275e 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -354,7 +354,7 @@
         return op_p;
 }
 
-void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
+static void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
         int i;
 
 	i = sysrq_key_table_key2index(key);
@@ -419,7 +419,7 @@
 	__handle_sysrq(key, pt_regs, tty, 1);
 }
 
-int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
+static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
                                 struct sysrq_key_op *remove_op_p) {
 
 	int retval;
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c
index 24355b2..b3d411a 100644
--- a/drivers/char/tb0219.c
+++ b/drivers/char/tb0219.c
@@ -283,7 +283,7 @@
 	vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW);
 }
 
-static int tb0219_probe(struct device *dev)
+static int tb0219_probe(struct platform_device *dev)
 {
 	int retval;
 
@@ -319,7 +319,7 @@
 	return 0;
 }
 
-static int tb0219_remove(struct device *dev)
+static int tb0219_remove(struct platform_device *dev)
 {
 	_machine_restart = old_machine_restart;
 
@@ -333,11 +333,12 @@
 
 static struct platform_device *tb0219_platform_device;
 
-static struct device_driver tb0219_device_driver = {
-	.name		= "TB0219",
-	.bus		= &platform_bus_type,
+static struct platform_driver tb0219_device_driver = {
 	.probe		= tb0219_probe,
 	.remove		= tb0219_remove,
+	.driver		= {
+		.name	= "TB0219",
+	},
 };
 
 static int __devinit tanbac_tb0219_init(void)
@@ -348,7 +349,7 @@
 	if (IS_ERR(tb0219_platform_device))
 		return PTR_ERR(tb0219_platform_device);
 
-	retval = driver_register(&tb0219_device_driver);
+	retval = platform_driver_register(&tb0219_device_driver);
 	if (retval < 0)
 		platform_device_unregister(tb0219_platform_device);
 
@@ -357,7 +358,7 @@
 
 static void __devexit tanbac_tb0219_exit(void)
 {
-	driver_unregister(&tb0219_device_driver);
+	platform_driver_unregister(&tb0219_device_driver);
 
 	platform_device_unregister(tb0219_platform_device);
 }
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 99a6049..9293bcc 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -19,7 +19,6 @@
  * 
  */
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 98601c7..4d75c26 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -26,7 +26,6 @@
  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/errno.h>
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index 867cc4e..60aabdb 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -32,7 +32,6 @@
  * iseries/vio.h
  */
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index 9464108..9ac6d43 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -613,7 +613,7 @@
 	.release	= gpio_release,
 };
 
-static int giu_probe(struct device *dev)
+static int giu_probe(struct platform_device *dev)
 {
 	unsigned long start, size, flags = 0;
 	unsigned int nr_pins = 0;
@@ -697,7 +697,7 @@
 	return cascade_irq(GIUINT_IRQ, giu_get_irq);
 }
 
-static int giu_remove(struct device *dev)
+static int giu_remove(struct platform_device *dev)
 {
 	iounmap(giu_base);
 
@@ -710,11 +710,12 @@
 
 static struct platform_device *giu_platform_device;
 
-static struct device_driver giu_device_driver = {
-	.name		= "GIU",
-	.bus		= &platform_bus_type,
+static struct platform_driver giu_device_driver = {
 	.probe		= giu_probe,
 	.remove		= giu_remove,
+	.driver		= {
+		.name	= "GIU",
+	},
 };
 
 static int __devinit vr41xx_giu_init(void)
@@ -725,7 +726,7 @@
 	if (IS_ERR(giu_platform_device))
 		return PTR_ERR(giu_platform_device);
 
-	retval = driver_register(&giu_device_driver);
+	retval = platform_driver_register(&giu_device_driver);
 	if (retval < 0)
 		platform_device_unregister(giu_platform_device);
 
@@ -734,7 +735,7 @@
 
 static void __devexit vr41xx_giu_exit(void)
 {
-	driver_unregister(&giu_device_driver);
+	platform_driver_unregister(&giu_device_driver);
 
 	platform_device_unregister(giu_platform_device);
 }
diff --git a/drivers/char/vr41xx_rtc.c b/drivers/char/vr41xx_rtc.c
index 5e3292d..435b307 100644
--- a/drivers/char/vr41xx_rtc.c
+++ b/drivers/char/vr41xx_rtc.c
@@ -560,13 +560,11 @@
 	.fops	= &rtc_fops,
 };
 
-static int rtc_probe(struct device *dev)
+static int rtc_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev;
 	unsigned int irq;
 	int retval;
 
-	pdev = to_platform_device(dev);
 	if (pdev->num_resources != 2)
 		return -EBUSY;
 
@@ -635,7 +633,7 @@
 	return 0;
 }
 
-static int rtc_remove(struct device *dev)
+static int rtc_remove(struct platform_device *dev)
 {
 	int retval;
 
@@ -655,11 +653,12 @@
 
 static struct platform_device *rtc_platform_device;
 
-static struct device_driver rtc_device_driver = {
-	.name		= rtc_name,
-	.bus		= &platform_bus_type,
+static struct platform_driver rtc_device_driver = {
 	.probe		= rtc_probe,
 	.remove		= rtc_remove,
+	.driver		= {
+		.name	= rtc_name,
+	},
 };
 
 static int __devinit vr41xx_rtc_init(void)
@@ -691,7 +690,7 @@
 	if (IS_ERR(rtc_platform_device))
 		return PTR_ERR(rtc_platform_device);
 
-	retval = driver_register(&rtc_device_driver);
+	retval = platform_driver_register(&rtc_device_driver);
 	if (retval < 0)
 		platform_device_unregister(rtc_platform_device);
 
@@ -700,7 +699,7 @@
 
 static void __devexit vr41xx_rtc_exit(void)
 {
-	driver_unregister(&rtc_device_driver);
+	platform_driver_unregister(&rtc_device_driver);
 
 	platform_device_unregister(rtc_platform_device);
 }
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index da631c1..9defcf8 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -139,7 +139,7 @@
  */
 static int mpcore_wdt_open(struct inode *inode, struct file *file)
 {
-	struct mpcore_wdt *wdt = dev_get_drvdata(&mpcore_wdt_dev->dev);
+	struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_dev);
 
 	if (test_and_set_bit(0, &wdt->timer_alive))
 		return -EBUSY;
@@ -291,9 +291,9 @@
  *	System shutdown handler.  Turn off the watchdog if we're
  *	restarting or halting the system.
  */
-static void mpcore_wdt_shutdown(struct device *_dev)
+static void mpcore_wdt_shutdown(struct platform_device *dev)
 {
-	struct mpcore_wdt *wdt = dev_get_drvdata(_dev);
+	struct mpcore_wdt *wdt = platform_get_drvdata(dev);
 
 	if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
 		mpcore_wdt_stop(wdt);
@@ -317,9 +317,8 @@
 	.fops		= &mpcore_wdt_fops,
 };
 
-static int __devinit mpcore_wdt_probe(struct device *_dev)
+static int __devinit mpcore_wdt_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(_dev);
 	struct mpcore_wdt *wdt;
 	struct resource *res;
 	int ret;
@@ -364,7 +363,7 @@
 	}
 
 	mpcore_wdt_stop(wdt);
-	dev_set_drvdata(&dev->dev, wdt);
+	platform_set_drvdata(&dev->dev, wdt);
 	mpcore_wdt_dev = dev;
 
 	return 0;
@@ -379,11 +378,11 @@
 	return ret;
 }
 
-static int __devexit mpcore_wdt_remove(struct device *dev)
+static int __devexit mpcore_wdt_remove(struct platform_device *dev)
 {
-	struct mpcore_wdt *wdt = dev_get_drvdata(dev);
+	struct mpcore_wdt *wdt = platform_get_drvdata(dev);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(dev, NULL);
 
 	misc_deregister(&mpcore_wdt_miscdev);
 
@@ -395,13 +394,14 @@
 	return 0;
 }
 
-static struct device_driver mpcore_wdt_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "mpcore_wdt",
-	.bus		= &platform_bus_type,
+static struct platform_driver mpcore_wdt_driver = {
 	.probe		= mpcore_wdt_probe,
 	.remove		= __devexit_p(mpcore_wdt_remove),
 	.shutdown	= mpcore_wdt_shutdown,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "mpcore_wdt",
+	},
 };
 
 static char banner[] __initdata = KERN_INFO "MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n";
@@ -420,12 +420,12 @@
 
 	printk(banner, mpcore_noboot, mpcore_margin, nowayout);
 
-	return driver_register(&mpcore_wdt_driver);
+	return platform_driver_register(&mpcore_wdt_driver);
 }
 
 static void __exit mpcore_wdt_exit(void)
 {
-	driver_unregister(&mpcore_wdt_driver);
+	platform_driver_unregister(&mpcore_wdt_driver);
 }
 
 module_init(mpcore_wdt_init);
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
index 119b3c5..00d9ef0 100644
--- a/drivers/char/watchdog/mv64x60_wdt.c
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -182,10 +182,9 @@
 	.fops = &mv64x60_wdt_fops,
 };
 
-static int __devinit mv64x60_wdt_probe(struct device *dev)
+static int __devinit mv64x60_wdt_probe(struct platform_device *dev)
 {
-	struct platform_device *pd = to_platform_device(dev);
-	struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data;
+	struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data;
 	int bus_clk = 133;
 
 	mv64x60_wdt_timeout = 10;
@@ -202,7 +201,7 @@
 	return misc_register(&mv64x60_wdt_miscdev);
 }
 
-static int __devexit mv64x60_wdt_remove(struct device *dev)
+static int __devexit mv64x60_wdt_remove(struct platform_device *dev)
 {
 	misc_deregister(&mv64x60_wdt_miscdev);
 
@@ -212,12 +211,13 @@
 	return 0;
 }
 
-static struct device_driver mv64x60_wdt_driver = {
-	.owner = THIS_MODULE,
-	.name = MV64x60_WDT_NAME,
-	.bus = &platform_bus_type,
+static struct platform_driver mv64x60_wdt_driver = {
 	.probe = mv64x60_wdt_probe,
 	.remove = __devexit_p(mv64x60_wdt_remove),
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = MV64x60_WDT_NAME,
+	},
 };
 
 static struct platform_device *mv64x60_wdt_dev;
@@ -235,14 +235,14 @@
 		goto out;
 	}
 
-	ret = driver_register(&mv64x60_wdt_driver);
+	ret = platform_driver_register(&mv64x60_wdt_driver);
       out:
 	return ret;
 }
 
 static void __exit mv64x60_wdt_exit(void)
 {
-	driver_unregister(&mv64x60_wdt_driver);
+	platform_driver_unregister(&mv64x60_wdt_driver);
 	platform_device_unregister(mv64x60_wdt_dev);
 }
 
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
index d9ef55b..2451edb 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -755,7 +755,6 @@
 MODULE_DEVICE_TABLE(pci, pcipcwd_pci_tbl);
 
 static struct pci_driver pcipcwd_driver = {
-	.owner		= THIS_MODULE,
 	.name		= WATCHDOG_NAME,
 	.id_table	= pcipcwd_pci_tbl,
 	.probe		= pcipcwd_card_init,
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 751cb77..eb667da 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -347,15 +347,14 @@
 }
 /* device interface */
 
-static int s3c2410wdt_probe(struct device *dev)
+static int s3c2410wdt_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *res;
 	int started = 0;
 	int ret;
 	int size;
 
-	DBG("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev);
+	DBG("%s: probe=%p\n", __FUNCTION__, pdev);
 
 	/* get the memory region for the watchdog timer */
 
@@ -386,13 +385,13 @@
 		return -ENOENT;
 	}
 
-	ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, dev);
+	ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev);
 	if (ret != 0) {
 		printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
 		return ret;
 	}
 
-	wdt_clock = clk_get(dev, "watchdog");
+	wdt_clock = clk_get(&pdev->dev, "watchdog");
 	if (wdt_clock == NULL) {
 		printk(KERN_INFO PFX "failed to find watchdog clock source\n");
 		return -ENOENT;
@@ -430,7 +429,7 @@
 	return 0;
 }
 
-static int s3c2410wdt_remove(struct device *dev)
+static int s3c2410wdt_remove(struct platform_device *dev)
 {
 	if (wdt_mem != NULL) {
 		release_resource(wdt_mem);
@@ -454,7 +453,7 @@
 	return 0;
 }
 
-static void s3c2410wdt_shutdown(struct device *dev)
+static void s3c2410wdt_shutdown(struct platform_device *dev)
 {
 	s3c2410wdt_stop();	
 }
@@ -464,7 +463,7 @@
 static unsigned long wtcon_save;
 static unsigned long wtdat_save;
 
-static int s3c2410wdt_suspend(struct device *dev, pm_message_t state)
+static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)
 {
 	/* Save watchdog state, and turn it off. */
 	wtcon_save = readl(wdt_base + S3C2410_WTCON);
@@ -476,7 +475,7 @@
 	return 0;
 }
 
-static int s3c2410wdt_resume(struct device *dev)
+static int s3c2410wdt_resume(struct platform_device *dev)
 {
 	/* Restore watchdog state. */
 
@@ -496,15 +495,16 @@
 #endif /* CONFIG_PM */
 
 
-static struct device_driver s3c2410wdt_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "s3c2410-wdt",
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2410wdt_driver = {
 	.probe		= s3c2410wdt_probe,
 	.remove		= s3c2410wdt_remove,
 	.shutdown	= s3c2410wdt_shutdown,
 	.suspend	= s3c2410wdt_suspend,
 	.resume		= s3c2410wdt_resume,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "s3c2410-wdt",
+	},
 };
 
 
@@ -513,12 +513,12 @@
 static int __init watchdog_init(void)
 {
 	printk(banner);
-	return driver_register(&s3c2410wdt_driver);
+	return platform_driver_register(&s3c2410wdt_driver);
 }
 
 static void __exit watchdog_exit(void)
 {
-	driver_unregister(&s3c2410wdt_driver);
+	platform_driver_unregister(&s3c2410wdt_driver);
 }
 
 module_init(watchdog_init);
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
index dc9370f..4b33119 100644
--- a/drivers/char/watchdog/wdt_pci.c
+++ b/drivers/char/watchdog/wdt_pci.c
@@ -711,7 +711,6 @@
 
 
 static struct pci_driver wdtpci_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "wdt_pci",
 	.id_table	= wdtpci_pci_tbl,
 	.probe		= wdtpci_init_one,
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 25acf47..23a6320 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -38,7 +38,6 @@
 static struct cpufreq_policy	*cpufreq_cpu_data[NR_CPUS];
 static DEFINE_SPINLOCK(cpufreq_driver_lock);
 
-
 /* internal prototypes */
 static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
 static void handle_update(void *data);
@@ -1115,24 +1114,21 @@
 	int retval = -EINVAL;
 
 	/*
-	 * Converted the lock_cpu_hotplug to preempt_disable()
-	 * and preempt_enable(). This is a bit kludgy and relies on how cpu
-	 * hotplug works. All we need is a guarantee that cpu hotplug won't make
-	 * progress on any cpu. Once we do preempt_disable(), this would ensure
-	 * that hotplug threads don't get onto this cpu, thereby delaying
-	 * the cpu remove process.
-	 *
-	 * We removed the lock_cpu_hotplug since we need to call this function
-	 * via cpu hotplug callbacks, which result in locking the cpu hotplug
-	 * thread itself. Agree this is not very clean, cpufreq community
-	 * could improve this if required. - Ashok Raj <ashok.raj@intel.com>
+	 * If we are already in context of hotplug thread, we dont need to
+	 * acquire the hotplug lock. Otherwise acquire cpucontrol to prevent
+	 * hotplug from removing this cpu that we are working on.
 	 */
-	preempt_disable();
+	if (!current_in_cpu_hotplug())
+		lock_cpu_hotplug();
+
 	dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
 		target_freq, relation);
 	if (cpu_online(policy->cpu) && cpufreq_driver->target)
 		retval = cpufreq_driver->target(policy, target_freq, relation);
-	preempt_enable();
+
+	if (!current_in_cpu_hotplug())
+		unlock_cpu_hotplug();
+
 	return retval;
 }
 EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index ba17292..6d83299 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/firmware/dell_rbu.c
@@ -34,7 +34,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index 1e5dfc7..c81bd4b 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -60,9 +60,11 @@
 
 #define HDAPS_POLL_PERIOD	(HZ/20)	/* poll for input every 1/20s */
 #define HDAPS_INPUT_FUZZ	4	/* input event threshold */
+#define HDAPS_INPUT_FLAT	4
 
 static struct timer_list hdaps_timer;
 static struct platform_device *pdev;
+static struct input_dev *hdaps_idev;
 static unsigned int hdaps_invert;
 static u8 km_activity;
 static int rest_x;
@@ -284,7 +286,7 @@
 
 /* Device model stuff */
 
-static int hdaps_probe(struct device *dev)
+static int hdaps_probe(struct platform_device *dev)
 {
 	int ret;
 
@@ -296,29 +298,18 @@
 	return 0;
 }
 
-static int hdaps_resume(struct device *dev)
+static int hdaps_resume(struct platform_device *dev)
 {
 	return hdaps_device_init();
 }
 
-static struct device_driver hdaps_driver = {
-	.name = "hdaps",
-	.bus = &platform_bus_type,
-	.owner = THIS_MODULE,
+static struct platform_driver hdaps_driver = {
 	.probe = hdaps_probe,
-	.resume = hdaps_resume
-};
-
-/* Input class stuff */
-
-static struct input_dev hdaps_idev = {
-	.name = "hdaps",
-	.evbit = { BIT(EV_ABS) },
-	.absbit = { BIT(ABS_X) | BIT(ABS_Y) },
-	.absmin  = { [ABS_X] = -256, [ABS_Y] = -256 },
-	.absmax  = { [ABS_X] = 256, [ABS_Y] = 256 },
-	.absfuzz = { [ABS_X] = HDAPS_INPUT_FUZZ, [ABS_Y] = HDAPS_INPUT_FUZZ },
-	.absflat = { [ABS_X] = HDAPS_INPUT_FUZZ, [ABS_Y] = HDAPS_INPUT_FUZZ },
+	.resume = hdaps_resume,
+	.driver	= {
+		.name = "hdaps",
+		.owner = THIS_MODULE,
+	},
 };
 
 /*
@@ -342,9 +333,9 @@
 	if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
 		goto out;
 
-	input_report_abs(&hdaps_idev, ABS_X, x - rest_x);
-	input_report_abs(&hdaps_idev, ABS_Y, y - rest_y);
-	input_sync(&hdaps_idev);
+	input_report_abs(hdaps_idev, ABS_X, x - rest_x);
+	input_report_abs(hdaps_idev, ABS_Y, y - rest_y);
+	input_sync(hdaps_idev);
 
 	mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD);
 
@@ -550,7 +541,7 @@
 		goto out;
 	}
 
-	ret = driver_register(&hdaps_driver);
+	ret = platform_driver_register(&hdaps_driver);
 	if (ret)
 		goto out_region;
 
@@ -564,12 +555,25 @@
 	if (ret)
 		goto out_device;
 
+	hdaps_idev = input_allocate_device();
+	if (!hdaps_idev) {
+		ret = -ENOMEM;
+		goto out_group;
+	}
+
 	/* initial calibrate for the input device */
 	hdaps_calibrate();
 
 	/* initialize the input class */
-	hdaps_idev.dev = &pdev->dev;
-	input_register_device(&hdaps_idev);
+	hdaps_idev->name = "hdaps";
+	hdaps_idev->cdev.dev = &pdev->dev;
+	hdaps_idev->evbit[0] = BIT(EV_ABS);
+	input_set_abs_params(hdaps_idev, ABS_X,
+			-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
+	input_set_abs_params(hdaps_idev, ABS_X,
+			-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
+
+	input_register_device(hdaps_idev);
 
 	/* start up our timer for the input device */
 	init_timer(&hdaps_timer);
@@ -580,10 +584,12 @@
 	printk(KERN_INFO "hdaps: driver successfully loaded.\n");
 	return 0;
 
+out_group:
+	sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
 out_device:
 	platform_device_unregister(pdev);
 out_driver:
-	driver_unregister(&hdaps_driver);
+	platform_driver_unregister(&hdaps_driver);
 out_region:
 	release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
 out:
@@ -594,10 +600,10 @@
 static void __exit hdaps_exit(void)
 {
 	del_timer_sync(&hdaps_timer);
-	input_unregister_device(&hdaps_idev);
+	input_unregister_device(hdaps_idev);
 	sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
 	platform_device_unregister(pdev);
-	driver_unregister(&hdaps_driver);
+	platform_driver_unregister(&hdaps_driver);
 	release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
 
 	printk(KERN_INFO "hdaps: driver unloaded.\n");
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 70ef926..4e9a04e 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -180,11 +180,10 @@
 #define W83781D_REG_BANK 0x4E
 
 #define W83781D_REG_CONFIG 0x40
-#define W83781D_REG_ALARM1 0x41
-#define W83781D_REG_ALARM2 0x42
-#define W83781D_REG_ALARM3 0x450
+#define W83781D_REG_ALARM1 0x459
+#define W83781D_REG_ALARM2 0x45A
+#define W83781D_REG_ALARM3 0x45B
 
-#define W83781D_REG_IRQ 0x4C
 #define W83781D_REG_BEEP_CONFIG 0x4D
 #define W83781D_REG_BEEP_INTS1 0x56
 #define W83781D_REG_BEEP_INTS2 0x57
@@ -1370,13 +1369,6 @@
 					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
 			}
 		}
-
-		/* enable comparator mode for temp2 and temp3 so
-	           alarm indication will work correctly */
-		i = w83627hf_read_value(client, W83781D_REG_IRQ);
-		if (!(i & 0x40))
-			w83627hf_write_value(client, W83781D_REG_IRQ,
-					    i | 0x40);
 	}
 
 	/* Start monitoring */
@@ -1400,7 +1392,7 @@
 			/* skip missing sensors */
 			if (((data->type == w83697hf) && (i == 1)) ||
 			    ((data->type == w83627thf || data->type == w83637hf)
-			    && (i == 4 || i == 5)))
+			    && (i == 5 || i == 6)))
 				continue;
 			data->in[i] =
 			    w83627hf_read_value(client, W83781D_REG_IN(i));
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index ba90f51..3eb4789 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -513,7 +513,6 @@
 }
 
 static struct pci_driver ali1535_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "ali1535_smbus",
 	.id_table	= ali1535_ids,
 	.probe		= ali1535_probe,
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index f1a62d8..e6f6320 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -408,7 +408,6 @@
 MODULE_DEVICE_TABLE (pci, ali1563_id_table);
 
 static struct pci_driver ali1563_pci_driver = {
-	.owner		= THIS_MODULE,
  	.name		= "ali1563_smbus",
 	.id_table	= ali1563_id_table,
  	.probe		= ali1563_probe,
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 400b08e..7a5c094 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -504,7 +504,6 @@
 }
 
 static struct pci_driver ali15x3_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "ali15x3_smbus",
 	.id_table	= ali15x3_ids,
 	.probe		= ali15x3_probe,
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index de035d1..1750ded 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -401,7 +401,6 @@
 }
 
 static struct pci_driver amd756_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "amd756_smbus",
 	.id_table	= amd756_ids,
 	.probe		= amd756_probe,
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index f3b79a6..e5ef560 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -384,7 +384,6 @@
 }
 
 static struct pci_driver amd8111_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "amd8111_smbus2",
 	.id_table	= amd8111_ids,
 	.probe		= amd8111_probe,
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index 1b5354e..e0cb3b0 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -155,7 +155,6 @@
 
 
 static struct pci_driver hydra_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "hydra_smbus",
 	.id_table	= hydra_ids,
 	.probe		= hydra_probe,
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 4f631950..ac3eafa 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -560,7 +560,6 @@
 }
 
 static struct pci_driver i801_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "i801_smbus",
 	.id_table	= i801_ids,
 	.probe		= i801_probe,
diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c
index 52bc305..748be30 100644
--- a/drivers/i2c/busses/i2c-i810.c
+++ b/drivers/i2c/busses/i2c-i810.c
@@ -233,7 +233,6 @@
 }
 
 static struct pci_driver i810_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "i810_smbus",
 	.id_table	= i810_ids,
 	.probe		= i810_probe,
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index cfae4ad..1414851 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -405,10 +405,9 @@
 };
 
 static int 
-iop3xx_i2c_remove(struct device *device)
+iop3xx_i2c_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(device);
-	struct i2c_adapter *padapter = dev_get_drvdata(&pdev->dev);
+	struct i2c_adapter *padapter = platform_get_drvdata(pdev);
 	struct i2c_algo_iop3xx_data *adapter_data = 
 		(struct i2c_algo_iop3xx_data *)padapter->algo_data;
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -426,15 +425,14 @@
 	kfree(adapter_data);
 	kfree(padapter);
 
-	dev_set_drvdata(&pdev->dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	return 0;
 }
 
 static int 
-iop3xx_i2c_probe(struct device *dev)
+iop3xx_i2c_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *res;
 	int ret;
 	struct i2c_adapter *new_adapter;
@@ -499,7 +497,7 @@
 	iop3xx_i2c_set_slave_addr(adapter_data);
 	iop3xx_i2c_enable(adapter_data);
 
-	dev_set_drvdata(&pdev->dev, new_adapter);
+	platform_set_drvdata(pdev, new_adapter);
 	new_adapter->algo_data = adapter_data;
 
 	i2c_add_adapter(new_adapter);
@@ -523,24 +521,25 @@
 }
 
 
-static struct device_driver iop3xx_i2c_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "IOP3xx-I2C",
-	.bus		= &platform_bus_type,
+static struct platform_driver iop3xx_i2c_driver = {
 	.probe		= iop3xx_i2c_probe,
-	.remove		= iop3xx_i2c_remove
+	.remove		= iop3xx_i2c_remove,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "IOP3xx-I2C",
+	},
 };
 
 static int __init 
 i2c_iop3xx_init (void)
 {
-	return driver_register(&iop3xx_i2c_driver);
+	return platform_driver_register(&iop3xx_i2c_driver);
 }
 
 static void __exit 
 i2c_iop3xx_exit (void)
 {
-	driver_unregister(&iop3xx_i2c_driver);
+	platform_driver_unregister(&iop3xx_i2c_driver);
 	return;
 }
 
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index 64552a3..cef024a 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -86,12 +86,11 @@
 	struct i2c_algo_bit_data algo_data;
 };
 
-static int ixp2000_i2c_remove(struct device *dev)
+static int ixp2000_i2c_remove(struct platform_device *plat_dev)
 {
-	struct platform_device *plat_dev = to_platform_device(dev);
-	struct ixp2000_i2c_data *drv_data = dev_get_drvdata(&plat_dev->dev);
+	struct ixp2000_i2c_data *drv_data = platform_get_drvdata(plat_dev);
 
-	dev_set_drvdata(&plat_dev->dev, NULL);
+	platform_set_drvdata(plat_dev, NULL);
 
 	i2c_bit_del_bus(&drv_data->adapter);
 
@@ -100,10 +99,9 @@
 	return 0;
 }
 
-static int ixp2000_i2c_probe(struct device *dev)
+static int ixp2000_i2c_probe(struct platform_device *plat_dev)
 {
 	int err;
-	struct platform_device *plat_dev = to_platform_device(dev);
 	struct ixp2000_i2c_pins *gpio = plat_dev->dev.platform_data;
 	struct ixp2000_i2c_data *drv_data = 
 		kzalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL);
@@ -139,27 +137,28 @@
 		return err;
 	} 
 
-	dev_set_drvdata(&plat_dev->dev, drv_data);
+	platform_set_drvdata(plat_dev, drv_data);
 
 	return 0;
 }
 
-static struct device_driver ixp2000_i2c_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "IXP2000-I2C",
-	.bus		= &platform_bus_type,
+static struct platform_driver ixp2000_i2c_driver = {
 	.probe		= ixp2000_i2c_probe,
 	.remove		= ixp2000_i2c_remove,
+	.driver		= {
+		.name	= "IXP2000-I2C",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static int __init ixp2000_i2c_init(void)
 {
-	return driver_register(&ixp2000_i2c_driver);
+	return platform_driver_register(&ixp2000_i2c_driver);
 }
 
 static void __exit ixp2000_i2c_exit(void)
 {
-	driver_unregister(&ixp2000_i2c_driver);
+	platform_driver_unregister(&ixp2000_i2c_driver);
 }
 
 module_init(ixp2000_i2c_init);
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
index cc652c3..aa36855 100644
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ b/drivers/i2c/busses/i2c-ixp4xx.c
@@ -87,12 +87,11 @@
 	struct i2c_algo_bit_data algo_data;
 };
 
-static int ixp4xx_i2c_remove(struct device *dev)
+static int ixp4xx_i2c_remove(struct platform_device *plat_dev)
 {
-	struct platform_device *plat_dev = to_platform_device(dev);
-	struct ixp4xx_i2c_data *drv_data = dev_get_drvdata(&plat_dev->dev);
+	struct ixp4xx_i2c_data *drv_data = platform_get_drvdata(plat_dev);
 
-	dev_set_drvdata(&plat_dev->dev, NULL);
+	platform_set_drvdata(plat_dev, NULL);
 
 	i2c_bit_del_bus(&drv_data->adapter);
 
@@ -101,10 +100,9 @@
 	return 0;
 }
 
-static int ixp4xx_i2c_probe(struct device *dev)
+static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
 {
 	int err;
-	struct platform_device *plat_dev = to_platform_device(dev);
 	struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data;
 	struct ixp4xx_i2c_data *drv_data = 
 		kzalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL);
@@ -148,27 +146,28 @@
 		return err;
 	}
 
-	dev_set_drvdata(&plat_dev->dev, drv_data);
+	platform_set_drvdata(plat_dev, drv_data);
 
 	return 0;
 }
 
-static struct device_driver ixp4xx_i2c_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "IXP4XX-I2C",
-	.bus		= &platform_bus_type,
+static struct platform_driver ixp4xx_i2c_driver = {
 	.probe		= ixp4xx_i2c_probe,
 	.remove		= ixp4xx_i2c_remove,
+	.driver		= {
+		.name	= "IXP4XX-I2C",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static int __init ixp4xx_i2c_init(void)
 {
-	return driver_register(&ixp4xx_i2c_driver);
+	return platform_driver_register(&ixp4xx_i2c_driver);
 }
 
 static void __exit ixp4xx_i2c_exit(void)
 {
-	driver_unregister(&ixp4xx_i2c_driver);
+	platform_driver_unregister(&ixp4xx_i2c_driver);
 }
 
 module_init(ixp4xx_i2c_init);
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 65b939a..5ccd338 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -288,11 +288,10 @@
 	.retries = 1
 };
 
-static int fsl_i2c_probe(struct device *device)
+static int fsl_i2c_probe(struct platform_device *pdev)
 {
 	int result = 0;
 	struct mpc_i2c *i2c;
-	struct platform_device *pdev = to_platform_device(device);
 	struct fsl_i2c_platform_data *pdata;
 	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
@@ -323,7 +322,7 @@
 		}
 
 	mpc_i2c_setclock(i2c);
-	dev_set_drvdata(device, i2c);
+	platform_set_drvdata(pdev, i2c);
 
 	i2c->adap = mpc_ops;
 	i2c_set_adapdata(&i2c->adap, i2c);
@@ -345,12 +344,12 @@
 	return result;
 };
 
-static int fsl_i2c_remove(struct device *device)
+static int fsl_i2c_remove(struct platform_device *pdev)
 {
-	struct mpc_i2c *i2c = dev_get_drvdata(device);
+	struct mpc_i2c *i2c = platform_get_drvdata(pdev);
 
 	i2c_del_adapter(&i2c->adap);
-	dev_set_drvdata(device, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	if (i2c->irq != 0)
 		free_irq(i2c->irq, i2c);
@@ -361,22 +360,23 @@
 };
 
 /* Structure for a device driver */
-static struct device_driver fsl_i2c_driver = {
-	.owner = THIS_MODULE,
-	.name = "fsl-i2c",
-	.bus = &platform_bus_type,
+static struct platform_driver fsl_i2c_driver = {
 	.probe = fsl_i2c_probe,
 	.remove = fsl_i2c_remove,
+	.driver	= {
+		.owner = THIS_MODULE,
+		.name = "fsl-i2c",
+	},
 };
 
 static int __init fsl_i2c_init(void)
 {
-	return driver_register(&fsl_i2c_driver);
+	return platform_driver_register(&fsl_i2c_driver);
 }
 
 static void __exit fsl_i2c_exit(void)
 {
-	driver_unregister(&fsl_i2c_driver);
+	platform_driver_unregister(&fsl_i2c_driver);
 }
 
 module_init(fsl_i2c_init);
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 6b48027..afd7634 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -492,11 +492,10 @@
 }
 
 static int __devinit
-mv64xxx_i2c_probe(struct device *dev)
+mv64xxx_i2c_probe(struct platform_device *pd)
 {
-	struct platform_device		*pd = to_platform_device(dev);
 	struct mv64xxx_i2c_data		*drv_data;
-	struct mv64xxx_i2c_pdata	*pdata = dev->platform_data;
+	struct mv64xxx_i2c_pdata	*pdata = pd->dev.platform_data;
 	int	rc;
 
 	if ((pd->id != 0) || !pdata)
@@ -526,7 +525,7 @@
 	drv_data->adapter.class = I2C_CLASS_HWMON;
 	drv_data->adapter.timeout = pdata->timeout;
 	drv_data->adapter.retries = pdata->retries;
-	dev_set_drvdata(dev, drv_data);
+	platform_set_drvdata(pd, drv_data);
 	i2c_set_adapdata(&drv_data->adapter, drv_data);
 
 	if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
@@ -555,9 +554,9 @@
 }
 
 static int __devexit
-mv64xxx_i2c_remove(struct device *dev)
+mv64xxx_i2c_remove(struct platform_device *dev)
 {
-	struct mv64xxx_i2c_data		*drv_data = dev_get_drvdata(dev);
+	struct mv64xxx_i2c_data		*drv_data = platform_get_drvdata(dev);
 	int	rc;
 
 	rc = i2c_del_adapter(&drv_data->adapter);
@@ -568,24 +567,25 @@
 	return rc;
 }
 
-static struct device_driver mv64xxx_i2c_driver = {
-	.owner	= THIS_MODULE,
-	.name	= MV64XXX_I2C_CTLR_NAME,
-	.bus	= &platform_bus_type,
+static struct platform_driver mv64xxx_i2c_driver = {
 	.probe	= mv64xxx_i2c_probe,
 	.remove	= mv64xxx_i2c_remove,
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= MV64XXX_I2C_CTLR_NAME,
+	},
 };
 
 static int __init
 mv64xxx_i2c_init(void)
 {
-	return driver_register(&mv64xxx_i2c_driver);
+	return platform_driver_register(&mv64xxx_i2c_driver);
 }
 
 static void __exit
 mv64xxx_i2c_exit(void)
 {
-	driver_unregister(&mv64xxx_i2c_driver);
+	platform_driver_unregister(&mv64xxx_i2c_driver);
 }
 
 module_init(mv64xxx_i2c_init);
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index fd26036..4d18e6e5 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -347,7 +347,6 @@
 }
 
 static struct pci_driver nforce2_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "nForce2_smbus",
 	.id_table	= nforce2_ids,
 	.probe		= nforce2_probe,
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 7d63eec..692f473 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -462,7 +462,6 @@
 }
 
 static struct pci_driver piix4_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "piix4_smbus",
 	.id_table	= piix4_ids,
 	.probe		= piix4_probe,
diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c
index 42cb1d8..9479525 100644
--- a/drivers/i2c/busses/i2c-prosavage.c
+++ b/drivers/i2c/busses/i2c-prosavage.c
@@ -301,7 +301,6 @@
 MODULE_DEVICE_TABLE (pci, prosavage_pci_tbl);
 
 static struct pci_driver prosavage_driver = {
-	.owner		=	THIS_MODULE,
 	.name		=	"prosavage_smbus",
 	.id_table	=	prosavage_pci_tbl,
 	.probe		=	prosavage_probe,
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 67ccbea..70f7ab8 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -936,10 +936,10 @@
 	},
 };
 
-static int i2c_pxa_probe(struct device *dev)
+static int i2c_pxa_probe(struct platform_device *dev)
 {
 	struct pxa_i2c *i2c = &i2c_pxa;
-	struct i2c_pxa_platform_data *plat = dev->platform_data;
+	struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
 	int ret;
 
 #ifdef CONFIG_PXA27x
@@ -968,7 +968,7 @@
 	i2c_pxa_reset(i2c);
 
 	i2c->adap.algo_data = i2c;
-	i2c->adap.dev.parent = dev;
+	i2c->adap.dev.parent = &dev->dev;
 
 	ret = i2c_add_adapter(&i2c->adap);
 	if (ret < 0) {
@@ -976,7 +976,7 @@
 		goto err_irq;
 	}
 
-	dev_set_drvdata(dev, i2c);
+	platform_set_drvdata(dev, i2c);
 
 #ifdef CONFIG_I2C_PXA_SLAVE
 	printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n",
@@ -993,11 +993,11 @@
 	return ret;
 }
 
-static int i2c_pxa_remove(struct device *dev)
+static int i2c_pxa_remove(struct platform_device *dev)
 {
-	struct pxa_i2c *i2c = dev_get_drvdata(dev);
+	struct pxa_i2c *i2c = platform_get_drvdata(dev);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(dev, NULL);
 
 	i2c_del_adapter(&i2c->adap);
 	free_irq(IRQ_I2C, i2c);
@@ -1006,21 +1006,22 @@
 	return 0;
 }
 
-static struct device_driver i2c_pxa_driver = {
-	.name		= "pxa2xx-i2c",
-	.bus		= &platform_bus_type,
+static struct platform_driver i2c_pxa_driver = {
 	.probe		= i2c_pxa_probe,
 	.remove		= i2c_pxa_remove,
+	.driver		= {
+		.name	= "pxa2xx-i2c",
+	},
 };
 
 static int __init i2c_adap_pxa_init(void)
 {
-	return driver_register(&i2c_pxa_driver);
+	return platform_driver_register(&i2c_pxa_driver);
 }
 
 static void i2c_adap_pxa_exit(void)
 {
-	return driver_unregister(&i2c_pxa_driver);
+	return platform_driver_unregister(&i2c_pxa_driver);
 }
 
 module_init(i2c_adap_pxa_init);
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 1b58226..58cfd31 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -760,24 +760,23 @@
  * called by the bus driver when a suitable device is found
 */
 
-static int s3c24xx_i2c_probe(struct device *dev)
+static int s3c24xx_i2c_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct s3c24xx_i2c *i2c = &s3c24xx_i2c;
 	struct resource *res;
 	int ret;
 
 	/* find the clock and enable it */
 
-	i2c->dev = dev;
-	i2c->clk = clk_get(dev, "i2c");
+	i2c->dev = &pdev->dev;
+	i2c->clk = clk_get(&pdev->dev, "i2c");
 	if (IS_ERR(i2c->clk)) {
-		dev_err(dev, "cannot get clock\n");
+		dev_err(&pdev->dev, "cannot get clock\n");
 		ret = -ENOENT;
 		goto out;
 	}
 
-	dev_dbg(dev, "clock source %p\n", i2c->clk);
+	dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
 
 	clk_use(i2c->clk);
 	clk_enable(i2c->clk);
@@ -786,7 +785,7 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL) {
-		dev_err(dev, "cannot find IO resource\n");
+		dev_err(&pdev->dev, "cannot find IO resource\n");
 		ret = -ENOENT;
 		goto out;
 	}
@@ -795,7 +794,7 @@
 					 pdev->name);
 
 	if (i2c->ioarea == NULL) {
-		dev_err(dev, "cannot request IO\n");
+		dev_err(&pdev->dev, "cannot request IO\n");
 		ret = -ENXIO;
 		goto out;
 	}
@@ -803,17 +802,17 @@
 	i2c->regs = ioremap(res->start, (res->end-res->start)+1);
 
 	if (i2c->regs == NULL) {
-		dev_err(dev, "cannot map IO\n");
+		dev_err(&pdev->dev, "cannot map IO\n");
 		ret = -ENXIO;
 		goto out;
 	}
 
-	dev_dbg(dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
+	dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
 
 	/* setup info block for the i2c core */
 
 	i2c->adap.algo_data = i2c;
-	i2c->adap.dev.parent = dev;
+	i2c->adap.dev.parent = &pdev->dev;
 
 	/* initialise the i2c controller */
 
@@ -827,7 +826,7 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (res == NULL) {
-		dev_err(dev, "cannot find IRQ\n");
+		dev_err(&pdev->dev, "cannot find IRQ\n");
 		ret = -ENOENT;
 		goto out;
 	}
@@ -836,23 +835,23 @@
 			  pdev->name, i2c);
 
 	if (ret != 0) {
-		dev_err(dev, "cannot claim IRQ\n");
+		dev_err(&pdev->dev, "cannot claim IRQ\n");
 		goto out;
 	}
 
 	i2c->irq = res;
 		
-	dev_dbg(dev, "irq resource %p (%ld)\n", res, res->start);
+	dev_dbg(&pdev->dev, "irq resource %p (%ld)\n", res, res->start);
 
 	ret = i2c_add_adapter(&i2c->adap);
 	if (ret < 0) {
-		dev_err(dev, "failed to add bus to i2c core\n");
+		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
 		goto out;
 	}
 
-	dev_set_drvdata(dev, i2c);
+	platform_set_drvdata(pdev, i2c);
 
-	dev_info(dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
+	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
 
  out:
 	if (ret < 0)
@@ -866,22 +865,22 @@
  * called when device is removed from the bus
 */
 
-static int s3c24xx_i2c_remove(struct device *dev)
+static int s3c24xx_i2c_remove(struct platform_device *pdev)
 {
-	struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
+	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
 	
 	if (i2c != NULL) {
 		s3c24xx_i2c_free(i2c);
-		dev_set_drvdata(dev, NULL);
+		platform_set_drvdata(pdev, NULL);
 	}
 
 	return 0;
 }
 
 #ifdef CONFIG_PM
-static int s3c24xx_i2c_resume(struct device *dev)
+static int s3c24xx_i2c_resume(struct platform_device *dev)
 {
-	struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
+	struct s3c24xx_i2c *i2c = platform_get_drvdata(dev);
 
 	if (i2c != NULL)
 		s3c24xx_i2c_init(i2c);
@@ -895,33 +894,35 @@
 
 /* device driver for platform bus bits */
 
-static struct device_driver s3c2410_i2c_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "s3c2410-i2c",
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2410_i2c_driver = {
 	.probe		= s3c24xx_i2c_probe,
 	.remove		= s3c24xx_i2c_remove,
 	.resume		= s3c24xx_i2c_resume,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "s3c2410-i2c",
+	},
 };
 
-static struct device_driver s3c2440_i2c_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "s3c2440-i2c",
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2440_i2c_driver = {
 	.probe		= s3c24xx_i2c_probe,
 	.remove		= s3c24xx_i2c_remove,
 	.resume		= s3c24xx_i2c_resume,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "s3c2440-i2c",
+	},
 };
 
 static int __init i2c_adap_s3c_init(void)
 {
 	int ret;
 
-	ret = driver_register(&s3c2410_i2c_driver);
+	ret = platform_driver_register(&s3c2410_i2c_driver);
 	if (ret == 0) {
-		ret = driver_register(&s3c2440_i2c_driver);
+		ret = platform_driver_register(&s3c2440_i2c_driver);
 		if (ret)
-			driver_unregister(&s3c2410_i2c_driver);
+			platform_driver_unregister(&s3c2410_i2c_driver);
 	}
 
 	return ret;
@@ -929,8 +930,8 @@
 
 static void __exit i2c_adap_s3c_exit(void)
 {
-	driver_unregister(&s3c2410_i2c_driver);
-	driver_unregister(&s3c2440_i2c_driver);
+	platform_driver_unregister(&s3c2410_i2c_driver);
+	platform_driver_unregister(&s3c2440_i2c_driver);
 }
 
 module_init(i2c_adap_s3c_init);
diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c
index aebe87b..0c85182 100644
--- a/drivers/i2c/busses/i2c-savage4.c
+++ b/drivers/i2c/busses/i2c-savage4.c
@@ -179,7 +179,6 @@
 }
 
 static struct pci_driver savage4_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "savage4_smbus",
 	.id_table	= savage4_ids,
 	.probe		= savage4_probe,
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 3ad27c3..b57ab74d 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -398,7 +398,6 @@
 }
 
 static struct pci_driver sis5595_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "sis5595_smbus",
 	.id_table	= sis5595_ids,
 	.probe		= sis5595_probe,
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index 7f49e5f..acb75e2 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -496,7 +496,6 @@
 
 
 static struct pci_driver sis630_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "sis630_smbus",
 	.id_table	= sis630_ids,
 	.probe		= sis630_probe,
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 6a134c0..3024907 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -329,7 +329,6 @@
 }
 
 static struct pci_driver sis96x_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "sis96x_smbus",
 	.id_table	= sis96x_ids,
 	.probe		= sis96x_probe,
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 544a38e..484bbac 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -159,7 +159,6 @@
 
 
 static struct pci_driver vt586b_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "vt586b_smbus",
 	.id_table	= vt586b_ids,
 	.probe		= vt586b_probe,
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index c9366b5..47e52bf 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -142,19 +142,18 @@
 	/* Make sure the SMBus host is ready to start transmitting */
 	if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
 		dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
-			"Resetting... ", temp);
+			"Resetting...\n", temp);
 
 		outb_p(temp, SMBHSTSTS);
 		if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
-			printk("Failed! (0x%02x)\n", temp);
+			dev_err(&vt596_adapter.dev, "SMBus reset failed! "
+				"(0x%02x)\n", temp);
 			return -1;
-		} else {
-			printk("Successful!\n");
 		}
 	}
 
 	/* Start the transaction by setting bit 6 */
-	outb_p(0x40 | (size & 0x3C), SMBHSTCNT);
+	outb_p(0x40 | size, SMBHSTCNT);
 
 	/* We will always wait for a fraction of a second */
 	do {
@@ -171,7 +170,7 @@
 	if (temp & 0x10) {
 		result = -1;
 		dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n",
-			inb_p(SMBHSTCNT) & 0x3C);
+			size);
 	}
 
 	if (temp & 0x08) {
@@ -180,11 +179,13 @@
 	}
 
 	if (temp & 0x04) {
+		int read = inb_p(SMBHSTADD) & 0x01;
 		result = -1;
-		/* Quick commands are used to probe for chips, so
-		   errors are expected, and we don't want to frighten the
-		   user. */
-		if ((inb_p(SMBHSTCNT) & 0x3C) != VT596_QUICK)
+		/* The quick and receive byte commands are used to probe
+		   for chips, so errors are expected, and we don't want
+		   to frighten the user. */
+		if (!((size == VT596_QUICK && !read) ||
+		      (size == VT596_BYTE && read)))
 			dev_err(&vt596_adapter.dev, "Transaction error!\n");
 	}
 
@@ -439,7 +440,6 @@
 MODULE_DEVICE_TABLE(pci, vt596_ids);
 
 static struct pci_driver vt596_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "vt596_smbus",
 	.id_table	= vt596_ids,
 	.probe		= vt596_probe,
@@ -462,9 +462,9 @@
 	}
 }
 
-MODULE_AUTHOR(
-    "Frodo Looijaard <frodol@dds.nl> and "
-    "Philip Edelbrock <phil@netroedge.com>");
+MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, "
+	      "Mark D. Studebaker <mdsxyz123@yahoo.com> and "
+	      "Jean Delvare <khali@linux-fr.org>");
 MODULE_DESCRIPTION("vt82c596 SMBus driver");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
index 650c3eb..b675773 100644
--- a/drivers/i2c/busses/i2c-voodoo3.c
+++ b/drivers/i2c/busses/i2c-voodoo3.c
@@ -225,7 +225,6 @@
 }
 
 static struct pci_driver voodoo3_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "voodoo3_smbus",
 	.id_table	= voodoo3_ids,
 	.probe		= voodoo3_probe,
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
index 01b0370..02682fb 100644
--- a/drivers/i2c/chips/ds1337.c
+++ b/drivers/i2c/chips/ds1337.c
@@ -164,9 +164,9 @@
 	buf[1] = BIN2BCD(dt->tm_sec);
 	buf[2] = BIN2BCD(dt->tm_min);
 	buf[3] = BIN2BCD(dt->tm_hour);
-	buf[4] = BIN2BCD(dt->tm_wday) + 1;
+	buf[4] = BIN2BCD(dt->tm_wday + 1);
 	buf[5] = BIN2BCD(dt->tm_mday);
-	buf[6] = BIN2BCD(dt->tm_mon) + 1;
+	buf[6] = BIN2BCD(dt->tm_mon + 1);
 	val = dt->tm_year;
 	if (val >= 100) {
 		val -= 100;
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index 9dbb72f..d2a100d 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -873,26 +873,27 @@
 	return 0;
 }
 
-static int otg_probe(struct device *dev)
+static int otg_probe(struct platform_device *dev)
 {
 	// struct omap_usb_config *config = dev->platform_data;
 
-	otg_dev = to_platform_device(dev);
+	otg_dev = dev;
 	return 0;
 }
 
-static int otg_remove(struct device *dev)
+static int otg_remove(struct platform_device *dev)
 {
 	otg_dev = 0;
 	return 0;
 }
 
-struct device_driver omap_otg_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "omap_otg",
-	.bus		= &platform_bus_type,
+struct platform_driver omap_otg_driver = {
 	.probe		= otg_probe,
-	.remove		= otg_remove,	
+	.remove		= otg_remove,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "omap_otg",
+	},
 };
 
 static int otg_bind(struct isp1301 *isp)
@@ -902,7 +903,7 @@
 	if (otg_dev)
 		return -EBUSY;
 
-	status = driver_register(&omap_otg_driver);
+	status = platform_driver_register(&omap_otg_driver);
 	if (status < 0)
 		return status;
 
@@ -913,7 +914,7 @@
 		status = -ENODEV;
 
 	if (status < 0)
-		driver_unregister(&omap_otg_driver);
+		platform_driver_unregister(&omap_otg_driver);
 	return status;
 }
 
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index a737886..42e5b81 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -539,6 +539,15 @@
 
 	  It is safe to say Y to this question.
 
+config BLK_DEV_CS5535
+	tristate "AMD CS5535 chipset support"
+	depends on X86 && !X86_64
+	help
+	  Include support for UDMA on the NSC/AMD CS5535 companion chipset.
+	  This will automatically be detected and configured if found.
+
+	  It is safe to say Y to this question.
+
 config BLK_DEV_HPT34X
 	tristate "HPT34X chipset support"
 	help
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index e83f54d..f615ab7 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -2038,11 +2038,9 @@
 	struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
 	ide_drive_t *drive = floppy->drive;
 	void __user *argp = (void __user *)arg;
-	int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+	int err;
 	int prevent = (arg) ? 1 : 0;
 	idefloppy_pc_t pc;
-	if (err != -EINVAL)
-		return err;
 
 	switch (cmd) {
 	case CDROMEJECT:
@@ -2094,7 +2092,7 @@
 	case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
 		return idefloppy_get_format_progress(drive, argp);
 	}
- 	return -EINVAL;
+	return generic_ide_ioctl(drive, file, bdev, cmd, arg);
 }
 
 static int idefloppy_media_changed(struct gendisk *disk)
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 0b0aa4f..af7af95 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -104,8 +104,6 @@
 	hwif->INSL	= ide_insl;
 }
 
-EXPORT_SYMBOL(default_hwif_iops);
-
 /*
  *	MMIO operations, typically used for SATA controllers
  */
@@ -329,8 +327,6 @@
 	hwif->atapi_output_bytes	= atapi_output_bytes;
 }
 
-EXPORT_SYMBOL(default_hwif_transport);
-
 /*
  * Beginning of Taskfile OPCODE Library and feature sets.
  */
@@ -529,8 +525,6 @@
 	return 0;
 }
 
-EXPORT_SYMBOL(wait_for_ready);
-
 /*
  * This routine busy-waits for the drive status to be not "busy".
  * It then checks the status for all of the "good" bits and none
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 7ec18fa..54f9639 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -161,8 +161,6 @@
 	return ide_stopped;
 }
 
-EXPORT_SYMBOL(do_rw_taskfile);
-
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 9fe1980..8af179b 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -803,6 +803,7 @@
 	hwif->irq = hw->irq;
 	hwif->noprobe = 0;
 	hwif->chipset = hw->chipset;
+	hwif->gendev.parent = hw->dev;
 
 	if (!initializing) {
 		probe_hwif_init_with_fixup(hwif, fixup);
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 1dafffa..ef79805 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -182,13 +182,14 @@
     
 } /* ide_detach */
 
-static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq)
+static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle)
 {
     hw_regs_t hw;
     memset(&hw, 0, sizeof(hw));
     ide_init_hwif_ports(&hw, io, ctl, NULL);
     hw.irq = irq;
     hw.chipset = ide_pci;
+    hw.dev = &handle->dev;
     return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
 }
 
@@ -327,12 +328,12 @@
 
     /* retry registration in case device is still spinning up */
     for (hd = -1, i = 0; i < 10; i++) {
-	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
+	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, handle);
 	if (hd >= 0) break;
 	if (link->io.NumPorts1 == 0x20) {
 	    outb(0x02, ctl_base + 0x10);
 	    hd = idecs_register(io_base + 0x10, ctl_base + 0x10,
-				link->irq.AssignedIRQ);
+				link->irq.AssignedIRQ, handle);
 	    if (hd >= 0) {
 		io_base += 0x10;
 		ctl_base += 0x10;
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index af46226..f35d684 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_BLK_DEV_CMD64X)		+= cmd64x.o
 obj-$(CONFIG_BLK_DEV_CS5520)		+= cs5520.o
 obj-$(CONFIG_BLK_DEV_CS5530)		+= cs5530.o
+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_HPT34X)		+= hpt34x.o
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 844a6c9..21965e5 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -74,6 +74,7 @@
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,	0x50, AMD_UDMA_133 },
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,	0x50, AMD_UDMA_133 },
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE,	0x50, AMD_UDMA_133 },
+	{ PCI_DEVICE_ID_AMD_CS5536_IDE,			0x40, AMD_UDMA_100 },
 	{ 0 }
 };
 
@@ -491,6 +492,7 @@
 	/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
 	/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
 	/* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
+	/* 17 */ DECLARE_AMD_DEV("AMD5536"),
 };
 
 static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -527,6 +529,7 @@
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
+	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_CS5536_IDE,		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
new file mode 100644
index 0000000..6eb3051
--- /dev/null
+++ b/drivers/ide/pci/cs5535.c
@@ -0,0 +1,305 @@
+/*
+ * linux/drivers/ide/pci/cs5535.c
+ *
+ * Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * History:
+ * 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com>
+ * - Reworked tuneproc, set_drive, misc mods to prep for mainline
+ * - Work was sponsored by CIS (M) Sdn Bhd.
+ * Ported to Kernel 2.6.11 on June 26, 2005 by
+ *   Wolfgang Zuleger <wolfgang.zuleger@gmx.de>
+ *   Alexander Kiausch <alex.kiausch@t-online.de>
+ * Originally developed by AMD for 2.4/2.6
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor/AMD.
+ *
+ * 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.
+ *
+ * Documentation:
+ *  CS5535 documentation available from AMD
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include "ide-timing.h"
+
+#define MSR_ATAC_BASE		0x51300000
+#define ATAC_GLD_MSR_CAP	(MSR_ATAC_BASE+0)
+#define ATAC_GLD_MSR_CONFIG	(MSR_ATAC_BASE+0x01)
+#define ATAC_GLD_MSR_SMI	(MSR_ATAC_BASE+0x02)
+#define ATAC_GLD_MSR_ERROR	(MSR_ATAC_BASE+0x03)
+#define ATAC_GLD_MSR_PM		(MSR_ATAC_BASE+0x04)
+#define ATAC_GLD_MSR_DIAG	(MSR_ATAC_BASE+0x05)
+#define ATAC_IO_BAR		(MSR_ATAC_BASE+0x08)
+#define ATAC_RESET		(MSR_ATAC_BASE+0x10)
+#define ATAC_CH0D0_PIO		(MSR_ATAC_BASE+0x20)
+#define ATAC_CH0D0_DMA		(MSR_ATAC_BASE+0x21)
+#define ATAC_CH0D1_PIO		(MSR_ATAC_BASE+0x22)
+#define ATAC_CH0D1_DMA		(MSR_ATAC_BASE+0x23)
+#define ATAC_PCI_ABRTERR	(MSR_ATAC_BASE+0x24)
+#define ATAC_BM0_CMD_PRIM	0x00
+#define ATAC_BM0_STS_PRIM	0x02
+#define ATAC_BM0_PRD		0x04
+#define CS5535_CABLE_DETECT	0x48
+
+/* Format I PIO settings. We seperate out cmd and data for safer timings */
+
+static unsigned int cs5535_pio_cmd_timings[5] =
+{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 };
+static unsigned int cs5535_pio_dta_timings[5] =
+{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 };
+
+static unsigned int cs5535_mwdma_timings[3] =
+{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 };
+
+static unsigned int cs5535_udma_timings[5] =
+{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 };
+
+/* Macros to check if the register is the reset value -  reset value is an
+   invalid timing and indicates the register has not been set previously */
+
+#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 )
+#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 )
+
+/****
+ *	cs5535_set_speed         -     Configure the chipset to the new speed
+ *	@drive: Drive to set up
+ *	@speed: desired speed
+ *
+ *	cs5535_set_speed() configures the chipset to a new speed.
+ */
+static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
+{
+
+	u32 reg = 0, dummy;
+	int unit = drive->select.b.unit;
+
+
+	/* Set the PIO timings */
+	if ((speed & XFER_MODE) == XFER_PIO) {
+		u8 pioa;
+		u8 piob;
+		u8 cmd;
+
+		pioa = speed - XFER_PIO_0;
+		piob = ide_get_best_pio_mode(&(drive->hwif->drives[!unit]),
+						255, 4, NULL);
+		cmd = pioa < piob ? pioa : piob;
+
+		/* Write the speed of the current drive */
+		reg = (cs5535_pio_cmd_timings[cmd] << 16) |
+			cs5535_pio_dta_timings[pioa];
+		wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0);
+
+		/* And if nessesary - change the speed of the other drive */
+		rdmsr(unit ?  ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy);
+
+		if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) !=
+			cs5535_pio_cmd_timings[cmd]) {
+			reg &= 0x0000FFFF;
+			reg |= cs5535_pio_cmd_timings[cmd] << 16;
+			wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0);
+		}
+
+		/* Set bit 31 of the DMA register for PIO format 1 timings */
+		rdmsr(unit ?  ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
+		wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA,
+					reg | 0x80000000UL, 0);
+	} else {
+		rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
+
+		reg &= 0x80000000UL;  /* Preserve the PIO format bit */
+
+		if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_7)
+			reg |= cs5535_udma_timings[speed - XFER_UDMA_0];
+		else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+			reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0];
+		else
+			return;
+
+		wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0);
+	}
+}
+
+static u8 cs5535_ratemask(ide_drive_t *drive)
+{
+	/* eighty93 will return 1 if it's 80core and capable of
+	exceeding udma2, 0 otherwise. we need ratemask to set
+	the max speed and if we can > udma2 then we return 2
+	which selects speed_max as udma4 which is the 5535's max
+	speed, and 1 selects udma2 which is the max for 40c */
+	if (!eighty_ninty_three(drive))
+		return 1;
+
+	return 2;
+}
+
+
+/****
+ *	cs5535_set_drive         -     Configure the drive to the new speed
+ *	@drive: Drive to set up
+ *	@speed: desired speed
+ *
+ *	cs5535_set_drive() configures the drive and the chipset to a
+ *	new speed. It also can be called by upper layers.
+ */
+static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
+{
+	speed = ide_rate_filter(cs5535_ratemask(drive), speed);
+	ide_config_drive_speed(drive, speed);
+	cs5535_set_speed(drive, speed);
+
+	return 0;
+}
+
+/****
+ *	cs5535_tuneproc    -       PIO setup
+ *	@drive: drive to set up
+ *	@pio: mode to use (255 for 'best possible')
+ *
+ *	A callback from the upper layers for PIO-only tuning.
+ */
+static void cs5535_tuneproc(ide_drive_t *drive, u8 xferspeed)
+{
+	u8 modes[] = {	XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3,
+			XFER_PIO_4 };
+
+	/* cs5535 max pio is pio 4, best_pio will check the blacklist.
+	i think we don't need to rate_filter the incoming xferspeed
+	since we know we're only going to choose pio */
+	xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4, NULL);
+	ide_config_drive_speed(drive, modes[xferspeed]);
+	cs5535_set_speed(drive, xferspeed);
+}
+
+static int cs5535_config_drive_for_dma(ide_drive_t *drive)
+{
+	u8 speed;
+
+	speed = ide_dma_speed(drive, cs5535_ratemask(drive));
+
+	/* If no DMA speed was available then let dma_check hit pio */
+	if (!speed) {
+		return 0;
+	}
+
+	cs5535_set_drive(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int cs5535_dma_check(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= drive->hwif;
+	struct hd_driveid *id	= drive->id;
+	u8 speed;
+
+	drive->init_speed = 0;
+
+	if ((id->capability & 1) && drive->autodma) {
+		if (ide_use_dma(drive)) {
+			if (cs5535_config_drive_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:
+		speed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+		cs5535_set_drive(drive, speed);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	/* IORDY not supported */
+	return 0;
+}
+
+static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
+{
+	u8 bit;
+
+	/* if a 80 wire cable was detected */
+	pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit);
+	return (bit & 1);
+}
+
+/****
+ *	init_hwif_cs5535        -       Initialize one ide cannel
+ *	@hwif: Channel descriptor
+ *
+ *	This gets invoked by the IDE driver once for each channel. It
+ *	performs channel-specific pre-initialization before drive probing.
+ *
+ */
+static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
+{
+	int i;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &cs5535_tuneproc;
+	hwif->speedproc = &cs5535_set_drive;
+	hwif->ide_dma_check = &cs5535_dma_check;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x1F;
+	hwif->mwdma_mask = 0x07;
+
+
+	hwif->udma_four = cs5535_cable_detect(hwif->pci_dev);
+
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	/* just setting autotune and not worrying about bios timings */
+	for (i = 0; i < 2; i++) {
+		hwif->drives[i].autotune = 1;
+		hwif->drives[i].autodma = hwif->autodma;
+	}
+}
+
+static ide_pci_device_t cs5535_chipset __devinitdata = {
+	.name		= "CS5535",
+	.init_hwif	= init_hwif_cs5535,
+	.channels	= 1,
+	.autodma	= AUTODMA,
+	.bootable	= ON_BOARD,
+};
+
+static int __devinit cs5535_init_one(struct pci_dev *dev,
+					const struct pci_device_id *id)
+{
+	return ide_setup_pci_device(dev, &cs5535_chipset);
+}
+
+static struct pci_device_id cs5535_pci_tbl[] =
+{
+	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_IDE, PCI_ANY_ID,
+		PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl);
+
+static struct pci_driver driver = {
+	.name       = "CS5535_IDE",
+	.id_table   = cs5535_pci_tbl,
+	.probe      = cs5535_init_one,
+};
+
+static int __init cs5535_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+module_init(cs5535_ide_init);
+
+MODULE_AUTHOR("AMD");
+MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 5a33513..9f41ecd 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -469,7 +469,7 @@
 
 static __devinitdata ide_hwif_t *primary;
 
-void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
+static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
 {
 	if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
 		primary = hwif;
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 2b9961b..022d244 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -701,6 +701,7 @@
 	unsigned long barsize	= pci_resource_len(dev, 5);
 	u8 tmpbyte	= 0;
 	void __iomem *ioaddr;
+	u32 tmp, irq_mask;
 
 	/*
 	 *	Drop back to PIO if we can't map the mmio. Some
@@ -726,6 +727,14 @@
 	pci_set_drvdata(dev, (void *) ioaddr);
 
 	if (pdev_is_sata(dev)) {
+		/* make sure IDE0/1 interrupts are not masked */
+		irq_mask = (1 << 22) | (1 << 23);
+		tmp = readl(ioaddr + 0x48);
+		if (tmp & irq_mask) {
+			tmp &= ~irq_mask;
+			writel(tmp, ioaddr + 0x48);
+			readl(ioaddr + 0x48); /* flush */
+		}
 		writel(0, ioaddr + 0x148);
 		writel(0, ioaddr + 0x1C8);
 	}
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 18ed776..d4f2111 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -787,8 +787,9 @@
 static LIST_HEAD(ide_pci_drivers);
 
 /*
- *	ide_register_pci_driver		-	attach IDE driver
+ *	__ide_register_pci_driver	-	attach IDE driver
  *	@driver: pci driver
+ *	@module: owner module of the driver
  *
  *	Registers a driver with the IDE layer. The IDE layer arranges that
  *	boot time setup is done in the expected device order and then 
@@ -801,15 +802,16 @@
  *	Returns are the same as for pci_register_driver
  */
 
-int ide_pci_register_driver(struct pci_driver *driver)
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module)
 {
 	if(!pre_init)
-		return pci_module_init(driver);
+		return __pci_register_driver(driver, module);
+	driver->driver.owner = module;
 	list_add_tail(&driver->node, &ide_pci_drivers);
 	return 0;
 }
 
-EXPORT_SYMBOL_GPL(ide_pci_register_driver);
+EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
 
 /**
  *	ide_unregister_pci_driver	-	unregister an IDE driver
@@ -897,6 +899,6 @@
 	{
 		list_del(l);
 		d = list_entry(l, struct pci_driver, node);
-		pci_register_driver(d);
+		__pci_register_driver(d, d->driver.owner);
 	}
 }
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index aed5ca2..5ea741f 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -31,7 +31,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: user_mad.c 2814 2005-07-06 19:14:09Z halr $
+ * $Id: user_mad.c 4010 2005-11-09 23:11:56Z roland $
  */
 
 #include <linux/module.h>
@@ -110,13 +110,13 @@
 };
 
 struct ib_umad_file {
-	struct ib_umad_port *port;
-	struct list_head     recv_list;
-	struct list_head     port_list;
-	spinlock_t           recv_lock;
-	wait_queue_head_t    recv_wait;
-	struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
-	struct ib_mr        *mr[IB_UMAD_MAX_AGENTS];
+	struct ib_umad_port    *port;
+	struct list_head	recv_list;
+	struct list_head	port_list;
+	spinlock_t		recv_lock;
+	wait_queue_head_t	recv_wait;
+	struct ib_mad_agent    *agent[IB_UMAD_MAX_AGENTS];
+	int			agents_dead;
 };
 
 struct ib_umad_packet {
@@ -145,6 +145,12 @@
 	kfree(dev);
 }
 
+/* caller must hold port->mutex at least for reading */
+static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
+{
+	return file->agents_dead ? NULL : file->agent[id];
+}
+
 static int queue_packet(struct ib_umad_file *file,
 			struct ib_mad_agent *agent,
 			struct ib_umad_packet *packet)
@@ -152,10 +158,11 @@
 	int ret = 1;
 
 	down_read(&file->port->mutex);
+
 	for (packet->mad.hdr.id = 0;
 	     packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
 	     packet->mad.hdr.id++)
-		if (agent == file->agent[packet->mad.hdr.id]) {
+		if (agent == __get_agent(file, packet->mad.hdr.id)) {
 			spin_lock_irq(&file->recv_lock);
 			list_add_tail(&packet->list, &file->recv_list);
 			spin_unlock_irq(&file->recv_lock);
@@ -327,7 +334,7 @@
 
 	down_read(&file->port->mutex);
 
-	agent = file->agent[packet->mad.hdr.id];
+	agent = __get_agent(file, packet->mad.hdr.id);
 	if (!agent) {
 		ret = -EINVAL;
 		goto err_up;
@@ -481,7 +488,7 @@
 	}
 
 	for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id)
-		if (!file->agent[agent_id])
+		if (!__get_agent(file, agent_id))
 			goto found;
 
 	ret = -ENOMEM;
@@ -505,29 +512,15 @@
 		goto out;
 	}
 
-	file->agent[agent_id] = agent;
-
-	file->mr[agent_id] = ib_get_dma_mr(agent->qp->pd, IB_ACCESS_LOCAL_WRITE);
-	if (IS_ERR(file->mr[agent_id])) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
 	if (put_user(agent_id,
 		     (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {
 		ret = -EFAULT;
-		goto err_mr;
+		ib_unregister_mad_agent(agent);
+		goto out;
 	}
 
+	file->agent[agent_id] = agent;
 	ret = 0;
-	goto out;
-
-err_mr:
-	ib_dereg_mr(file->mr[agent_id]);
-
-err:
-	file->agent[agent_id] = NULL;
-	ib_unregister_mad_agent(agent);
 
 out:
 	up_write(&file->port->mutex);
@@ -536,27 +529,29 @@
 
 static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg)
 {
+	struct ib_mad_agent *agent = NULL;
 	u32 id;
 	int ret = 0;
 
+	if (get_user(id, (u32 __user *) arg))
+		return -EFAULT;
+
 	down_write(&file->port->mutex);
 
-	if (get_user(id, (u32 __user *) arg)) {
-		ret = -EFAULT;
-		goto out;
-	}
-
-	if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !file->agent[id]) {
+	if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
 		ret = -EINVAL;
 		goto out;
 	}
 
-	ib_dereg_mr(file->mr[id]);
-	ib_unregister_mad_agent(file->agent[id]);
+	agent = file->agent[id];
 	file->agent[id] = NULL;
 
 out:
 	up_write(&file->port->mutex);
+
+	if (agent)
+		ib_unregister_mad_agent(agent);
+
 	return ret;
 }
 
@@ -621,23 +616,29 @@
 	struct ib_umad_file *file = filp->private_data;
 	struct ib_umad_device *dev = file->port->umad_dev;
 	struct ib_umad_packet *packet, *tmp;
+	int already_dead;
 	int i;
 
 	down_write(&file->port->mutex);
-	for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
-		if (file->agent[i]) {
-			ib_dereg_mr(file->mr[i]);
-			ib_unregister_mad_agent(file->agent[i]);
-		}
+
+	already_dead = file->agents_dead;
+	file->agents_dead = 1;
 
 	list_for_each_entry_safe(packet, tmp, &file->recv_list, list)
 		kfree(packet);
 
 	list_del(&file->port_list);
-	up_write(&file->port->mutex);
+
+	downgrade_write(&file->port->mutex);
+
+	if (!already_dead)
+		for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
+			if (file->agent[i])
+				ib_unregister_mad_agent(file->agent[i]);
+
+	up_read(&file->port->mutex);
 
 	kfree(file);
-
 	kref_put(&dev->ref, ib_umad_release_dev);
 
 	return 0;
@@ -801,7 +802,7 @@
 		goto err_class;
 	port->sm_dev->owner = THIS_MODULE;
 	port->sm_dev->ops   = &umad_sm_fops;
-	kobject_set_name(&port->dev->kobj, "issm%d", port->dev_num);
+	kobject_set_name(&port->sm_dev->kobj, "issm%d", port->dev_num);
 	if (cdev_add(port->sm_dev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1))
 		goto err_sm_cdev;
 
@@ -863,14 +864,36 @@
 
 	port->ib_dev = NULL;
 
-	list_for_each_entry(file, &port->file_list, port_list)
-		for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id) {
-			if (!file->agent[id])
-				continue;
-			ib_dereg_mr(file->mr[id]);
-			ib_unregister_mad_agent(file->agent[id]);
-			file->agent[id] = NULL;
-		}
+	/*
+	 * Now go through the list of files attached to this port and
+	 * unregister all of their MAD agents.  We need to hold
+	 * port->mutex while doing this to avoid racing with
+	 * ib_umad_close(), but we can't hold the mutex for writing
+	 * while calling ib_unregister_mad_agent(), since that might
+	 * deadlock by calling back into queue_packet().  So we
+	 * downgrade our lock to a read lock, and then drop and
+	 * reacquire the write lock for the next iteration.
+	 *
+	 * We do list_del_init() on the file's list_head so that the
+	 * list_del in ib_umad_close() is still OK, even after the
+	 * file is removed from the list.
+	 */
+	while (!list_empty(&port->file_list)) {
+		file = list_entry(port->file_list.next, struct ib_umad_file,
+				  port_list);
+
+		file->agents_dead = 1;
+		list_del_init(&file->port_list);
+
+		downgrade_write(&port->mutex);
+
+		for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
+			if (file->agent[id])
+				ib_unregister_mad_agent(file->agent[id]);
+
+		up_read(&port->mutex);
+		down_write(&port->mutex);
+	}
 
 	up_write(&port->mutex);
 
@@ -913,7 +936,7 @@
 
 err:
 	while (--i >= s)
-		ib_umad_kill_port(&umad_dev->port[i]);
+		ib_umad_kill_port(&umad_dev->port[i - s]);
 
 	kref_put(&umad_dev->ref, ib_umad_release_dev);
 }
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 63a7415..ed45da8 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -708,7 +708,7 @@
 		resp->wc[i].opcode 	   = wc[i].opcode;
 		resp->wc[i].vendor_err 	   = wc[i].vendor_err;
 		resp->wc[i].byte_len 	   = wc[i].byte_len;
-		resp->wc[i].imm_data 	   = wc[i].imm_data;
+		resp->wc[i].imm_data 	   = (__u32 __force) wc[i].imm_data;
 		resp->wc[i].qp_num 	   = wc[i].qp_num;
 		resp->wc[i].src_qp 	   = wc[i].src_qp;
 		resp->wc[i].wc_flags 	   = wc[i].wc_flags;
@@ -908,7 +908,12 @@
 	if (ret)
 		goto err_destroy;
 
-	resp.qp_handle = uobj->uobject.id;
+	resp.qp_handle       = uobj->uobject.id;
+	resp.max_recv_sge    = attr.cap.max_recv_sge;
+	resp.max_send_sge    = attr.cap.max_send_sge;
+	resp.max_recv_wr     = attr.cap.max_recv_wr;
+	resp.max_send_wr     = attr.cap.max_send_wr;
+	resp.max_inline_data = attr.cap.max_inline_data;
 
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
 			 &resp, sizeof resp)) {
@@ -1135,7 +1140,7 @@
 		next->num_sge    = user_wr->num_sge;
 		next->opcode     = user_wr->opcode;
 		next->send_flags = user_wr->send_flags;
-		next->imm_data   = user_wr->imm_data;
+		next->imm_data   = (__be32 __force) user_wr->imm_data;
 
 		if (qp->qp_type == IB_QPT_UD) {
 			next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr,
@@ -1701,7 +1706,6 @@
 	}
 
 	attr.max_wr    = cmd.max_wr;
-	attr.max_sge   = cmd.max_sge;
 	attr.srq_limit = cmd.srq_limit;
 
 	ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 4186cc8..4c15e11 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -325,16 +325,8 @@
 int ib_resize_cq(struct ib_cq *cq,
                  int           cqe)
 {
-	int ret;
-
-	if (!cq->device->resize_cq)
-		return -ENOSYS;
-
-	ret = cq->device->resize_cq(cq, &cqe);
-	if (!ret)
-		cq->cqe = cqe;
-
-	return ret;
+	return cq->device->resize_cq ?
+		cq->device->resize_cq(cq, cqe) : -ENOSYS;
 }
 EXPORT_SYMBOL(ib_resize_cq);
 
diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c
index 25ebab6..c3bec74 100644
--- a/drivers/infiniband/hw/mthca/mthca_catas.c
+++ b/drivers/infiniband/hw/mthca/mthca_catas.c
@@ -97,7 +97,7 @@
 		}
 
 	spin_lock_irqsave(&catas_lock, flags);
-	if (dev->catas_err.stop)
+	if (!dev->catas_err.stop)
 		mod_timer(&dev->catas_err.timer,
 			  jiffies + MTHCA_CATAS_POLL_INTERVAL);
 	spin_unlock_irqrestore(&catas_lock, flags);
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 49f211d..9ed3458 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -1060,6 +1060,8 @@
 		dev_lim->hca.arbel.resize_srq = field & 1;
 		MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET);
 		dev_lim->max_sg = min_t(int, field, dev_lim->max_sg);
+		MTHCA_GET(size, outbox, QUERY_DEV_LIM_MAX_DESC_SZ_RQ_OFFSET);
+		dev_lim->max_desc_sz = min_t(int, size, dev_lim->max_desc_sz);
 		MTHCA_GET(size, outbox, QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET);
 		dev_lim->mpt_entry_sz = size;
 		MTHCA_GET(field, outbox, QUERY_DEV_LIM_PBL_SZ_OFFSET);
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index f98e235..4a8adce 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -258,7 +258,7 @@
 {
 	struct mthca_cq *cq;
 	struct mthca_cqe *cqe;
-	int prod_index;
+	u32 prod_index;
 	int nfreed = 0;
 
 	spin_lock_irq(&dev->cq_table.lock);
@@ -293,19 +293,15 @@
 	 * Now sweep backwards through the CQ, removing CQ entries
 	 * that match our QP by copying older entries on top of them.
 	 */
-	while (prod_index > cq->cons_index) {
-		cqe = get_cqe(cq, (prod_index - 1) & cq->ibcq.cqe);
+	while ((int) --prod_index - (int) cq->cons_index >= 0) {
+		cqe = get_cqe(cq, prod_index & cq->ibcq.cqe);
 		if (cqe->my_qpn == cpu_to_be32(qpn)) {
 			if (srq)
 				mthca_free_srq_wqe(srq, be32_to_cpu(cqe->wqe));
 			++nfreed;
-		}
-		else if (nfreed)
-			memcpy(get_cqe(cq, (prod_index - 1 + nfreed) &
-				       cq->ibcq.cqe),
-			       cqe,
-			       MTHCA_CQ_ENTRY_SIZE);
-		--prod_index;
+		} else if (nfreed)
+			memcpy(get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe),
+			       cqe, MTHCA_CQ_ENTRY_SIZE);
 	}
 
 	if (nfreed) {
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index e7e5d3b..497ff79 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -131,6 +131,7 @@
 	int      max_sg;
 	int      num_qps;
 	int      max_wqes;
+	int	 max_desc_sz;
 	int	 max_qp_init_rdma;
 	int      reserved_qps;
 	int      num_srqs;
@@ -154,6 +155,7 @@
 	int      reserved_mcgs;
 	int      num_pds;
 	int      reserved_pds;
+	u32      page_size_cap;
 	u32      flags;
 	u8       port_width_cap;
 };
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 45c6328..6f94b25 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -168,6 +168,7 @@
 	mdev->limits.max_srq_wqes       = dev_lim->max_srq_sz;
 	mdev->limits.reserved_srqs      = dev_lim->reserved_srqs;
 	mdev->limits.reserved_eecs      = dev_lim->reserved_eecs;
+	mdev->limits.max_desc_sz        = dev_lim->max_desc_sz;
 	/*
 	 * Subtract 1 from the limit because we need to allocate a
 	 * spare CQE so the HCA HW can tell the difference between an
@@ -181,6 +182,7 @@
 	mdev->limits.reserved_uars      = dev_lim->reserved_uars;
 	mdev->limits.reserved_pds       = dev_lim->reserved_pds;
 	mdev->limits.port_width_cap     = dev_lim->max_port_width;
+	mdev->limits.page_size_cap      = ~(u32) (dev_lim->min_page_sz - 1);
 	mdev->limits.flags              = dev_lim->flags;
 
 	/* IB_DEVICE_RESIZE_MAX_WR not supported by driver.
@@ -1196,7 +1198,6 @@
 
 static struct pci_driver mthca_driver = {
 	.name		= DRV_NAME,
-	.owner		= THIS_MODULE,
 	.id_table	= mthca_pci_table,
 	.probe		= mthca_init_one,
 	.remove		= __devexit_p(mthca_remove_one)
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 6b01666..4cc7e28 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -90,6 +90,7 @@
 	memcpy(&props->node_guid,      out_mad->data + 12, 8);
 
 	props->max_mr_size         = ~0ull;
+	props->page_size_cap       = mdev->limits.page_size_cap;
 	props->max_qp              = mdev->limits.num_qps - mdev->limits.reserved_qps;
 	props->max_qp_wr           = mdev->limits.max_wqes;
 	props->max_sge             = mdev->limits.max_sg;
@@ -615,11 +616,11 @@
 		return ERR_PTR(err);
 	}
 
-	init_attr->cap.max_inline_data = 0;
 	init_attr->cap.max_send_wr     = qp->sq.max;
 	init_attr->cap.max_recv_wr     = qp->rq.max;
 	init_attr->cap.max_send_sge    = qp->sq.max_gs;
 	init_attr->cap.max_recv_sge    = qp->rq.max_gs;
+	init_attr->cap.max_inline_data = qp->max_inline_data;
 
 	return &qp->ibqp;
 }
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index bcd4b01..1e73947 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -251,6 +251,7 @@
 	struct mthca_wq        sq;
 	enum ib_sig_type       sq_policy;
 	int                    send_wqe_offset;
+	int                    max_inline_data;
 
 	u64                   *wrid;
 	union mthca_buf	       queue;
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 8852ea4..760c418d 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -885,6 +885,48 @@
 	return err;
 }
 
+static void mthca_adjust_qp_caps(struct mthca_dev *dev,
+				 struct mthca_pd *pd,
+				 struct mthca_qp *qp)
+{
+	int max_data_size;
+
+	/*
+	 * Calculate the maximum size of WQE s/g segments, excluding
+	 * the next segment and other non-data segments.
+	 */
+	max_data_size = min(dev->limits.max_desc_sz, 1 << qp->sq.wqe_shift) -
+		sizeof (struct mthca_next_seg);
+
+	switch (qp->transport) {
+	case MLX:
+		max_data_size -= 2 * sizeof (struct mthca_data_seg);
+		break;
+
+	case UD:
+		if (mthca_is_memfree(dev))
+			max_data_size -= sizeof (struct mthca_arbel_ud_seg);
+		else
+			max_data_size -= sizeof (struct mthca_tavor_ud_seg);
+		break;
+
+	default:
+		max_data_size -= sizeof (struct mthca_raddr_seg);
+		break;
+	}
+
+	/* We don't support inline data for kernel QPs (yet). */
+	if (!pd->ibpd.uobject)
+		qp->max_inline_data = 0;
+        else
+		qp->max_inline_data = max_data_size - MTHCA_INLINE_HEADER_SIZE;
+
+	qp->sq.max_gs = max_data_size / sizeof (struct mthca_data_seg);
+	qp->rq.max_gs = (min(dev->limits.max_desc_sz, 1 << qp->rq.wqe_shift) -
+			sizeof (struct mthca_next_seg)) /
+			sizeof (struct mthca_data_seg);
+}
+
 /*
  * Allocate and register buffer for WQEs.  qp->rq.max, sq.max,
  * rq.max_gs and sq.max_gs must all be assigned.
@@ -902,27 +944,53 @@
 	size = sizeof (struct mthca_next_seg) +
 		qp->rq.max_gs * sizeof (struct mthca_data_seg);
 
+	if (size > dev->limits.max_desc_sz)
+		return -EINVAL;
+
 	for (qp->rq.wqe_shift = 6; 1 << qp->rq.wqe_shift < size;
 	     qp->rq.wqe_shift++)
 		; /* nothing */
 
-	size = sizeof (struct mthca_next_seg) +
-		qp->sq.max_gs * sizeof (struct mthca_data_seg);
+	size = qp->sq.max_gs * sizeof (struct mthca_data_seg);
 	switch (qp->transport) {
 	case MLX:
 		size += 2 * sizeof (struct mthca_data_seg);
 		break;
+
 	case UD:
-		if (mthca_is_memfree(dev))
-			size += sizeof (struct mthca_arbel_ud_seg);
-		else
-			size += sizeof (struct mthca_tavor_ud_seg);
+		size += mthca_is_memfree(dev) ?
+			sizeof (struct mthca_arbel_ud_seg) :
+			sizeof (struct mthca_tavor_ud_seg);
 		break;
+
+	case UC:
+		size += sizeof (struct mthca_raddr_seg);
+		break;
+
+	case RC:
+		size += sizeof (struct mthca_raddr_seg);
+		/*
+		 * An atomic op will require an atomic segment, a
+		 * remote address segment and one scatter entry.
+		 */
+		size = max_t(int, size,
+			     sizeof (struct mthca_atomic_seg) +
+			     sizeof (struct mthca_raddr_seg) +
+			     sizeof (struct mthca_data_seg));
+		break;
+
 	default:
-		/* bind seg is as big as atomic + raddr segs */
-		size += sizeof (struct mthca_bind_seg);
+		break;
 	}
 
+	/* Make sure that we have enough space for a bind request */
+	size = max_t(int, size, sizeof (struct mthca_bind_seg));
+
+	size += sizeof (struct mthca_next_seg);
+
+	if (size > dev->limits.max_desc_sz)
+		return -EINVAL;
+
 	for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size;
 	     qp->sq.wqe_shift++)
 		; /* nothing */
@@ -1066,6 +1134,8 @@
 		return ret;
 	}
 
+	mthca_adjust_qp_caps(dev, pd, qp);
+
 	/*
 	 * If this is a userspace QP, we're done now.  The doorbells
 	 * will be allocated and buffers will be initialized in
@@ -1486,8 +1556,8 @@
 				}
 
 				wqe += sizeof (struct mthca_atomic_seg);
-				size += sizeof (struct mthca_raddr_seg) / 16 +
-					sizeof (struct mthca_atomic_seg);
+				size += (sizeof (struct mthca_raddr_seg) +
+					 sizeof (struct mthca_atomic_seg)) / 16;
 				break;
 
 			case IB_WR_RDMA_WRITE:
@@ -1637,6 +1707,7 @@
 {
 	struct mthca_dev *dev = to_mdev(ibqp->device);
 	struct mthca_qp *qp = to_mqp(ibqp);
+	__be32 doorbell[2];
 	unsigned long flags;
 	int err = 0;
 	int nreq;
@@ -1654,6 +1725,22 @@
 	ind = qp->rq.next_ind;
 
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
+		if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
+			nreq = 0;
+
+			doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
+			doorbell[1] = cpu_to_be32(qp->qpn << 8);
+
+			wmb();
+
+			mthca_write64(doorbell,
+				      dev->kar + MTHCA_RECEIVE_DOORBELL,
+				      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+
+			qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB;
+			size0 = 0;
+		}
+
 		if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
 			mthca_err(dev, "RQ %06x full (%u head, %u tail,"
 					" %d max, %d nreq)\n", qp->qpn,
@@ -1711,8 +1798,6 @@
 
 out:
 	if (likely(nreq)) {
-		__be32 doorbell[2];
-
 		doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
 		doorbell[1] = cpu_to_be32((qp->qpn << 8) | nreq);
 
@@ -1806,8 +1891,8 @@
 				}
 
 				wqe += sizeof (struct mthca_atomic_seg);
-				size += sizeof (struct mthca_raddr_seg) / 16 +
-					sizeof (struct mthca_atomic_seg);
+				size += (sizeof (struct mthca_raddr_seg) +
+					 sizeof (struct mthca_atomic_seg)) / 16;
 				break;
 
 			case IB_WR_RDMA_READ:
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index 26d5161..f7d2342 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -417,6 +417,7 @@
 {
 	struct mthca_dev *dev = to_mdev(ibsrq->device);
 	struct mthca_srq *srq = to_msrq(ibsrq);
+	__be32 doorbell[2];
 	unsigned long flags;
 	int err = 0;
 	int first_ind;
@@ -432,6 +433,25 @@
 	first_ind = srq->first_free;
 
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
+		if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
+			nreq = 0;
+
+			doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
+			doorbell[1] = cpu_to_be32(srq->srqn << 8);
+
+			/*
+			 * Make sure that descriptors are written
+			 * before doorbell is rung.
+			 */
+			wmb();
+
+			mthca_write64(doorbell,
+				      dev->kar + MTHCA_RECEIVE_DOORBELL,
+				      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+
+			first_ind = srq->first_free;
+		}
+
 		ind = srq->first_free;
 
 		if (ind < 0) {
@@ -494,8 +514,6 @@
 	}
 
 	if (likely(nreq)) {
-		__be32 doorbell[2];
-
 		doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
 		doorbell[1] = cpu_to_be32((srq->srqn << 8) | nreq);
 
diff --git a/drivers/infiniband/hw/mthca/mthca_wqe.h b/drivers/infiniband/hw/mthca/mthca_wqe.h
index 1f4c0ff..73f1c0b 100644
--- a/drivers/infiniband/hw/mthca/mthca_wqe.h
+++ b/drivers/infiniband/hw/mthca/mthca_wqe.h
@@ -49,7 +49,8 @@
 };
 
 enum {
-	MTHCA_INVAL_LKEY = 0x100
+	MTHCA_INVAL_LKEY			= 0x100,
+	MTHCA_TAVOR_MAX_WQES_PER_RECV_DB	= 256
 };
 
 struct mthca_next_seg {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 0095acc..9923a15 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -179,6 +179,7 @@
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
 	struct list_head fs_list;
 	struct dentry *mcg_dentry;
+	struct dentry *path_dentry;
 #endif
 };
 
@@ -270,7 +271,6 @@
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
 struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct net_device *dev);
-void ipoib_mcast_iter_free(struct ipoib_mcast_iter *iter);
 int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter);
 void ipoib_mcast_iter_read(struct ipoib_mcast_iter *iter,
 				  union ib_gid *gid,
@@ -278,6 +278,11 @@
 				  unsigned int *queuelen,
 				  unsigned int *complete,
 				  unsigned int *send_only);
+
+struct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev);
+int ipoib_path_iter_next(struct ipoib_path_iter *iter);
+void ipoib_path_iter_read(struct ipoib_path_iter *iter,
+			  struct ipoib_path *path);
 #endif
 
 int ipoib_mcast_attach(struct net_device *dev, u16 mlid,
@@ -299,13 +304,13 @@
 int ipoib_pkey_dev_delay_open(struct net_device *dev);
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
-int ipoib_create_debug_file(struct net_device *dev);
-void ipoib_delete_debug_file(struct net_device *dev);
+void ipoib_create_debug_files(struct net_device *dev);
+void ipoib_delete_debug_files(struct net_device *dev);
 int ipoib_register_debugfs(void);
 void ipoib_unregister_debugfs(void);
 #else
-static inline int ipoib_create_debug_file(struct net_device *dev) { return 0; }
-static inline void ipoib_delete_debug_file(struct net_device *dev) { }
+static inline void ipoib_create_debug_files(struct net_device *dev) { }
+static inline void ipoib_delete_debug_files(struct net_device *dev) { }
 static inline int ipoib_register_debugfs(void) { return 0; }
 static inline void ipoib_unregister_debugfs(void) { }
 #endif
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
index 38b150f..685258e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
@@ -43,6 +43,18 @@
 
 static struct dentry *ipoib_root;
 
+static void format_gid(union ib_gid *gid, char *buf)
+{
+	int i, n;
+
+	for (n = 0, i = 0; i < 8; ++i) {
+		n += sprintf(buf + n, "%x",
+			     be16_to_cpu(((__be16 *) gid->raw)[i]));
+		if (i < 7)
+			buf[n++] = ':';
+	}
+}
+
 static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos)
 {
 	struct ipoib_mcast_iter *iter;
@@ -54,7 +66,7 @@
 
 	while (n--) {
 		if (ipoib_mcast_iter_next(iter)) {
-			ipoib_mcast_iter_free(iter);
+			kfree(iter);
 			return NULL;
 		}
 	}
@@ -70,7 +82,7 @@
 	(*pos)++;
 
 	if (ipoib_mcast_iter_next(iter)) {
-		ipoib_mcast_iter_free(iter);
+		kfree(iter);
 		return NULL;
 	}
 
@@ -87,32 +99,32 @@
 	struct ipoib_mcast_iter *iter = iter_ptr;
 	char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
 	union ib_gid mgid;
-	int i, n;
 	unsigned long created;
 	unsigned int queuelen, complete, send_only;
 
-	if (iter) {
-		ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen,
-				      &complete, &send_only);
+	if (!iter)
+		return 0;
 
-		for (n = 0, i = 0; i < sizeof mgid / 2; ++i) {
-			n += sprintf(gid_buf + n, "%x",
-				     be16_to_cpu(((__be16 *) mgid.raw)[i]));
-			if (i < sizeof mgid / 2 - 1)
-				gid_buf[n++] = ':';
-		}
-	}
+	ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen,
+			      &complete, &send_only);
 
-	seq_printf(file, "GID: %*s", -(1 + (int) sizeof gid_buf), gid_buf);
+	format_gid(&mgid, gid_buf);
 
 	seq_printf(file,
-		   " created: %10ld queuelen: %4d complete: %d send_only: %d\n",
-		   created, queuelen, complete, send_only);
+		   "GID: %s\n"
+		   "  created: %10ld\n"
+		   "  queuelen: %9d\n"
+		   "  complete: %9s\n"
+		   "  send_only: %8s\n"
+		   "\n",
+		   gid_buf, created, queuelen,
+		   complete ? "yes" : "no",
+		   send_only ? "yes" : "no");
 
 	return 0;
 }
 
-static struct seq_operations ipoib_seq_ops = {
+static struct seq_operations ipoib_mcg_seq_ops = {
 	.start = ipoib_mcg_seq_start,
 	.next  = ipoib_mcg_seq_next,
 	.stop  = ipoib_mcg_seq_stop,
@@ -124,7 +136,7 @@
 	struct seq_file *seq;
 	int ret;
 
-	ret = seq_open(file, &ipoib_seq_ops);
+	ret = seq_open(file, &ipoib_mcg_seq_ops);
 	if (ret)
 		return ret;
 
@@ -134,7 +146,7 @@
 	return 0;
 }
 
-static struct file_operations ipoib_fops = {
+static struct file_operations ipoib_mcg_fops = {
 	.owner   = THIS_MODULE,
 	.open    = ipoib_mcg_open,
 	.read    = seq_read,
@@ -142,25 +154,138 @@
 	.release = seq_release
 };
 
-int ipoib_create_debug_file(struct net_device *dev)
+static void *ipoib_path_seq_start(struct seq_file *file, loff_t *pos)
 {
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	char name[IFNAMSIZ + sizeof "_mcg"];
+	struct ipoib_path_iter *iter;
+	loff_t n = *pos;
 
-	snprintf(name, sizeof name, "%s_mcg", dev->name);
+	iter = ipoib_path_iter_init(file->private);
+	if (!iter)
+		return NULL;
 
-	priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
-					       ipoib_root, dev, &ipoib_fops);
+	while (n--) {
+		if (ipoib_path_iter_next(iter)) {
+			kfree(iter);
+			return NULL;
+		}
+	}
 
-	return priv->mcg_dentry ? 0 : -ENOMEM;
+	return iter;
 }
 
-void ipoib_delete_debug_file(struct net_device *dev)
+static void *ipoib_path_seq_next(struct seq_file *file, void *iter_ptr,
+				   loff_t *pos)
+{
+	struct ipoib_path_iter *iter = iter_ptr;
+
+	(*pos)++;
+
+	if (ipoib_path_iter_next(iter)) {
+		kfree(iter);
+		return NULL;
+	}
+
+	return iter;
+}
+
+static void ipoib_path_seq_stop(struct seq_file *file, void *iter_ptr)
+{
+	/* nothing for now */
+}
+
+static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr)
+{
+	struct ipoib_path_iter *iter = iter_ptr;
+	char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
+	struct ipoib_path path;
+	int rate;
+
+	if (!iter)
+		return 0;
+
+	ipoib_path_iter_read(iter, &path);
+
+	format_gid(&path.pathrec.dgid, gid_buf);
+
+	seq_printf(file,
+		   "GID: %s\n"
+		   "  complete: %6s\n",
+		   gid_buf, path.pathrec.dlid ? "yes" : "no");
+
+	if (path.pathrec.dlid) {
+		rate = ib_sa_rate_enum_to_int(path.pathrec.rate) * 25;
+
+		seq_printf(file,
+			   "  DLID:     0x%04x\n"
+			   "  SL: %12d\n"
+			   "  rate: %*d%s Gb/sec\n",
+			   be16_to_cpu(path.pathrec.dlid),
+			   path.pathrec.sl,
+			   10 - ((rate % 10) ? 2 : 0),
+			   rate / 10, rate % 10 ? ".5" : "");
+	}
+
+	seq_putc(file, '\n');
+
+	return 0;
+}
+
+static struct seq_operations ipoib_path_seq_ops = {
+	.start = ipoib_path_seq_start,
+	.next  = ipoib_path_seq_next,
+	.stop  = ipoib_path_seq_stop,
+	.show  = ipoib_path_seq_show,
+};
+
+static int ipoib_path_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int ret;
+
+	ret = seq_open(file, &ipoib_path_seq_ops);
+	if (ret)
+		return ret;
+
+	seq = file->private_data;
+	seq->private = inode->u.generic_ip;
+
+	return 0;
+}
+
+static struct file_operations ipoib_path_fops = {
+	.owner   = THIS_MODULE,
+	.open    = ipoib_path_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release
+};
+
+void ipoib_create_debug_files(struct net_device *dev)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	char name[IFNAMSIZ + sizeof "_path"];
+
+	snprintf(name, sizeof name, "%s_mcg", dev->name);
+	priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					       ipoib_root, dev, &ipoib_mcg_fops);
+	if (!priv->mcg_dentry)
+		ipoib_warn(priv, "failed to create mcg debug file\n");
+
+	snprintf(name, sizeof name, "%s_path", dev->name);
+	priv->path_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+						ipoib_root, dev, &ipoib_path_fops);
+	if (!priv->path_dentry)
+		ipoib_warn(priv, "failed to create path debug file\n");
+}
+
+void ipoib_delete_debug_files(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
 	if (priv->mcg_dentry)
 		debugfs_remove(priv->mcg_dentry);
+	if (priv->path_dentry)
+		debugfs_remove(priv->path_dentry);
 }
 
 int ipoib_register_debugfs(void)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index ce02962..2fa3075 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -58,6 +58,11 @@
 MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
 #endif
 
+struct ipoib_path_iter {
+	struct net_device *dev;
+	struct ipoib_path  path;
+};
+
 static const u8 ipv4_bcast_addr[] = {
 	0x00, 0xff, 0xff, 0xff,
 	0xff, 0x12, 0x40, 0x1b,	0x00, 0x00, 0x00, 0x00,
@@ -250,6 +255,64 @@
 	kfree(path);
 }
 
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
+
+struct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev)
+{
+	struct ipoib_path_iter *iter;
+
+	iter = kmalloc(sizeof *iter, GFP_KERNEL);
+	if (!iter)
+		return NULL;
+
+	iter->dev = dev;
+	memset(iter->path.pathrec.dgid.raw, 0, 16);
+
+	if (ipoib_path_iter_next(iter)) {
+		kfree(iter);
+		return NULL;
+	}
+
+	return iter;
+}
+
+int ipoib_path_iter_next(struct ipoib_path_iter *iter)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(iter->dev);
+	struct rb_node *n;
+	struct ipoib_path *path;
+	int ret = 1;
+
+	spin_lock_irq(&priv->lock);
+
+	n = rb_first(&priv->path_tree);
+
+	while (n) {
+		path = rb_entry(n, struct ipoib_path, rb_node);
+
+		if (memcmp(iter->path.pathrec.dgid.raw, path->pathrec.dgid.raw,
+			   sizeof (union ib_gid)) < 0) {
+			iter->path = *path;
+			ret = 0;
+			break;
+		}
+
+		n = rb_next(n);
+	}
+
+	spin_unlock_irq(&priv->lock);
+
+	return ret;
+}
+
+void ipoib_path_iter_read(struct ipoib_path_iter *iter,
+			  struct ipoib_path *path)
+{
+	*path = iter->path;
+}
+
+#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */
+
 void ipoib_flush_paths(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -763,7 +826,7 @@
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv;
 
-	ipoib_delete_debug_file(dev);
+	ipoib_delete_debug_files(dev);
 
 	/* Delete any child interfaces first */
 	list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) {
@@ -972,8 +1035,7 @@
 		goto register_failed;
 	}
 
-	if (ipoib_create_debug_file(priv->dev))
-		goto debug_failed;
+	ipoib_create_debug_files(priv->dev);
 
 	if (ipoib_add_pkey_attr(priv->dev))
 		goto sysfs_failed;
@@ -987,9 +1049,7 @@
 	return priv->dev;
 
 sysfs_failed:
-	ipoib_delete_debug_file(priv->dev);
-
-debug_failed:
+	ipoib_delete_debug_files(priv->dev);
 	unregister_netdev(priv->dev);
 
 register_failed:
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 3ecf78a..c33ed87 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -120,12 +120,8 @@
 	if (mcast->ah)
 		ipoib_put_ah(mcast->ah);
 
-	while (!skb_queue_empty(&mcast->pkt_queue)) {
-		struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
-
-		skb->dev = dev;
-		dev_kfree_skb_any(skb);
-	}
+	while (!skb_queue_empty(&mcast->pkt_queue))
+		dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
 
 	kfree(mcast);
 }
@@ -317,13 +313,8 @@
 					IPOIB_GID_ARG(mcast->mcmember.mgid), status);
 
 		/* Flush out any queued packets */
-		while (!skb_queue_empty(&mcast->pkt_queue)) {
-			struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
-
-			skb->dev = dev;
-
-			dev_kfree_skb_any(skb);
-		}
+		while (!skb_queue_empty(&mcast->pkt_queue))
+			dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
 
 		/* Clear the busy flag so we try again */
 		clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
@@ -928,21 +919,16 @@
 		return NULL;
 
 	iter->dev = dev;
-	memset(iter->mgid.raw, 0, sizeof iter->mgid);
+	memset(iter->mgid.raw, 0, 16);
 
 	if (ipoib_mcast_iter_next(iter)) {
-		ipoib_mcast_iter_free(iter);
+		kfree(iter);
 		return NULL;
 	}
 
 	return iter;
 }
 
-void ipoib_mcast_iter_free(struct ipoib_mcast_iter *iter)
-{
-	kfree(iter);
-}
-
 int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(iter->dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 332d730..d280b34 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -113,8 +113,7 @@
 
 	priv->parent = ppriv->dev;
 
-	if (ipoib_create_debug_file(priv->dev))
-		goto debug_failed;
+	ipoib_create_debug_files(priv->dev);
 
 	if (ipoib_add_pkey_attr(priv->dev))
 		goto sysfs_failed;
@@ -130,9 +129,7 @@
 	return 0;
 
 sysfs_failed:
-	ipoib_delete_debug_file(priv->dev);
-
-debug_failed:
+	ipoib_delete_debug_files(priv->dev);
 	unregister_netdev(priv->dev);
 
 register_failed:
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 2687e34..321a3a1 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -32,7 +32,6 @@
  * $Id: ib_srp.c 3932 2005-11-01 17:19:29Z roland $
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 0879915..c8ae2bb 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -669,7 +669,7 @@
 		INPUT_ADD_HOTPLUG_VAR("NAME=\"%s\"", dev->name);
 	if (dev->phys)
 		INPUT_ADD_HOTPLUG_VAR("PHYS=\"%s\"", dev->phys);
-	if (dev->phys)
+	if (dev->uniq)
 		INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq);
 
 	INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX);
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index d00d14b..64672d4 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -259,17 +259,17 @@
 }
 
 #ifdef CONFIG_PM
-static int corgikbd_suspend(struct device *dev, pm_message_t state)
+static int corgikbd_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct corgikbd *corgikbd = dev_get_drvdata(dev);
+	struct corgikbd *corgikbd = platform_get_drvdata(dev);
 	corgikbd->suspended = 1;
 
 	return 0;
 }
 
-static int corgikbd_resume(struct device *dev)
+static int corgikbd_resume(struct platform_device *dev)
 {
-	struct corgikbd *corgikbd = dev_get_drvdata(dev);
+	struct corgikbd *corgikbd = platform_get_drvdata(dev);
 
 	/* Upon resume, ignore the suspend key for a short while */
 	corgikbd->suspend_jiffies=jiffies;
@@ -282,7 +282,7 @@
 #define corgikbd_resume		NULL
 #endif
 
-static int __init corgikbd_probe(struct device *dev)
+static int __init corgikbd_probe(struct platform_device *pdev)
 {
 	struct corgikbd *corgikbd;
 	struct input_dev *input_dev;
@@ -296,7 +296,7 @@
 		return -ENOMEM;
 	}
 
-	dev_set_drvdata(dev, corgikbd);
+	platform_set_drvdata(pdev, corgikbd);
 
 	corgikbd->input = input_dev;
 	spin_lock_init(&corgikbd->lock);
@@ -321,7 +321,7 @@
 	input_dev->id.vendor = 0x0001;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = dev;
+	input_dev->cdev.dev = &pdev->dev;
 	input_dev->private = corgikbd;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
@@ -356,10 +356,10 @@
 	return 0;
 }
 
-static int corgikbd_remove(struct device *dev)
+static int corgikbd_remove(struct platform_device *pdev)
 {
 	int i;
-	struct corgikbd *corgikbd = dev_get_drvdata(dev);
+	struct corgikbd *corgikbd = platform_get_drvdata(pdev);
 
 	for (i = 0; i < CORGI_KEY_SENSE_NUM; i++)
 		free_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd);
@@ -374,23 +374,24 @@
 	return 0;
 }
 
-static struct device_driver corgikbd_driver = {
-	.name		= "corgi-keyboard",
-	.bus		= &platform_bus_type,
+static struct platform_driver corgikbd_driver = {
 	.probe		= corgikbd_probe,
 	.remove		= corgikbd_remove,
 	.suspend	= corgikbd_suspend,
 	.resume		= corgikbd_resume,
+	.driver		= {
+		.name	= "corgi-keyboard",
+	},
 };
 
 static int __devinit corgikbd_init(void)
 {
-	return driver_register(&corgikbd_driver);
+	return platform_driver_register(&corgikbd_driver);
 }
 
 static void __exit corgikbd_exit(void)
 {
-	driver_unregister(&corgikbd_driver);
+	platform_driver_unregister(&corgikbd_driver);
 }
 
 module_init(corgikbd_init);
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index 0fa38a5..6a15fe3 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -309,10 +309,10 @@
 }
 
 #ifdef CONFIG_PM
-static int spitzkbd_suspend(struct device *dev, pm_message_t state)
+static int spitzkbd_suspend(struct platform_device *dev, pm_message_t state)
 {
 	int i;
-	struct spitzkbd *spitzkbd = dev_get_drvdata(dev);
+	struct spitzkbd *spitzkbd = platform_get_drvdata(dev);
 	spitzkbd->suspended = 1;
 
 	/* Set Strobe lines as inputs - *except* strobe line 0 leave this
@@ -323,10 +323,10 @@
 	return 0;
 }
 
-static int spitzkbd_resume(struct device *dev)
+static int spitzkbd_resume(struct platform_device *dev)
 {
 	int i;
-	struct spitzkbd *spitzkbd = dev_get_drvdata(dev);
+	struct spitzkbd *spitzkbd = platform_get_drvdata(dev);
 
 	for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++)
 		pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH);
@@ -342,7 +342,7 @@
 #define spitzkbd_resume		NULL
 #endif
 
-static int __init spitzkbd_probe(struct device *dev)
+static int __init spitzkbd_probe(struct platform_device *dev)
 {
 	struct spitzkbd *spitzkbd;
 	struct input_dev *input_dev;
@@ -358,7 +358,7 @@
 		return -ENOMEM;
 	}
 
-	dev_set_drvdata(dev, spitzkbd);
+	platform_set_drvdata(dev, spitzkbd);
 	strcpy(spitzkbd->phys, "spitzkbd/input0");
 
 	spin_lock_init(&spitzkbd->lock);
@@ -380,7 +380,7 @@
 	input_dev->private = spitzkbd;
 	input_dev->name = "Spitz Keyboard";
 	input_dev->phys = spitzkbd->phys;
-	input_dev->cdev.dev = dev;
+	input_dev->cdev.dev = &dev->dev;
 
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->id.vendor = 0x0001;
@@ -437,10 +437,10 @@
 	return 0;
 }
 
-static int spitzkbd_remove(struct device *dev)
+static int spitzkbd_remove(struct platform_device *dev)
 {
 	int i;
-	struct spitzkbd *spitzkbd = dev_get_drvdata(dev);
+	struct spitzkbd *spitzkbd = platform_get_drvdata(dev);
 
 	for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++)
 		free_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd);
@@ -460,23 +460,24 @@
 	return 0;
 }
 
-static struct device_driver spitzkbd_driver = {
-	.name		= "spitz-keyboard",
-	.bus		= &platform_bus_type,
+static struct platform_driver spitzkbd_driver = {
 	.probe		= spitzkbd_probe,
 	.remove		= spitzkbd_remove,
 	.suspend	= spitzkbd_suspend,
 	.resume		= spitzkbd_resume,
+	.driver		= {
+		.name	= "spitz-keyboard",
+	},
 };
 
 static int __devinit spitzkbd_init(void)
 {
-	return driver_register(&spitzkbd_driver);
+	return platform_driver_register(&spitzkbd_driver);
 }
 
 static void __exit spitzkbd_exit(void)
 {
-	driver_unregister(&spitzkbd_driver);
+	platform_driver_unregister(&spitzkbd_driver);
 }
 
 module_init(spitzkbd_init);
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 01e1864..ac86c1d 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -912,7 +912,7 @@
  * Here we try to restore the original BIOS settings
  */
 
-static int i8042_suspend(struct device *dev, pm_message_t state)
+static int i8042_suspend(struct platform_device *dev, pm_message_t state)
 {
 	del_timer_sync(&i8042_timer);
 	i8042_controller_reset();
@@ -925,7 +925,7 @@
  * Here we try to reset everything back to a state in which suspended
  */
 
-static int i8042_resume(struct device *dev)
+static int i8042_resume(struct platform_device *dev)
 {
 	int i;
 
@@ -964,17 +964,18 @@
  * because otherwise BIOSes will be confused.
  */
 
-static void i8042_shutdown(struct device *dev)
+static void i8042_shutdown(struct platform_device *dev)
 {
 	i8042_controller_cleanup();
 }
 
-static struct device_driver i8042_driver = {
-	.name		= "i8042",
-	.bus		= &platform_bus_type,
+static struct platform_driver i8042_driver = {
 	.suspend	= i8042_suspend,
 	.resume		= i8042_resume,
 	.shutdown	= i8042_shutdown,
+	.driver		= {
+		.name	= "i8042",
+	},
 };
 
 static int __init i8042_create_kbd_port(void)
@@ -1078,7 +1079,7 @@
 		goto err_platform_exit;
 	}
 
-	err = driver_register(&i8042_driver);
+	err = platform_driver_register(&i8042_driver);
 	if (err)
 		goto err_controller_cleanup;
 
@@ -1126,7 +1127,7 @@
  err_unregister_device:
 	platform_device_unregister(i8042_platform_device);
  err_unregister_driver:
-	driver_unregister(&i8042_driver);
+	platform_driver_unregister(&i8042_driver);
  err_controller_cleanup:
 	i8042_controller_cleanup();
  err_platform_exit:
@@ -1148,7 +1149,7 @@
 	del_timer_sync(&i8042_timer);
 
 	platform_device_unregister(i8042_platform_device);
-	driver_unregister(&i8042_driver);
+	platform_driver_unregister(&i8042_driver);
 
 	i8042_platform_exit();
 
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index 52c4925..a3bd115 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -107,7 +107,7 @@
  * Allocate and initialize serio structure for subsequent registration
  * with serio core.
  */
-static int __devinit rpckbd_probe(struct device *dev)
+static int __devinit rpckbd_probe(struct platform_device *dev)
 {
 	struct serio *serio;
 
@@ -120,37 +120,38 @@
 	serio->write		= rpckbd_write;
 	serio->open		= rpckbd_open;
 	serio->close		= rpckbd_close;
-	serio->dev.parent	= dev;
+	serio->dev.parent	= &dev->dev;
 	strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name));
 	strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys));
 
-	dev_set_drvdata(dev, serio);
+	platform_set_drvdata(dev, serio);
 	serio_register_port(serio);
 	return 0;
 }
 
-static int __devexit rpckbd_remove(struct device *dev)
+static int __devexit rpckbd_remove(struct platform_device *dev)
 {
-	struct serio *serio = dev_get_drvdata(dev);
+	struct serio *serio = platform_get_drvdata(dev);
 	serio_unregister_port(serio);
 	return 0;
 }
 
-static struct device_driver rpckbd_driver = {
-	.name		= "kart",
-	.bus		= &platform_bus_type,
+static struct platform_driver rpckbd_driver = {
 	.probe		= rpckbd_probe,
 	.remove		= __devexit_p(rpckbd_remove),
+	.driver		= {
+		.name	= "kart",
+	},
 };
 
 static int __init rpckbd_init(void)
 {
-	return driver_register(&rpckbd_driver);
+	return platform_driver_register(&rpckbd_driver);
 }
 
 static void __exit rpckbd_exit(void)
 {
-	driver_unregister(&rpckbd_driver);
+	platform_driver_unregister(&rpckbd_driver);
 }
 
 module_init(rpckbd_init);
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index 15e88ee..1042987 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -231,9 +231,9 @@
 }
 
 #ifdef CONFIG_PM
-static int corgits_suspend(struct device *dev, pm_message_t state)
+static int corgits_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
+	struct corgi_ts *corgi_ts = platform_get_drvdata(dev);
 
 	if (corgi_ts->pendown) {
 		del_timer_sync(&corgi_ts->timer);
@@ -248,9 +248,9 @@
 	return 0;
 }
 
-static int corgits_resume(struct device *dev)
+static int corgits_resume(struct platform_device *dev)
 {
-	struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
+	struct corgi_ts *corgi_ts = platform_get_drvdata(dev);
 
 	corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
 	/* Enable Falling Edge */
@@ -264,10 +264,9 @@
 #define corgits_resume		NULL
 #endif
 
-static int __init corgits_probe(struct device *dev)
+static int __init corgits_probe(struct platform_device *pdev)
 {
 	struct corgi_ts *corgi_ts;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct input_dev *input_dev;
 	int err = -ENOMEM;
 
@@ -276,9 +275,9 @@
 	if (!corgi_ts || !input_dev)
 		goto fail;
 
-	dev_set_drvdata(dev, corgi_ts);
+	platform_set_drvdata(pdev, corgi_ts);
 
-	corgi_ts->machinfo = dev->platform_data;
+	corgi_ts->machinfo = pdev->dev.platform_data;
 	corgi_ts->irq_gpio = platform_get_irq(pdev, 0);
 
 	if (corgi_ts->irq_gpio < 0) {
@@ -298,7 +297,7 @@
 	input_dev->id.vendor = 0x0001;
 	input_dev->id.product = 0x0002;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = dev;
+	input_dev->cdev.dev = &pdev->dev;
 	input_dev->private = corgi_ts;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
@@ -339,9 +338,9 @@
 
 }
 
-static int corgits_remove(struct device *dev)
+static int corgits_remove(struct platform_device *pdev)
 {
-	struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
+	struct corgi_ts *corgi_ts = platform_get_drvdata(pdev);
 
 	free_irq(corgi_ts->irq_gpio, NULL);
 	del_timer_sync(&corgi_ts->timer);
@@ -351,23 +350,24 @@
 	return 0;
 }
 
-static struct device_driver corgits_driver = {
-	.name		= "corgi-ts",
-	.bus		= &platform_bus_type,
+static struct platform_driver corgits_driver = {
 	.probe		= corgits_probe,
 	.remove		= corgits_remove,
 	.suspend	= corgits_suspend,
 	.resume		= corgits_resume,
+	.driver		= {
+		.name	= "corgi-ts",
+	},
 };
 
 static int __devinit corgits_init(void)
 {
-	return driver_register(&corgits_driver);
+	return platform_driver_register(&corgits_driver);
 }
 
 static void __exit corgits_exit(void)
 {
-	driver_unregister(&corgits_driver);
+	platform_driver_unregister(&corgits_driver);
 }
 
 module_init(corgits_init);
diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c
index 434e684..2f7c9fc 100644
--- a/drivers/isdn/divert/divert_init.c
+++ b/drivers/isdn/divert/divert_init.c
@@ -10,7 +10,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 0b0ea26..1b37d86 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -11,7 +11,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
 #ifdef CONFIG_PROC_FS
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index 0bfd698..f1a1f9a 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -9,7 +9,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/proc_fs.h>
 
 #include "isdn_divert.h"
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
index b4d795d..dc7ef95 100644
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -23,7 +23,6 @@
  * o tx_skb at PH_DEACTIVATE time
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
index 2cf5d1a..8e192a3 100644
--- a/drivers/isdn/hisax/st5481_init.c
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -25,7 +25,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
index 1fd3d4e..acc1d3c 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -11,7 +11,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/signal.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 12c8137..cb791f8 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -13,7 +13,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index babec81..aa01628 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -14,7 +14,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/signal.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 87f59a0..40e5614 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -12,7 +12,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 4d57011..6c26f1e 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -11,7 +11,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 8a7d54a..4643df0 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -14,7 +14,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
 #include <linux/isdn.h>
diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h
index 9028cc3..7d7245f 100644
--- a/drivers/isdn/icn/icn.h
+++ b/drivers/isdn/icn/icn.h
@@ -35,7 +35,6 @@
 #ifdef __KERNEL__
 /* Kernel includes */
 
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
index 8fb7bc1..d699fe5 100644
--- a/drivers/isdn/isdnloop/isdnloop.h
+++ b/drivers/isdn/isdnloop/isdnloop.h
@@ -33,7 +33,6 @@
 #ifdef __KERNEL__
 /* Kernel includes */
 
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
diff --git a/drivers/isdn/sc/includes.h b/drivers/isdn/sc/includes.h
index 4611da6..5286e0c 100644
--- a/drivers/isdn/sc/includes.h
+++ b/drivers/isdn/sc/includes.h
@@ -4,7 +4,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <asm/io.h>
 #include <linux/delay.h>
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 01654fc..5131530 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -272,7 +271,8 @@
 		return ERR_PTR(-ENOMEM);
 
 	ITERATE_RDEV(mddev, rdev, tmp) {
-		if (! rdev->in_sync || rdev->faulty)
+		if (! test_bit(In_sync, &rdev->flags)
+		    || test_bit(Faulty, &rdev->flags))
 			continue;
 
 		target = (rdev->sb_offset << 1) + offset + index * (PAGE_SIZE/512);
@@ -292,7 +292,8 @@
 	struct list_head *tmp;
 
 	ITERATE_RDEV(mddev, rdev, tmp)
-		if (rdev->in_sync && !rdev->faulty)
+		if (test_bit(In_sync, &rdev->flags)
+		    && !test_bit(Faulty, &rdev->flags))
 			md_super_write(mddev, rdev,
 				       (rdev->sb_offset<<1) + offset
 				       + page->index * (PAGE_SIZE/512),
@@ -300,7 +301,7 @@
 				       page);
 
 	if (wait)
-		wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+		md_super_wait(mddev);
 	return 0;
 }
 
@@ -481,7 +482,8 @@
 	/* verify that the bitmap-specific fields are valid */
 	if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
 		reason = "bad magic";
-	else if (sb->version != cpu_to_le32(BITMAP_MAJOR))
+	else if (le32_to_cpu(sb->version) < BITMAP_MAJOR_LO ||
+		 le32_to_cpu(sb->version) > BITMAP_MAJOR_HI)
 		reason = "unrecognized superblock version";
 	else if (chunksize < 512 || chunksize > (1024 * 1024 * 4))
 		reason = "bitmap chunksize out of range (512B - 4MB)";
@@ -526,6 +528,8 @@
 	bitmap->daemon_lastrun = jiffies;
 	bitmap->max_write_behind = write_behind;
 	bitmap->flags |= sb->state;
+	if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
+		bitmap->flags |= BITMAP_HOSTENDIAN;
 	bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
 	if (sb->state & BITMAP_STALE)
 		bitmap->events_cleared = bitmap->mddev->events;
@@ -763,7 +767,10 @@
 
  	/* set the bit */
 	kaddr = kmap_atomic(page, KM_USER0);
-	set_bit(bit, kaddr);
+	if (bitmap->flags & BITMAP_HOSTENDIAN)
+		set_bit(bit, kaddr);
+	else
+		ext2_set_bit(bit, kaddr);
 	kunmap_atomic(kaddr, KM_USER0);
 	PRINTK("set file bit %lu page %lu\n", bit, page->index);
 
@@ -821,8 +828,7 @@
 					    wake_up_process(bitmap->writeback_daemon->tsk));
 			spin_unlock_irq(&bitmap->write_lock);
 		} else
-			wait_event(bitmap->mddev->sb_wait,
-				   atomic_read(&bitmap->mddev->pending_writes)==0);
+			md_super_wait(bitmap->mddev);
 	}
 	return 0;
 }
@@ -890,6 +896,7 @@
 	oldindex = ~0L;
 
 	for (i = 0; i < chunks; i++) {
+		int b;
 		index = file_page_index(i);
 		bit = file_page_offset(i);
 		if (index != oldindex) { /* this is a new page, read it in */
@@ -938,7 +945,11 @@
 
 			bitmap->filemap[bitmap->file_pages++] = page;
 		}
-		if (test_bit(bit, page_address(page))) {
+		if (bitmap->flags & BITMAP_HOSTENDIAN)
+			b = test_bit(bit, page_address(page));
+		else
+			b = ext2_test_bit(bit, page_address(page));
+		if (b) {
 			/* if the disk bit is set, set the memory bit */
 			bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap),
 					       ((i+1) << (CHUNK_BLOCK_SHIFT(bitmap)) >= start)
@@ -1096,7 +1107,10 @@
 						  -1);
 
 				/* clear the bit */
-				clear_bit(file_page_offset(j), page_address(page));
+				if (bitmap->flags & BITMAP_HOSTENDIAN)
+					clear_bit(file_page_offset(j), page_address(page));
+				else
+					ext2_clear_bit(file_page_offset(j), page_address(page));
 			}
 		}
 		spin_unlock_irqrestore(&bitmap->lock, flags);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 9ecf51e..adf960d 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -131,6 +131,8 @@
 
 static struct block_device_operations md_fops;
 
+static int start_readonly;
+
 /*
  * Enables to iterate over all existing md arrays
  * all_mddevs_lock protects this list.
@@ -181,7 +183,7 @@
 	if (!mddev->raid_disks && list_empty(&mddev->disks)) {
 		list_del(&mddev->all_mddevs);
 		blk_put_queue(mddev->queue);
-		kfree(mddev);
+		kobject_unregister(&mddev->kobj);
 	}
 	spin_unlock(&all_mddevs_lock);
 }
@@ -330,18 +332,46 @@
 static int super_written(struct bio *bio, unsigned int bytes_done, int error)
 {
 	mdk_rdev_t *rdev = bio->bi_private;
+	mddev_t *mddev = rdev->mddev;
 	if (bio->bi_size)
 		return 1;
 
 	if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags))
-		md_error(rdev->mddev, rdev);
+		md_error(mddev, rdev);
 
-	if (atomic_dec_and_test(&rdev->mddev->pending_writes))
-		wake_up(&rdev->mddev->sb_wait);
+	if (atomic_dec_and_test(&mddev->pending_writes))
+		wake_up(&mddev->sb_wait);
 	bio_put(bio);
 	return 0;
 }
 
+static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int error)
+{
+	struct bio *bio2 = bio->bi_private;
+	mdk_rdev_t *rdev = bio2->bi_private;
+	mddev_t *mddev = rdev->mddev;
+	if (bio->bi_size)
+		return 1;
+
+	if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
+	    error == -EOPNOTSUPP) {
+		unsigned long flags;
+		/* barriers don't appear to be supported :-( */
+		set_bit(BarriersNotsupp, &rdev->flags);
+		mddev->barriers_work = 0;
+		spin_lock_irqsave(&mddev->write_lock, flags);
+		bio2->bi_next = mddev->biolist;
+		mddev->biolist = bio2;
+		spin_unlock_irqrestore(&mddev->write_lock, flags);
+		wake_up(&mddev->sb_wait);
+		bio_put(bio);
+		return 0;
+	}
+	bio_put(bio2);
+	bio->bi_private = rdev;
+	return super_written(bio, bytes_done, error);
+}
+
 void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
 		   sector_t sector, int size, struct page *page)
 {
@@ -350,16 +380,54 @@
 	 * and decrement it on completion, waking up sb_wait
 	 * if zero is reached.
 	 * If an error occurred, call md_error
+	 *
+	 * As we might need to resubmit the request if BIO_RW_BARRIER
+	 * causes ENOTSUPP, we allocate a spare bio...
 	 */
 	struct bio *bio = bio_alloc(GFP_NOIO, 1);
+	int rw = (1<<BIO_RW) | (1<<BIO_RW_SYNC);
 
 	bio->bi_bdev = rdev->bdev;
 	bio->bi_sector = sector;
 	bio_add_page(bio, page, size, 0);
 	bio->bi_private = rdev;
 	bio->bi_end_io = super_written;
+	bio->bi_rw = rw;
+
 	atomic_inc(&mddev->pending_writes);
-	submit_bio((1<<BIO_RW)|(1<<BIO_RW_SYNC), bio);
+	if (!test_bit(BarriersNotsupp, &rdev->flags)) {
+		struct bio *rbio;
+		rw |= (1<<BIO_RW_BARRIER);
+		rbio = bio_clone(bio, GFP_NOIO);
+		rbio->bi_private = bio;
+		rbio->bi_end_io = super_written_barrier;
+		submit_bio(rw, rbio);
+	} else
+		submit_bio(rw, bio);
+}
+
+void md_super_wait(mddev_t *mddev)
+{
+	/* wait for all superblock writes that were scheduled to complete.
+	 * if any had to be retried (due to BARRIER problems), retry them
+	 */
+	DEFINE_WAIT(wq);
+	for(;;) {
+		prepare_to_wait(&mddev->sb_wait, &wq, TASK_UNINTERRUPTIBLE);
+		if (atomic_read(&mddev->pending_writes)==0)
+			break;
+		while (mddev->biolist) {
+			struct bio *bio;
+			spin_lock_irq(&mddev->write_lock);
+			bio = mddev->biolist;
+			mddev->biolist = bio->bi_next ;
+			bio->bi_next = NULL;
+			spin_unlock_irq(&mddev->write_lock);
+			submit_bio(bio->bi_rw, bio);
+		}
+		schedule();
+	}
+	finish_wait(&mddev->sb_wait, &wq);
 }
 
 static int bi_complete(struct bio *bio, unsigned int bytes_done, int error)
@@ -610,7 +678,7 @@
 	mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page);
 
 	rdev->raid_disk = -1;
-	rdev->in_sync = 0;
+	rdev->flags = 0;
 	if (mddev->raid_disks == 0) {
 		mddev->major_version = 0;
 		mddev->minor_version = sb->minor_version;
@@ -671,21 +739,19 @@
 		return 0;
 
 	if (mddev->level != LEVEL_MULTIPATH) {
-		rdev->faulty = 0;
-		rdev->flags = 0;
 		desc = sb->disks + rdev->desc_nr;
 
 		if (desc->state & (1<<MD_DISK_FAULTY))
-			rdev->faulty = 1;
+			set_bit(Faulty, &rdev->flags);
 		else if (desc->state & (1<<MD_DISK_SYNC) &&
 			 desc->raid_disk < mddev->raid_disks) {
-			rdev->in_sync = 1;
+			set_bit(In_sync, &rdev->flags);
 			rdev->raid_disk = desc->raid_disk;
 		}
 		if (desc->state & (1<<MD_DISK_WRITEMOSTLY))
 			set_bit(WriteMostly, &rdev->flags);
 	} else /* MULTIPATH are always insync */
-		rdev->in_sync = 1;
+		set_bit(In_sync, &rdev->flags);
 	return 0;
 }
 
@@ -699,6 +765,7 @@
 	mdk_rdev_t *rdev2;
 	int next_spare = mddev->raid_disks;
 
+
 	/* make rdev->sb match mddev data..
 	 *
 	 * 1/ zero out disks
@@ -758,23 +825,27 @@
 	sb->disks[0].state = (1<<MD_DISK_REMOVED);
 	ITERATE_RDEV(mddev,rdev2,tmp) {
 		mdp_disk_t *d;
-		if (rdev2->raid_disk >= 0 && rdev2->in_sync && !rdev2->faulty)
-			rdev2->desc_nr = rdev2->raid_disk;
+		int desc_nr;
+		if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
+		    && !test_bit(Faulty, &rdev2->flags))
+			desc_nr = rdev2->raid_disk;
 		else
-			rdev2->desc_nr = next_spare++;
+			desc_nr = next_spare++;
+		rdev2->desc_nr = desc_nr;
 		d = &sb->disks[rdev2->desc_nr];
 		nr_disks++;
 		d->number = rdev2->desc_nr;
 		d->major = MAJOR(rdev2->bdev->bd_dev);
 		d->minor = MINOR(rdev2->bdev->bd_dev);
-		if (rdev2->raid_disk >= 0 && rdev->in_sync && !rdev2->faulty)
+		if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
+		    && !test_bit(Faulty, &rdev2->flags))
 			d->raid_disk = rdev2->raid_disk;
 		else
 			d->raid_disk = rdev2->desc_nr; /* compatibility */
-		if (rdev2->faulty) {
+		if (test_bit(Faulty, &rdev2->flags)) {
 			d->state = (1<<MD_DISK_FAULTY);
 			failed++;
-		} else if (rdev2->in_sync) {
+		} else if (test_bit(In_sync, &rdev2->flags)) {
 			d->state = (1<<MD_DISK_ACTIVE);
 			d->state |= (1<<MD_DISK_SYNC);
 			active++;
@@ -787,7 +858,6 @@
 		if (test_bit(WriteMostly, &rdev2->flags))
 			d->state |= (1<<MD_DISK_WRITEMOSTLY);
 	}
-	
 	/* now set the "removed" and "faulty" bits on any missing devices */
 	for (i=0 ; i < mddev->raid_disks ; i++) {
 		mdp_disk_t *d = &sb->disks[i];
@@ -944,7 +1014,7 @@
 	struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);
 
 	rdev->raid_disk = -1;
-	rdev->in_sync = 0;
+	rdev->flags = 0;
 	if (mddev->raid_disks == 0) {
 		mddev->major_version = 1;
 		mddev->patch_version = 0;
@@ -996,22 +1066,19 @@
 		role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
 		switch(role) {
 		case 0xffff: /* spare */
-			rdev->faulty = 0;
 			break;
 		case 0xfffe: /* faulty */
-			rdev->faulty = 1;
+			set_bit(Faulty, &rdev->flags);
 			break;
 		default:
-			rdev->in_sync = 1;
-			rdev->faulty = 0;
+			set_bit(In_sync, &rdev->flags);
 			rdev->raid_disk = role;
 			break;
 		}
-		rdev->flags = 0;
 		if (sb->devflags & WriteMostly1)
 			set_bit(WriteMostly, &rdev->flags);
 	} else /* MULTIPATH are always insync */
-		rdev->in_sync = 1;
+		set_bit(In_sync, &rdev->flags);
 
 	return 0;
 }
@@ -1055,9 +1122,9 @@
 	
 	ITERATE_RDEV(mddev,rdev2,tmp) {
 		i = rdev2->desc_nr;
-		if (rdev2->faulty)
+		if (test_bit(Faulty, &rdev2->flags))
 			sb->dev_roles[i] = cpu_to_le16(0xfffe);
-		else if (rdev2->in_sync)
+		else if (test_bit(In_sync, &rdev2->flags))
 			sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
 		else
 			sb->dev_roles[i] = cpu_to_le16(0xffff);
@@ -1115,6 +1182,7 @@
 {
 	mdk_rdev_t *same_pdev;
 	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
+	struct kobject *ko;
 
 	if (rdev->mddev) {
 		MD_BUG();
@@ -1143,10 +1211,22 @@
 		if (find_rdev_nr(mddev, rdev->desc_nr))
 			return -EBUSY;
 	}
+	bdevname(rdev->bdev,b);
+	if (kobject_set_name(&rdev->kobj, "dev-%s", b) < 0)
+		return -ENOMEM;
 			
 	list_add(&rdev->same_set, &mddev->disks);
 	rdev->mddev = mddev;
-	printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b));
+	printk(KERN_INFO "md: bind<%s>\n", b);
+
+	rdev->kobj.parent = &mddev->kobj;
+	kobject_add(&rdev->kobj);
+
+	if (rdev->bdev->bd_part)
+		ko = &rdev->bdev->bd_part->kobj;
+	else
+		ko = &rdev->bdev->bd_disk->kobj;
+	sysfs_create_link(&rdev->kobj, ko, "block");
 	return 0;
 }
 
@@ -1160,6 +1240,8 @@
 	list_del_init(&rdev->same_set);
 	printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
 	rdev->mddev = NULL;
+	sysfs_remove_link(&rdev->kobj, "block");
+	kobject_del(&rdev->kobj);
 }
 
 /*
@@ -1215,7 +1297,7 @@
 	md_autodetect_dev(rdev->bdev->bd_dev);
 #endif
 	unlock_rdev(rdev);
-	kfree(rdev);
+	kobject_put(&rdev->kobj);
 }
 
 static void kick_rdev_from_array(mdk_rdev_t * rdev)
@@ -1287,7 +1369,8 @@
 	char b[BDEVNAME_SIZE];
 	printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n",
 		bdevname(rdev->bdev,b), (unsigned long long)rdev->size,
-	       	rdev->faulty, rdev->in_sync, rdev->desc_nr);
+	        test_bit(Faulty, &rdev->flags), test_bit(In_sync, &rdev->flags),
+	        rdev->desc_nr);
 	if (rdev->sb_loaded) {
 		printk(KERN_INFO "md: rdev superblock:\n");
 		print_sb((mdp_super_t*)page_address(rdev->sb_page));
@@ -1344,7 +1427,7 @@
 	int sync_req;
 
 repeat:
-	spin_lock(&mddev->write_lock);
+	spin_lock_irq(&mddev->write_lock);
 	sync_req = mddev->in_sync;
 	mddev->utime = get_seconds();
 	mddev->events ++;
@@ -1367,11 +1450,11 @@
 	 */
 	if (!mddev->persistent) {
 		mddev->sb_dirty = 0;
-		spin_unlock(&mddev->write_lock);
+		spin_unlock_irq(&mddev->write_lock);
 		wake_up(&mddev->sb_wait);
 		return;
 	}
-	spin_unlock(&mddev->write_lock);
+	spin_unlock_irq(&mddev->write_lock);
 
 	dprintk(KERN_INFO 
 		"md: updating %s RAID superblock on device (in sync %d)\n",
@@ -1381,11 +1464,11 @@
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		char b[BDEVNAME_SIZE];
 		dprintk(KERN_INFO "md: ");
-		if (rdev->faulty)
+		if (test_bit(Faulty, &rdev->flags))
 			dprintk("(skipping faulty ");
 
 		dprintk("%s ", bdevname(rdev->bdev,b));
-		if (!rdev->faulty) {
+		if (!test_bit(Faulty, &rdev->flags)) {
 			md_super_write(mddev,rdev,
 				       rdev->sb_offset<<1, rdev->sb_size,
 				       rdev->sb_page);
@@ -1399,21 +1482,106 @@
 			/* only need to write one superblock... */
 			break;
 	}
-	wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+	md_super_wait(mddev);
 	/* if there was a failure, sb_dirty was set to 1, and we re-write super */
 
-	spin_lock(&mddev->write_lock);
+	spin_lock_irq(&mddev->write_lock);
 	if (mddev->in_sync != sync_req|| mddev->sb_dirty == 1) {
 		/* have to write it out again */
-		spin_unlock(&mddev->write_lock);
+		spin_unlock_irq(&mddev->write_lock);
 		goto repeat;
 	}
 	mddev->sb_dirty = 0;
-	spin_unlock(&mddev->write_lock);
+	spin_unlock_irq(&mddev->write_lock);
 	wake_up(&mddev->sb_wait);
 
 }
 
+struct rdev_sysfs_entry {
+	struct attribute attr;
+	ssize_t (*show)(mdk_rdev_t *, char *);
+	ssize_t (*store)(mdk_rdev_t *, const char *, size_t);
+};
+
+static ssize_t
+state_show(mdk_rdev_t *rdev, char *page)
+{
+	char *sep = "";
+	int len=0;
+
+	if (test_bit(Faulty, &rdev->flags)) {
+		len+= sprintf(page+len, "%sfaulty",sep);
+		sep = ",";
+	}
+	if (test_bit(In_sync, &rdev->flags)) {
+		len += sprintf(page+len, "%sin_sync",sep);
+		sep = ",";
+	}
+	if (!test_bit(Faulty, &rdev->flags) &&
+	    !test_bit(In_sync, &rdev->flags)) {
+		len += sprintf(page+len, "%sspare", sep);
+		sep = ",";
+	}
+	return len+sprintf(page+len, "\n");
+}
+
+static struct rdev_sysfs_entry
+rdev_state = __ATTR_RO(state);
+
+static ssize_t
+super_show(mdk_rdev_t *rdev, char *page)
+{
+	if (rdev->sb_loaded && rdev->sb_size) {
+		memcpy(page, page_address(rdev->sb_page), rdev->sb_size);
+		return rdev->sb_size;
+	} else
+		return 0;
+}
+static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super);
+
+static struct attribute *rdev_default_attrs[] = {
+	&rdev_state.attr,
+	&rdev_super.attr,
+	NULL,
+};
+static ssize_t
+rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+	struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
+	mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+
+	if (!entry->show)
+		return -EIO;
+	return entry->show(rdev, page);
+}
+
+static ssize_t
+rdev_attr_store(struct kobject *kobj, struct attribute *attr,
+	      const char *page, size_t length)
+{
+	struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
+	mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+
+	if (!entry->store)
+		return -EIO;
+	return entry->store(rdev, page, length);
+}
+
+static void rdev_free(struct kobject *ko)
+{
+	mdk_rdev_t *rdev = container_of(ko, mdk_rdev_t, kobj);
+	kfree(rdev);
+}
+static struct sysfs_ops rdev_sysfs_ops = {
+	.show		= rdev_attr_show,
+	.store		= rdev_attr_store,
+};
+static struct kobj_type rdev_ktype = {
+	.release	= rdev_free,
+	.sysfs_ops	= &rdev_sysfs_ops,
+	.default_attrs	= rdev_default_attrs,
+};
+
 /*
  * Import a device. If 'super_format' >= 0, then sanity check the superblock
  *
@@ -1445,11 +1613,15 @@
 	if (err)
 		goto abort_free;
 
+	rdev->kobj.parent = NULL;
+	rdev->kobj.ktype = &rdev_ktype;
+	kobject_init(&rdev->kobj);
+
 	rdev->desc_nr = -1;
-	rdev->faulty = 0;
-	rdev->in_sync = 0;
+	rdev->flags = 0;
 	rdev->data_offset = 0;
 	atomic_set(&rdev->nr_pending, 0);
+	atomic_set(&rdev->read_errors, 0);
 
 	size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
 	if (!size) {
@@ -1537,7 +1709,7 @@
 		if (mddev->level == LEVEL_MULTIPATH) {
 			rdev->desc_nr = i++;
 			rdev->raid_disk = rdev->desc_nr;
-			rdev->in_sync = 1;
+			set_bit(In_sync, &rdev->flags);
 		}
 	}
 
@@ -1551,6 +1723,162 @@
 
 }
 
+static ssize_t
+level_show(mddev_t *mddev, char *page)
+{
+	mdk_personality_t *p = mddev->pers;
+	if (p == NULL && mddev->raid_disks == 0)
+		return 0;
+	if (mddev->level >= 0)
+		return sprintf(page, "RAID-%d\n", mddev->level);
+	else
+		return sprintf(page, "%s\n", p->name);
+}
+
+static struct md_sysfs_entry md_level = __ATTR_RO(level);
+
+static ssize_t
+raid_disks_show(mddev_t *mddev, char *page)
+{
+	if (mddev->raid_disks == 0)
+		return 0;
+	return sprintf(page, "%d\n", mddev->raid_disks);
+}
+
+static struct md_sysfs_entry md_raid_disks = __ATTR_RO(raid_disks);
+
+static ssize_t
+action_show(mddev_t *mddev, char *page)
+{
+	char *type = "idle";
+	if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+	    test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) {
+		if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+			if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+				type = "resync";
+			else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+				type = "check";
+			else
+				type = "repair";
+		} else
+			type = "recover";
+	}
+	return sprintf(page, "%s\n", type);
+}
+
+static ssize_t
+action_store(mddev_t *mddev, const char *page, size_t len)
+{
+	if (!mddev->pers || !mddev->pers->sync_request)
+		return -EINVAL;
+
+	if (strcmp(page, "idle")==0 || strcmp(page, "idle\n")==0) {
+		if (mddev->sync_thread) {
+			set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+			md_unregister_thread(mddev->sync_thread);
+			mddev->sync_thread = NULL;
+			mddev->recovery = 0;
+		}
+		return len;
+	}
+
+	if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+	    test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
+		return -EBUSY;
+	if (strcmp(page, "resync")==0 || strcmp(page, "resync\n")==0 ||
+	    strcmp(page, "recover")==0 || strcmp(page, "recover\n")==0)
+		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+	else {
+		if (strcmp(page, "check")==0 || strcmp(page, "check\n")==0)
+			set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+		else if (strcmp(page, "repair")!=0 && strcmp(page, "repair\n")!=0)
+			return -EINVAL;
+		set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
+		set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+	}
+	md_wakeup_thread(mddev->thread);
+	return len;
+}
+
+static ssize_t
+mismatch_cnt_show(mddev_t *mddev, char *page)
+{
+	return sprintf(page, "%llu\n",
+		       (unsigned long long) mddev->resync_mismatches);
+}
+
+static struct md_sysfs_entry
+md_scan_mode = __ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
+
+
+static struct md_sysfs_entry
+md_mismatches = __ATTR_RO(mismatch_cnt);
+
+static struct attribute *md_default_attrs[] = {
+	&md_level.attr,
+	&md_raid_disks.attr,
+	NULL,
+};
+
+static struct attribute *md_redundancy_attrs[] = {
+	&md_scan_mode.attr,
+	&md_mismatches.attr,
+	NULL,
+};
+static struct attribute_group md_redundancy_group = {
+	.name = NULL,
+	.attrs = md_redundancy_attrs,
+};
+
+
+static ssize_t
+md_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+	struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr);
+	mddev_t *mddev = container_of(kobj, struct mddev_s, kobj);
+	ssize_t rv;
+
+	if (!entry->show)
+		return -EIO;
+	mddev_lock(mddev);
+	rv = entry->show(mddev, page);
+	mddev_unlock(mddev);
+	return rv;
+}
+
+static ssize_t
+md_attr_store(struct kobject *kobj, struct attribute *attr,
+	      const char *page, size_t length)
+{
+	struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr);
+	mddev_t *mddev = container_of(kobj, struct mddev_s, kobj);
+	ssize_t rv;
+
+	if (!entry->store)
+		return -EIO;
+	mddev_lock(mddev);
+	rv = entry->store(mddev, page, length);
+	mddev_unlock(mddev);
+	return rv;
+}
+
+static void md_free(struct kobject *ko)
+{
+	mddev_t *mddev = container_of(ko, mddev_t, kobj);
+	kfree(mddev);
+}
+
+static struct sysfs_ops md_sysfs_ops = {
+	.show	= md_attr_show,
+	.store	= md_attr_store,
+};
+static struct kobj_type md_ktype = {
+	.release	= md_free,
+	.sysfs_ops	= &md_sysfs_ops,
+	.default_attrs	= md_default_attrs,
+};
+
 int mdp_major = 0;
 
 static struct kobject *md_probe(dev_t dev, int *part, void *data)
@@ -1592,6 +1920,11 @@
 	add_disk(disk);
 	mddev->gendisk = disk;
 	up(&disks_sem);
+	mddev->kobj.parent = &disk->kobj;
+	mddev->kobj.k_name = NULL;
+	snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
+	mddev->kobj.ktype = &md_ktype;
+	kobject_register(&mddev->kobj);
 	return NULL;
 }
 
@@ -1663,7 +1996,7 @@
 
 		/* devices must have minimum size of one chunk */
 		ITERATE_RDEV(mddev,rdev,tmp) {
-			if (rdev->faulty)
+			if (test_bit(Faulty, &rdev->flags))
 				continue;
 			if (rdev->size < chunk_size / 1024) {
 				printk(KERN_WARNING
@@ -1691,7 +2024,7 @@
 	 * Also find largest hardsector size
 	 */
 	ITERATE_RDEV(mddev,rdev,tmp) {
-		if (rdev->faulty)
+		if (test_bit(Faulty, &rdev->flags))
 			continue;
 		sync_blockdev(rdev->bdev);
 		invalidate_bdev(rdev->bdev, 0);
@@ -1715,6 +2048,10 @@
 
 	mddev->recovery = 0;
 	mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
+	mddev->barriers_work = 1;
+
+	if (start_readonly)
+		mddev->ro = 2; /* read-only, but switch on first write */
 
 	/* before we start the array running, initialise the bitmap */
 	err = bitmap_create(mddev);
@@ -1730,12 +2067,24 @@
 		bitmap_destroy(mddev);
 		return err;
 	}
+	if (mddev->pers->sync_request)
+		sysfs_create_group(&mddev->kobj, &md_redundancy_group);
+	else if (mddev->ro == 2) /* auto-readonly not meaningful */
+		mddev->ro = 0;
+
  	atomic_set(&mddev->writes_pending,0);
 	mddev->safemode = 0;
 	mddev->safemode_timer.function = md_safemode_timeout;
 	mddev->safemode_timer.data = (unsigned long) mddev;
 	mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */
 	mddev->in_sync = 1;
+
+	ITERATE_RDEV(mddev,rdev,tmp)
+		if (rdev->raid_disk >= 0) {
+			char nm[20];
+			sprintf(nm, "rd%d", rdev->raid_disk);
+			sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
+		}
 	
 	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 	md_wakeup_thread(mddev->thread);
@@ -1821,16 +2170,19 @@
 
 		if (ro) {
 			err  = -ENXIO;
-			if (mddev->ro)
+			if (mddev->ro==1)
 				goto out;
 			mddev->ro = 1;
 		} else {
 			bitmap_flush(mddev);
-			wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+			md_super_wait(mddev);
 			if (mddev->ro)
 				set_disk_ro(disk, 0);
 			blk_queue_make_request(mddev->queue, md_fail_request);
 			mddev->pers->stop(mddev);
+			if (mddev->pers->sync_request)
+				sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
+
 			module_put(mddev->pers->owner);
 			mddev->pers = NULL;
 			if (mddev->ro)
@@ -1857,9 +2209,18 @@
 	 * Free resources if final stop
 	 */
 	if (!ro) {
+		mdk_rdev_t *rdev;
+		struct list_head *tmp;
 		struct gendisk *disk;
 		printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
 
+		ITERATE_RDEV(mddev,rdev,tmp)
+			if (rdev->raid_disk >= 0) {
+				char nm[20];
+				sprintf(nm, "rd%d", rdev->raid_disk);
+				sysfs_remove_link(&mddev->kobj, nm);
+			}
+
 		export_array(mddev);
 
 		mddev->array_size = 0;
@@ -2012,7 +2373,7 @@
 		return err;
 	}
 
-	if (start_rdev->faulty) {
+	if (test_bit(Faulty, &start_rdev->flags)) {
 		printk(KERN_WARNING 
 			"md: can not autostart based on faulty %s!\n",
 			bdevname(start_rdev->bdev,b));
@@ -2071,11 +2432,11 @@
 	nr=working=active=failed=spare=0;
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		nr++;
-		if (rdev->faulty)
+		if (test_bit(Faulty, &rdev->flags))
 			failed++;
 		else {
 			working++;
-			if (rdev->in_sync)
+			if (test_bit(In_sync, &rdev->flags))
 				active++;	
 			else
 				spare++;
@@ -2166,9 +2527,9 @@
 		info.minor = MINOR(rdev->bdev->bd_dev);
 		info.raid_disk = rdev->raid_disk;
 		info.state = 0;
-		if (rdev->faulty)
+		if (test_bit(Faulty, &rdev->flags))
 			info.state |= (1<<MD_DISK_FAULTY);
-		else if (rdev->in_sync) {
+		else if (test_bit(In_sync, &rdev->flags)) {
 			info.state |= (1<<MD_DISK_ACTIVE);
 			info.state |= (1<<MD_DISK_SYNC);
 		}
@@ -2261,7 +2622,7 @@
 				validate_super(mddev, rdev);
 		rdev->saved_raid_disk = rdev->raid_disk;
 
-		rdev->in_sync = 0; /* just to be sure */
+		clear_bit(In_sync, &rdev->flags); /* just to be sure */
 		if (info->state & (1<<MD_DISK_WRITEMOSTLY))
 			set_bit(WriteMostly, &rdev->flags);
 
@@ -2299,11 +2660,11 @@
 		else
 			rdev->raid_disk = -1;
 
-		rdev->faulty = 0;
+		rdev->flags = 0;
+
 		if (rdev->raid_disk < mddev->raid_disks)
-			rdev->in_sync = (info->state & (1<<MD_DISK_SYNC));
-		else
-			rdev->in_sync = 0;
+			if (info->state & (1<<MD_DISK_SYNC))
+				set_bit(In_sync, &rdev->flags);
 
 		if (info->state & (1<<MD_DISK_WRITEMOSTLY))
 			set_bit(WriteMostly, &rdev->flags);
@@ -2402,14 +2763,14 @@
 		goto abort_export;
 	}
 
-	if (rdev->faulty) {
+	if (test_bit(Faulty, &rdev->flags)) {
 		printk(KERN_WARNING 
 			"md: can not hot-add faulty %s disk to %s!\n",
 			bdevname(rdev->bdev,b), mdname(mddev));
 		err = -EINVAL;
 		goto abort_export;
 	}
-	rdev->in_sync = 0;
+	clear_bit(In_sync, &rdev->flags);
 	rdev->desc_nr = -1;
 	bind_rdev_to_array(rdev, mddev);
 
@@ -2929,12 +3290,22 @@
 
 	/*
 	 * The remaining ioctls are changing the state of the
-	 * superblock, so we do not allow read-only arrays
-	 * here:
+	 * superblock, so we do not allow them on read-only arrays.
+	 * However non-MD ioctls (e.g. get-size) will still come through
+	 * here and hit the 'default' below, so only disallow
+	 * 'md' ioctls, and switch to rw mode if started auto-readonly.
 	 */
-	if (mddev->ro) {
-		err = -EROFS;
-		goto abort_unlock;
+	if (_IOC_TYPE(cmd) == MD_MAJOR &&
+	    mddev->ro && mddev->pers) {
+		if (mddev->ro == 2) {
+			mddev->ro = 0;
+		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+		md_wakeup_thread(mddev->thread);
+
+		} else {
+			err = -EROFS;
+			goto abort_unlock;
+		}
 	}
 
 	switch (cmd)
@@ -3064,21 +3435,17 @@
 	 */
 
 	allow_signal(SIGKILL);
-	complete(thread->event);
 	while (!kthread_should_stop()) {
-		void (*run)(mddev_t *);
 
-		wait_event_interruptible_timeout(thread->wqueue,
-						 test_bit(THREAD_WAKEUP, &thread->flags)
-						 || kthread_should_stop(),
-						 thread->timeout);
+		wait_event_timeout(thread->wqueue,
+				   test_bit(THREAD_WAKEUP, &thread->flags)
+				   || kthread_should_stop(),
+				   thread->timeout);
 		try_to_freeze();
 
 		clear_bit(THREAD_WAKEUP, &thread->flags);
 
-		run = thread->run;
-		if (run)
-			run(thread->mddev);
+		thread->run(thread->mddev);
 	}
 
 	return 0;
@@ -3097,7 +3464,6 @@
 				 const char *name)
 {
 	mdk_thread_t *thread;
-	struct completion event;
 
 	thread = kmalloc(sizeof(mdk_thread_t), GFP_KERNEL);
 	if (!thread)
@@ -3106,18 +3472,14 @@
 	memset(thread, 0, sizeof(mdk_thread_t));
 	init_waitqueue_head(&thread->wqueue);
 
-	init_completion(&event);
-	thread->event = &event;
 	thread->run = run;
 	thread->mddev = mddev;
-	thread->name = name;
 	thread->timeout = MAX_SCHEDULE_TIMEOUT;
 	thread->tsk = kthread_run(md_thread, thread, name, mdname(thread->mddev));
 	if (IS_ERR(thread->tsk)) {
 		kfree(thread);
 		return NULL;
 	}
-	wait_for_completion(&event);
 	return thread;
 }
 
@@ -3136,7 +3498,7 @@
 		return;
 	}
 
-	if (!rdev || rdev->faulty)
+	if (!rdev || test_bit(Faulty, &rdev->flags))
 		return;
 /*
 	dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
@@ -3322,8 +3684,10 @@
 		seq_printf(seq, "%s : %sactive", mdname(mddev),
 						mddev->pers ? "" : "in");
 		if (mddev->pers) {
-			if (mddev->ro)
+			if (mddev->ro==1)
 				seq_printf(seq, " (read-only)");
+			if (mddev->ro==2)
+				seq_printf(seq, "(auto-read-only)");
 			seq_printf(seq, " %s", mddev->pers->name);
 		}
 
@@ -3334,7 +3698,7 @@
 				bdevname(rdev->bdev,b), rdev->desc_nr);
 			if (test_bit(WriteMostly, &rdev->flags))
 				seq_printf(seq, "(W)");
-			if (rdev->faulty) {
+			if (test_bit(Faulty, &rdev->flags)) {
 				seq_printf(seq, "(F)");
 				continue;
 			} else if (rdev->raid_disk < 0)
@@ -3363,11 +3727,15 @@
 		if (mddev->pers) {
 			mddev->pers->status (seq, mddev);
 	 		seq_printf(seq, "\n      ");
-			if (mddev->curr_resync > 2) {
-				status_resync (seq, mddev);
-				seq_printf(seq, "\n      ");
-			} else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
-				seq_printf(seq, "	resync=DELAYED\n      ");
+			if (mddev->pers->sync_request) {
+				if (mddev->curr_resync > 2) {
+					status_resync (seq, mddev);
+					seq_printf(seq, "\n      ");
+				} else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
+					seq_printf(seq, "\tresync=DELAYED\n      ");
+				else if (mddev->recovery_cp < MaxSector)
+					seq_printf(seq, "\tresync=PENDING\n      ");
+			}
 		} else
 			seq_printf(seq, "\n       ");
 
@@ -3504,15 +3872,22 @@
 	if (bio_data_dir(bi) != WRITE)
 		return;
 
+	BUG_ON(mddev->ro == 1);
+	if (mddev->ro == 2) {
+		/* need to switch to read/write */
+		mddev->ro = 0;
+		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+		md_wakeup_thread(mddev->thread);
+	}
 	atomic_inc(&mddev->writes_pending);
 	if (mddev->in_sync) {
-		spin_lock(&mddev->write_lock);
+		spin_lock_irq(&mddev->write_lock);
 		if (mddev->in_sync) {
 			mddev->in_sync = 0;
 			mddev->sb_dirty = 1;
 			md_wakeup_thread(mddev->thread);
 		}
-		spin_unlock(&mddev->write_lock);
+		spin_unlock_irq(&mddev->write_lock);
 	}
 	wait_event(mddev->sb_wait, mddev->sb_dirty==0);
 }
@@ -3568,9 +3943,7 @@
 		mddev->curr_resync = 2;
 
 	try_again:
-		if (signal_pending(current) ||
-		    kthread_should_stop()) {
-			flush_signals(current);
+		if (kthread_should_stop()) {
 			set_bit(MD_RECOVERY_INTR, &mddev->recovery);
 			goto skip;
 		}
@@ -3590,9 +3963,8 @@
 					 * time 'round when curr_resync == 2
 					 */
 					continue;
-				prepare_to_wait(&resync_wait, &wq, TASK_INTERRUPTIBLE);
-				if (!signal_pending(current) &&
-				    !kthread_should_stop() &&
+				prepare_to_wait(&resync_wait, &wq, TASK_UNINTERRUPTIBLE);
+				if (!kthread_should_stop() &&
 				    mddev2->curr_resync >= mddev->curr_resync) {
 					printk(KERN_INFO "md: delaying resync of %s"
 					       " until %s has finished resync (they"
@@ -3608,12 +3980,13 @@
 		}
 	} while (mddev->curr_resync < 2);
 
-	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
 		/* resync follows the size requested by the personality,
 		 * which defaults to physical size, but can be virtual size
 		 */
 		max_sectors = mddev->resync_max_sectors;
-	else
+		mddev->resync_mismatches = 0;
+	} else
 		/* recovery follows the physical size of devices */
 		max_sectors = mddev->size << 1;
 
@@ -3626,7 +3999,8 @@
 
 	is_mddev_idle(mddev); /* this also initializes IO event counters */
 	/* we don't use the checkpoint if there's a bitmap */
-	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap)
+	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap
+	    && ! test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
 		j = mddev->recovery_cp;
 	else
 		j = 0;
@@ -3699,13 +4073,12 @@
 		}
 
 
-		if (signal_pending(current) || kthread_should_stop()) {
+		if (kthread_should_stop()) {
 			/*
 			 * got a signal, exit.
 			 */
 			printk(KERN_INFO 
 				"md: md_do_sync() got signal ... exiting\n");
-			flush_signals(current);
 			set_bit(MD_RECOVERY_INTR, &mddev->recovery);
 			goto out;
 		}
@@ -3727,7 +4100,7 @@
 		if (currspeed > sysctl_speed_limit_min) {
 			if ((currspeed > sysctl_speed_limit_max) ||
 					!is_mddev_idle(mddev)) {
-				msleep_interruptible(250);
+				msleep(250);
 				goto repeat;
 			}
 		}
@@ -3820,7 +4193,7 @@
 	if (mddev_trylock(mddev)==0) {
 		int spares =0;
 
-		spin_lock(&mddev->write_lock);
+		spin_lock_irq(&mddev->write_lock);
 		if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
 		    !mddev->in_sync && mddev->recovery_cp == MaxSector) {
 			mddev->in_sync = 1;
@@ -3828,7 +4201,7 @@
 		}
 		if (mddev->safemode == 1)
 			mddev->safemode = 0;
-		spin_unlock(&mddev->write_lock);
+		spin_unlock_irq(&mddev->write_lock);
 
 		if (mddev->sb_dirty)
 			md_update_sb(mddev);
@@ -3864,9 +4237,13 @@
 			set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 			goto unlock;
 		}
-		if (mddev->recovery)
-			/* probably just the RECOVERY_NEEDED flag */
-			mddev->recovery = 0;
+		/* Clear some bits that don't mean anything, but
+		 * might be left set
+		 */
+		clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+		clear_bit(MD_RECOVERY_ERR, &mddev->recovery);
+		clear_bit(MD_RECOVERY_INTR, &mddev->recovery);
+		clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
 
 		/* no recovery is running.
 		 * remove any failed drives, then
@@ -3876,31 +4253,41 @@
 		 */
 		ITERATE_RDEV(mddev,rdev,rtmp)
 			if (rdev->raid_disk >= 0 &&
-			    (rdev->faulty || ! rdev->in_sync) &&
+			    (test_bit(Faulty, &rdev->flags) || ! test_bit(In_sync, &rdev->flags)) &&
 			    atomic_read(&rdev->nr_pending)==0) {
-				if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0)
+				if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0) {
+					char nm[20];
+					sprintf(nm,"rd%d", rdev->raid_disk);
+					sysfs_remove_link(&mddev->kobj, nm);
 					rdev->raid_disk = -1;
+				}
 			}
 
 		if (mddev->degraded) {
 			ITERATE_RDEV(mddev,rdev,rtmp)
 				if (rdev->raid_disk < 0
-				    && !rdev->faulty) {
-					if (mddev->pers->hot_add_disk(mddev,rdev))
+				    && !test_bit(Faulty, &rdev->flags)) {
+					if (mddev->pers->hot_add_disk(mddev,rdev)) {
+						char nm[20];
+						sprintf(nm, "rd%d", rdev->raid_disk);
+						sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
 						spares++;
-					else
+					} else
 						break;
 				}
 		}
 
-		if (!spares && (mddev->recovery_cp == MaxSector )) {
-			/* nothing we can do ... */
+		if (spares) {
+			clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+			clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+		} else if (mddev->recovery_cp < MaxSector) {
+			set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+		} else if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+			/* nothing to be done ... */
 			goto unlock;
-		}
+
 		if (mddev->pers->sync_request) {
 			set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
-			if (!spares)
-				set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
 			if (spares && mddev->bitmap && ! mddev->bitmap->file) {
 				/* We are adding a device or devices to an array
 				 * which has the bitmap stored on all devices.
@@ -3975,7 +4362,7 @@
 			" MD_SB_DISKS=%d\n",
 			MD_MAJOR_VERSION, MD_MINOR_VERSION,
 			MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS);
-	printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR,
+	printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR_HI,
 			BITMAP_MINOR);
 
 	if (register_blkdev(MAJOR_NR, "md"))
@@ -4039,7 +4426,7 @@
 		if (IS_ERR(rdev))
 			continue;
 
-		if (rdev->faulty) {
+		if (test_bit(Faulty, &rdev->flags)) {
 			MD_BUG();
 			continue;
 		}
@@ -4086,6 +4473,23 @@
 module_init(md_init)
 module_exit(md_exit)
 
+static int get_ro(char *buffer, struct kernel_param *kp)
+{
+	return sprintf(buffer, "%d", start_readonly);
+}
+static int set_ro(const char *val, struct kernel_param *kp)
+{
+	char *e;
+	int num = simple_strtoul(val, &e, 10);
+	if (*val && (*e == '\0' || *e == '\n')) {
+		start_readonly = num;
+		return 0;;
+	}
+	return -EINVAL;
+}
+
+module_param_call(start_ro, set_ro, get_ro, NULL, 0600);
+
 EXPORT_SYMBOL(register_md_personality);
 EXPORT_SYMBOL(unregister_md_personality);
 EXPORT_SYMBOL(md_error);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index c06f447..145cdc5 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -63,8 +63,8 @@
 
 	rcu_read_lock();
 	for (i = 0; i < disks; i++) {
-		mdk_rdev_t *rdev = conf->multipaths[i].rdev;
-		if (rdev && rdev->in_sync) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+		if (rdev && test_bit(In_sync, &rdev->flags)) {
 			atomic_inc(&rdev->nr_pending);
 			rcu_read_unlock();
 			return i;
@@ -139,8 +139,9 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks; i++) {
-		mdk_rdev_t *rdev = conf->multipaths[i].rdev;
-		if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags)
+		    && atomic_read(&rdev->nr_pending)) {
 			request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
 			atomic_inc(&rdev->nr_pending);
@@ -211,7 +212,7 @@
 	for (i = 0; i < conf->raid_disks; i++)
 		seq_printf (seq, "%s",
 			       conf->multipaths[i].rdev && 
-			       conf->multipaths[i].rdev->in_sync ? "U" : "_");
+			       test_bit(In_sync, &conf->multipaths[i].rdev->flags) ? "U" : "_");
 	seq_printf (seq, "]");
 }
 
@@ -224,8 +225,8 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-		mdk_rdev_t *rdev = conf->multipaths[i].rdev;
-		if (rdev && !rdev->faulty) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct block_device *bdev = rdev->bdev;
 			request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -265,10 +266,10 @@
 		/*
 		 * Mark disk as unusable
 		 */
-		if (!rdev->faulty) {
+		if (!test_bit(Faulty, &rdev->flags)) {
 			char b[BDEVNAME_SIZE];
-			rdev->in_sync = 0;
-			rdev->faulty = 1;
+			clear_bit(In_sync, &rdev->flags);
+			set_bit(Faulty, &rdev->flags);
 			mddev->sb_dirty = 1;
 			conf->working_disks--;
 			printk(KERN_ALERT "multipath: IO failure on %s,"
@@ -298,7 +299,7 @@
 		tmp = conf->multipaths + i;
 		if (tmp->rdev)
 			printk(" disk%d, o:%d, dev:%s\n",
-				i,!tmp->rdev->faulty,
+				i,!test_bit(Faulty, &tmp->rdev->flags),
 			       bdevname(tmp->rdev->bdev,b));
 	}
 }
@@ -330,8 +331,8 @@
 
 			conf->working_disks++;
 			rdev->raid_disk = path;
-			rdev->in_sync = 1;
-			p->rdev = rdev;
+			set_bit(In_sync, &rdev->flags);
+			rcu_assign_pointer(p->rdev, rdev);
 			found = 1;
 		}
 
@@ -350,7 +351,7 @@
 
 	rdev = p->rdev;
 	if (rdev) {
-		if (rdev->in_sync ||
+		if (test_bit(In_sync, &rdev->flags) ||
 		    atomic_read(&rdev->nr_pending)) {
 			printk(KERN_ERR "hot-remove-disk, slot %d is identified"				" but is still operational!\n", number);
 			err = -EBUSY;
@@ -482,7 +483,7 @@
 		    mddev->queue->max_sectors > (PAGE_SIZE>>9))
 			blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
-		if (!rdev->faulty) 
+		if (!test_bit(Faulty, &rdev->flags))
 			conf->working_disks++;
 	}
 
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index e16f473..2da9d3b 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -301,7 +301,7 @@
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
-	int mirror, behind;
+	int mirror, behind = test_bit(R1BIO_BehindIO, &r1_bio->state);
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
 
 	if (bio->bi_size)
@@ -311,47 +311,54 @@
 		if (r1_bio->bios[mirror] == bio)
 			break;
 
-	/*
-	 * this branch is our 'one mirror IO has finished' event handler:
-	 */
-	if (!uptodate) {
-		md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
-		/* an I/O failed, we can't clear the bitmap */
-		set_bit(R1BIO_Degraded, &r1_bio->state);
-	} else
+	if (error == -ENOTSUPP && test_bit(R1BIO_Barrier, &r1_bio->state)) {
+		set_bit(BarriersNotsupp, &conf->mirrors[mirror].rdev->flags);
+		set_bit(R1BIO_BarrierRetry, &r1_bio->state);
+		r1_bio->mddev->barriers_work = 0;
+	} else {
 		/*
-		 * Set R1BIO_Uptodate in our master bio, so that
-		 * we will return a good error code for to the higher
-		 * levels even if IO on some other mirrored buffer fails.
-		 *
-		 * The 'master' represents the composite IO operation to
-		 * user-side. So if something waits for IO, then it will
-		 * wait for the 'master' bio.
+		 * this branch is our 'one mirror IO has finished' event handler:
 		 */
-		set_bit(R1BIO_Uptodate, &r1_bio->state);
+		r1_bio->bios[mirror] = NULL;
+		bio_put(bio);
+		if (!uptodate) {
+			md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
+			/* an I/O failed, we can't clear the bitmap */
+			set_bit(R1BIO_Degraded, &r1_bio->state);
+		} else
+			/*
+			 * Set R1BIO_Uptodate in our master bio, so that
+			 * we will return a good error code for to the higher
+			 * levels even if IO on some other mirrored buffer fails.
+			 *
+			 * The 'master' represents the composite IO operation to
+			 * user-side. So if something waits for IO, then it will
+			 * wait for the 'master' bio.
+			 */
+			set_bit(R1BIO_Uptodate, &r1_bio->state);
 
-	update_head_pos(mirror, r1_bio);
+		update_head_pos(mirror, r1_bio);
 
-	behind = test_bit(R1BIO_BehindIO, &r1_bio->state);
-	if (behind) {
-		if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags))
-			atomic_dec(&r1_bio->behind_remaining);
+		if (behind) {
+			if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags))
+				atomic_dec(&r1_bio->behind_remaining);
 
-		/* In behind mode, we ACK the master bio once the I/O has safely
-		 * reached all non-writemostly disks. Setting the Returned bit
-		 * ensures that this gets done only once -- we don't ever want to
-		 * return -EIO here, instead we'll wait */
+			/* In behind mode, we ACK the master bio once the I/O has safely
+			 * reached all non-writemostly disks. Setting the Returned bit
+			 * ensures that this gets done only once -- we don't ever want to
+			 * return -EIO here, instead we'll wait */
 
-		if (atomic_read(&r1_bio->behind_remaining) >= (atomic_read(&r1_bio->remaining)-1) &&
-		    test_bit(R1BIO_Uptodate, &r1_bio->state)) {
-			/* Maybe we can return now */
-			if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) {
-				struct bio *mbio = r1_bio->master_bio;
-				PRINTK(KERN_DEBUG "raid1: behind end write sectors %llu-%llu\n",
-				       (unsigned long long) mbio->bi_sector,
-				       (unsigned long long) mbio->bi_sector +
-				       (mbio->bi_size >> 9) - 1);
-				bio_endio(mbio, mbio->bi_size, 0);
+			if (atomic_read(&r1_bio->behind_remaining) >= (atomic_read(&r1_bio->remaining)-1) &&
+			    test_bit(R1BIO_Uptodate, &r1_bio->state)) {
+				/* Maybe we can return now */
+				if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) {
+					struct bio *mbio = r1_bio->master_bio;
+					PRINTK(KERN_DEBUG "raid1: behind end write sectors %llu-%llu\n",
+					       (unsigned long long) mbio->bi_sector,
+					       (unsigned long long) mbio->bi_sector +
+					       (mbio->bi_size >> 9) - 1);
+					bio_endio(mbio, mbio->bi_size, 0);
+				}
 			}
 		}
 	}
@@ -361,8 +368,16 @@
 	 * already.
 	 */
 	if (atomic_dec_and_test(&r1_bio->remaining)) {
+		if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) {
+			reschedule_retry(r1_bio);
+			/* Don't dec_pending yet, we want to hold
+			 * the reference over the retry
+			 */
+			return 0;
+		}
 		if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
 			/* free extra copy of the data pages */
+/* FIXME bio has been freed!!! */
 			int i = bio->bi_vcnt;
 			while (i--)
 				__free_page(bio->bi_io_vec[i].bv_page);
@@ -416,12 +431,12 @@
 		/* Choose the first operation device, for consistancy */
 		new_disk = 0;
 
-		for (rdev = conf->mirrors[new_disk].rdev;
-		     !rdev || !rdev->in_sync
+		for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
+		     !rdev || !test_bit(In_sync, &rdev->flags)
 			     || test_bit(WriteMostly, &rdev->flags);
-		     rdev = conf->mirrors[++new_disk].rdev) {
+		     rdev = rcu_dereference(conf->mirrors[++new_disk].rdev)) {
 
-			if (rdev && rdev->in_sync)
+			if (rdev && test_bit(In_sync, &rdev->flags))
 				wonly_disk = new_disk;
 
 			if (new_disk == conf->raid_disks - 1) {
@@ -434,12 +449,12 @@
 
 
 	/* make sure the disk is operational */
-	for (rdev = conf->mirrors[new_disk].rdev;
-	     !rdev || !rdev->in_sync ||
+	for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
+	     !rdev || !test_bit(In_sync, &rdev->flags) ||
 		     test_bit(WriteMostly, &rdev->flags);
-	     rdev = conf->mirrors[new_disk].rdev) {
+	     rdev = rcu_dereference(conf->mirrors[new_disk].rdev)) {
 
-		if (rdev && rdev->in_sync)
+		if (rdev && test_bit(In_sync, &rdev->flags))
 			wonly_disk = new_disk;
 
 		if (new_disk <= 0)
@@ -474,10 +489,10 @@
 			disk = conf->raid_disks;
 		disk--;
 
-		rdev = conf->mirrors[disk].rdev;
+		rdev = rcu_dereference(conf->mirrors[disk].rdev);
 
 		if (!rdev ||
-		    !rdev->in_sync ||
+		    !test_bit(In_sync, &rdev->flags) ||
 		    test_bit(WriteMostly, &rdev->flags))
 			continue;
 
@@ -496,11 +511,11 @@
 
 
 	if (new_disk >= 0) {
-		rdev = conf->mirrors[new_disk].rdev;
+		rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
 		if (!rdev)
 			goto retry;
 		atomic_inc(&rdev->nr_pending);
-		if (!rdev->in_sync) {
+		if (!test_bit(In_sync, &rdev->flags)) {
 			/* cannot risk returning a device that failed
 			 * before we inc'ed nr_pending
 			 */
@@ -522,8 +537,8 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks; i++) {
-		mdk_rdev_t *rdev = conf->mirrors[i].rdev;
-		if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
 			request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
 			atomic_inc(&rdev->nr_pending);
@@ -556,8 +571,8 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-		mdk_rdev_t *rdev = conf->mirrors[i].rdev;
-		if (rdev && !rdev->faulty) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct block_device *bdev = rdev->bdev;
 			request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -648,8 +663,9 @@
 	struct bio_list bl;
 	struct page **behind_pages = NULL;
 	const int rw = bio_data_dir(bio);
+	int do_barriers;
 
-	if (unlikely(bio_barrier(bio))) {
+	if (unlikely(!mddev->barriers_work && bio_barrier(bio))) {
 		bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
 		return 0;
 	}
@@ -728,10 +744,10 @@
 #endif
 	rcu_read_lock();
 	for (i = 0;  i < disks; i++) {
-		if ((rdev=conf->mirrors[i].rdev) != NULL &&
-		    !rdev->faulty) {
+		if ((rdev=rcu_dereference(conf->mirrors[i].rdev)) != NULL &&
+		    !test_bit(Faulty, &rdev->flags)) {
 			atomic_inc(&rdev->nr_pending);
-			if (rdev->faulty) {
+			if (test_bit(Faulty, &rdev->flags)) {
 				atomic_dec(&rdev->nr_pending);
 				r1_bio->bios[i] = NULL;
 			} else
@@ -759,6 +775,10 @@
 	atomic_set(&r1_bio->remaining, 0);
 	atomic_set(&r1_bio->behind_remaining, 0);
 
+	do_barriers = bio->bi_rw & BIO_RW_BARRIER;
+	if (do_barriers)
+		set_bit(R1BIO_Barrier, &r1_bio->state);
+
 	bio_list_init(&bl);
 	for (i = 0; i < disks; i++) {
 		struct bio *mbio;
@@ -771,7 +791,7 @@
 		mbio->bi_sector	= r1_bio->sector + conf->mirrors[i].rdev->data_offset;
 		mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
 		mbio->bi_end_io	= raid1_end_write_request;
-		mbio->bi_rw = WRITE;
+		mbio->bi_rw = WRITE | do_barriers;
 		mbio->bi_private = r1_bio;
 
 		if (behind_pages) {
@@ -824,7 +844,7 @@
 	for (i = 0; i < conf->raid_disks; i++)
 		seq_printf(seq, "%s",
 			      conf->mirrors[i].rdev &&
-			      conf->mirrors[i].rdev->in_sync ? "U" : "_");
+			      test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
 	seq_printf(seq, "]");
 }
 
@@ -840,14 +860,14 @@
 	 * next level up know.
 	 * else mark the drive as failed
 	 */
-	if (rdev->in_sync
+	if (test_bit(In_sync, &rdev->flags)
 	    && conf->working_disks == 1)
 		/*
 		 * Don't fail the drive, act as though we were just a
 		 * normal single drive
 		 */
 		return;
-	if (rdev->in_sync) {
+	if (test_bit(In_sync, &rdev->flags)) {
 		mddev->degraded++;
 		conf->working_disks--;
 		/*
@@ -855,8 +875,8 @@
 		 */
 		set_bit(MD_RECOVERY_ERR, &mddev->recovery);
 	}
-	rdev->in_sync = 0;
-	rdev->faulty = 1;
+	clear_bit(In_sync, &rdev->flags);
+	set_bit(Faulty, &rdev->flags);
 	mddev->sb_dirty = 1;
 	printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
 		"	Operation continuing on %d devices\n",
@@ -881,7 +901,7 @@
 		tmp = conf->mirrors + i;
 		if (tmp->rdev)
 			printk(" disk %d, wo:%d, o:%d, dev:%s\n",
-				i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+				i, !test_bit(In_sync, &tmp->rdev->flags), !test_bit(Faulty, &tmp->rdev->flags),
 				bdevname(tmp->rdev->bdev,b));
 	}
 }
@@ -913,11 +933,11 @@
 	for (i = 0; i < conf->raid_disks; i++) {
 		tmp = conf->mirrors + i;
 		if (tmp->rdev 
-		    && !tmp->rdev->faulty
-		    && !tmp->rdev->in_sync) {
+		    && !test_bit(Faulty, &tmp->rdev->flags)
+		    && !test_bit(In_sync, &tmp->rdev->flags)) {
 			conf->working_disks++;
 			mddev->degraded--;
-			tmp->rdev->in_sync = 1;
+			set_bit(In_sync, &tmp->rdev->flags);
 		}
 	}
 
@@ -954,7 +974,7 @@
 			found = 1;
 			if (rdev->saved_raid_disk != mirror)
 				conf->fullsync = 1;
-			p->rdev = rdev;
+			rcu_assign_pointer(p->rdev, rdev);
 			break;
 		}
 
@@ -972,7 +992,7 @@
 	print_conf(conf);
 	rdev = p->rdev;
 	if (rdev) {
-		if (rdev->in_sync ||
+		if (test_bit(In_sync, &rdev->flags) ||
 		    atomic_read(&rdev->nr_pending)) {
 			err = -EBUSY;
 			goto abort;
@@ -1153,6 +1173,36 @@
 		if (test_bit(R1BIO_IsSync, &r1_bio->state)) {
 			sync_request_write(mddev, r1_bio);
 			unplug = 1;
+		} else if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) {
+			/* some requests in the r1bio were BIO_RW_BARRIER
+			 * requests which failed with -ENOTSUPP.  Hohumm..
+			 * Better resubmit without the barrier.
+			 * We know which devices to resubmit for, because
+			 * all others have had their bios[] entry cleared.
+			 */
+			int i;
+			clear_bit(R1BIO_BarrierRetry, &r1_bio->state);
+			clear_bit(R1BIO_Barrier, &r1_bio->state);
+			for (i=0; i < conf->raid_disks; i++)
+				if (r1_bio->bios[i]) {
+					struct bio_vec *bvec;
+					int j;
+
+					bio = bio_clone(r1_bio->master_bio, GFP_NOIO);
+					/* copy pages from the failed bio, as
+					 * this might be a write-behind device */
+					__bio_for_each_segment(bvec, bio, j, 0)
+						bvec->bv_page = bio_iovec_idx(r1_bio->bios[i], j)->bv_page;
+					bio_put(r1_bio->bios[i]);
+					bio->bi_sector = r1_bio->sector +
+						conf->mirrors[i].rdev->data_offset;
+					bio->bi_bdev = conf->mirrors[i].rdev->bdev;
+					bio->bi_end_io = raid1_end_write_request;
+					bio->bi_rw = WRITE;
+					bio->bi_private = r1_bio;
+					r1_bio->bios[i] = bio;
+					generic_make_request(bio);
+				}
 		} else {
 			int disk;
 			bio = r1_bio->bios[r1_bio->read_disk];
@@ -1260,7 +1310,7 @@
 	 * This call the bitmap_start_sync doesn't actually record anything
 	 */
 	if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) &&
-	    !conf->fullsync) {
+	    !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
 		/* We can skip this block, and probably several more */
 		*skipped = 1;
 		return sync_blocks;
@@ -1282,11 +1332,11 @@
 	/* make sure disk is operational */
 	wonly = disk;
 	while (conf->mirrors[disk].rdev == NULL ||
-	       !conf->mirrors[disk].rdev->in_sync ||
+	       !test_bit(In_sync, &conf->mirrors[disk].rdev->flags) ||
 	       test_bit(WriteMostly, &conf->mirrors[disk].rdev->flags)
 		) {
 		if (conf->mirrors[disk].rdev  &&
-		    conf->mirrors[disk].rdev->in_sync)
+		    test_bit(In_sync, &conf->mirrors[disk].rdev->flags))
 			wonly = disk;
 		if (disk <= 0)
 			disk = conf->raid_disks;
@@ -1333,11 +1383,12 @@
 			bio->bi_rw = READ;
 			bio->bi_end_io = end_sync_read;
 		} else if (conf->mirrors[i].rdev == NULL ||
-			   conf->mirrors[i].rdev->faulty) {
+			   test_bit(Faulty, &conf->mirrors[i].rdev->flags)) {
 			still_degraded = 1;
 			continue;
-		} else if (!conf->mirrors[i].rdev->in_sync ||
-			   sector_nr + RESYNC_SECTORS > mddev->recovery_cp) {
+		} else if (!test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
+			   sector_nr + RESYNC_SECTORS > mddev->recovery_cp   ||
+			   test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
 			bio->bi_rw = WRITE;
 			bio->bi_end_io = end_sync_write;
 			write_targets ++;
@@ -1371,8 +1422,9 @@
 			break;
 		if (sync_blocks == 0) {
 			if (!bitmap_start_sync(mddev->bitmap, sector_nr,
-					&sync_blocks, still_degraded) &&
-					!conf->fullsync)
+					       &sync_blocks, still_degraded) &&
+			    !conf->fullsync &&
+			    !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
 				break;
 			if (sync_blocks < (PAGE_SIZE>>9))
 				BUG();
@@ -1478,7 +1530,7 @@
 			blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
 		disk->head_position = 0;
-		if (!rdev->faulty && rdev->in_sync)
+		if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
 			conf->working_disks++;
 	}
 	conf->raid_disks = mddev->raid_disks;
@@ -1518,7 +1570,7 @@
 	 */
 	for (j = 0; j < conf->raid_disks &&
 		     (!conf->mirrors[j].rdev ||
-		      !conf->mirrors[j].rdev->in_sync) ; j++)
+		      !test_bit(In_sync, &conf->mirrors[j].rdev->flags)) ; j++)
 		/* nothing */;
 	conf->last_used = j;
 
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index bbe40e9..867f06a 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -496,6 +496,7 @@
 	int disk, slot, nslot;
 	const int sectors = r10_bio->sectors;
 	sector_t new_distance, current_distance;
+	mdk_rdev_t *rdev;
 
 	raid10_find_phys(conf, r10_bio);
 	rcu_read_lock();
@@ -510,8 +511,8 @@
 		slot = 0;
 		disk = r10_bio->devs[slot].devnum;
 
-		while (!conf->mirrors[disk].rdev ||
-		       !conf->mirrors[disk].rdev->in_sync) {
+		while ((rdev = rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
+		       !test_bit(In_sync, &rdev->flags)) {
 			slot++;
 			if (slot == conf->copies) {
 				slot = 0;
@@ -527,8 +528,8 @@
 	/* make sure the disk is operational */
 	slot = 0;
 	disk = r10_bio->devs[slot].devnum;
-	while (!conf->mirrors[disk].rdev ||
-	       !conf->mirrors[disk].rdev->in_sync) {
+	while ((rdev=rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
+	       !test_bit(In_sync, &rdev->flags)) {
 		slot ++;
 		if (slot == conf->copies) {
 			disk = -1;
@@ -547,11 +548,11 @@
 		int ndisk = r10_bio->devs[nslot].devnum;
 
 
-		if (!conf->mirrors[ndisk].rdev ||
-		    !conf->mirrors[ndisk].rdev->in_sync)
+		if ((rdev=rcu_dereference(conf->mirrors[ndisk].rdev)) == NULL ||
+		    !test_bit(In_sync, &rdev->flags))
 			continue;
 
-		if (!atomic_read(&conf->mirrors[ndisk].rdev->nr_pending)) {
+		if (!atomic_read(&rdev->nr_pending)) {
 			disk = ndisk;
 			slot = nslot;
 			break;
@@ -569,7 +570,7 @@
 	r10_bio->read_slot = slot;
 /*	conf->next_seq_sect = this_sector + sectors;*/
 
-	if (disk >= 0 && conf->mirrors[disk].rdev)
+	if (disk >= 0 && (rdev=rcu_dereference(conf->mirrors[disk].rdev))!= NULL)
 		atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
 	rcu_read_unlock();
 
@@ -583,8 +584,8 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks; i++) {
-		mdk_rdev_t *rdev = conf->mirrors[i].rdev;
-		if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
 			request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
 			atomic_inc(&rdev->nr_pending);
@@ -614,8 +615,8 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-		mdk_rdev_t *rdev = conf->mirrors[i].rdev;
-		if (rdev && !rdev->faulty) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct block_device *bdev = rdev->bdev;
 			request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -768,9 +769,10 @@
 	rcu_read_lock();
 	for (i = 0;  i < conf->copies; i++) {
 		int d = r10_bio->devs[i].devnum;
-		if (conf->mirrors[d].rdev &&
-		    !conf->mirrors[d].rdev->faulty) {
-			atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev);
+		if (rdev &&
+		    !test_bit(Faulty, &rdev->flags)) {
+			atomic_inc(&rdev->nr_pending);
 			r10_bio->devs[i].bio = bio;
 		} else
 			r10_bio->devs[i].bio = NULL;
@@ -824,7 +826,7 @@
 	for (i = 0; i < conf->raid_disks; i++)
 		seq_printf(seq, "%s",
 			      conf->mirrors[i].rdev &&
-			      conf->mirrors[i].rdev->in_sync ? "U" : "_");
+			      test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
 	seq_printf(seq, "]");
 }
 
@@ -839,7 +841,7 @@
 	 * next level up know.
 	 * else mark the drive as failed
 	 */
-	if (rdev->in_sync
+	if (test_bit(In_sync, &rdev->flags)
 	    && conf->working_disks == 1)
 		/*
 		 * Don't fail the drive, just return an IO error.
@@ -849,7 +851,7 @@
 		 * really dead" tests...
 		 */
 		return;
-	if (rdev->in_sync) {
+	if (test_bit(In_sync, &rdev->flags)) {
 		mddev->degraded++;
 		conf->working_disks--;
 		/*
@@ -857,8 +859,8 @@
 		 */
 		set_bit(MD_RECOVERY_ERR, &mddev->recovery);
 	}
-	rdev->in_sync = 0;
-	rdev->faulty = 1;
+	clear_bit(In_sync, &rdev->flags);
+	set_bit(Faulty, &rdev->flags);
 	mddev->sb_dirty = 1;
 	printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n"
 		"	Operation continuing on %d devices\n",
@@ -883,7 +885,8 @@
 		tmp = conf->mirrors + i;
 		if (tmp->rdev)
 			printk(" disk %d, wo:%d, o:%d, dev:%s\n",
-				i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+				i, !test_bit(In_sync, &tmp->rdev->flags),
+			        !test_bit(Faulty, &tmp->rdev->flags),
 				bdevname(tmp->rdev->bdev,b));
 	}
 }
@@ -936,11 +939,11 @@
 	for (i = 0; i < conf->raid_disks; i++) {
 		tmp = conf->mirrors + i;
 		if (tmp->rdev
-		    && !tmp->rdev->faulty
-		    && !tmp->rdev->in_sync) {
+		    && !test_bit(Faulty, &tmp->rdev->flags)
+		    && !test_bit(In_sync, &tmp->rdev->flags)) {
 			conf->working_disks++;
 			mddev->degraded--;
-			tmp->rdev->in_sync = 1;
+			set_bit(In_sync, &tmp->rdev->flags);
 		}
 	}
 
@@ -980,7 +983,7 @@
 			p->head_position = 0;
 			rdev->raid_disk = mirror;
 			found = 1;
-			p->rdev = rdev;
+			rcu_assign_pointer(p->rdev, rdev);
 			break;
 		}
 
@@ -998,7 +1001,7 @@
 	print_conf(conf);
 	rdev = p->rdev;
 	if (rdev) {
-		if (rdev->in_sync ||
+		if (test_bit(In_sync, &rdev->flags) ||
 		    atomic_read(&rdev->nr_pending)) {
 			err = -EBUSY;
 			goto abort;
@@ -1414,7 +1417,7 @@
 
 		for (i=0 ; i<conf->raid_disks; i++)
 			if (conf->mirrors[i].rdev &&
-			    !conf->mirrors[i].rdev->in_sync) {
+			    !test_bit(In_sync, &conf->mirrors[i].rdev->flags)) {
 				/* want to reconstruct this device */
 				r10bio_t *rb2 = r10_bio;
 
@@ -1435,7 +1438,7 @@
 				for (j=0; j<conf->copies;j++) {
 					int d = r10_bio->devs[j].devnum;
 					if (conf->mirrors[d].rdev &&
-					    conf->mirrors[d].rdev->in_sync) {
+					    test_bit(In_sync, &conf->mirrors[d].rdev->flags)) {
 						/* This is where we read from */
 						bio = r10_bio->devs[0].bio;
 						bio->bi_next = biolist;
@@ -1511,7 +1514,7 @@
 			bio = r10_bio->devs[i].bio;
 			bio->bi_end_io = NULL;
 			if (conf->mirrors[d].rdev == NULL ||
-			    conf->mirrors[d].rdev->faulty)
+			    test_bit(Faulty, &conf->mirrors[d].rdev->flags))
 				continue;
 			atomic_inc(&conf->mirrors[d].rdev->nr_pending);
 			atomic_inc(&r10_bio->remaining);
@@ -1697,7 +1700,7 @@
 			mddev->queue->max_sectors = (PAGE_SIZE>>9);
 
 		disk->head_position = 0;
-		if (!rdev->faulty && rdev->in_sync)
+		if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
 			conf->working_disks++;
 	}
 	conf->raid_disks = mddev->raid_disks;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 1223e98..e2a4028 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -293,9 +293,31 @@
 	return sh;
 }
 
-static int grow_stripes(raid5_conf_t *conf, int num)
+static int grow_one_stripe(raid5_conf_t *conf)
 {
 	struct stripe_head *sh;
+	sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
+	if (!sh)
+		return 0;
+	memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev));
+	sh->raid_conf = conf;
+	spin_lock_init(&sh->lock);
+
+	if (grow_buffers(sh, conf->raid_disks)) {
+		shrink_buffers(sh, conf->raid_disks);
+		kmem_cache_free(conf->slab_cache, sh);
+		return 0;
+	}
+	/* we just created an active stripe so... */
+	atomic_set(&sh->count, 1);
+	atomic_inc(&conf->active_stripes);
+	INIT_LIST_HEAD(&sh->lru);
+	release_stripe(sh);
+	return 1;
+}
+
+static int grow_stripes(raid5_conf_t *conf, int num)
+{
 	kmem_cache_t *sc;
 	int devs = conf->raid_disks;
 
@@ -308,48 +330,39 @@
 		return 1;
 	conf->slab_cache = sc;
 	while (num--) {
-		sh = kmem_cache_alloc(sc, GFP_KERNEL);
-		if (!sh)
+		if (!grow_one_stripe(conf))
 			return 1;
-		memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev));
-		sh->raid_conf = conf;
-		spin_lock_init(&sh->lock);
-
-		if (grow_buffers(sh, conf->raid_disks)) {
-			shrink_buffers(sh, conf->raid_disks);
-			kmem_cache_free(sc, sh);
-			return 1;
-		}
-		/* we just created an active stripe so... */
-		atomic_set(&sh->count, 1);
-		atomic_inc(&conf->active_stripes);
-		INIT_LIST_HEAD(&sh->lru);
-		release_stripe(sh);
 	}
 	return 0;
 }
 
-static void shrink_stripes(raid5_conf_t *conf)
+static int drop_one_stripe(raid5_conf_t *conf)
 {
 	struct stripe_head *sh;
 
-	while (1) {
-		spin_lock_irq(&conf->device_lock);
-		sh = get_free_stripe(conf);
-		spin_unlock_irq(&conf->device_lock);
-		if (!sh)
-			break;
-		if (atomic_read(&sh->count))
-			BUG();
-		shrink_buffers(sh, conf->raid_disks);
-		kmem_cache_free(conf->slab_cache, sh);
-		atomic_dec(&conf->active_stripes);
-	}
+	spin_lock_irq(&conf->device_lock);
+	sh = get_free_stripe(conf);
+	spin_unlock_irq(&conf->device_lock);
+	if (!sh)
+		return 0;
+	if (atomic_read(&sh->count))
+		BUG();
+	shrink_buffers(sh, conf->raid_disks);
+	kmem_cache_free(conf->slab_cache, sh);
+	atomic_dec(&conf->active_stripes);
+	return 1;
+}
+
+static void shrink_stripes(raid5_conf_t *conf)
+{
+	while (drop_one_stripe(conf))
+		;
+
 	kmem_cache_destroy(conf->slab_cache);
 	conf->slab_cache = NULL;
 }
 
-static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done,
+static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
 				   int error)
 {
  	struct stripe_head *sh = bi->bi_private;
@@ -401,10 +414,35 @@
 		}
 #else
 		set_bit(R5_UPTODATE, &sh->dev[i].flags);
-#endif		
+#endif
+		if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
+			printk("R5: read error corrected!!\n");
+			clear_bit(R5_ReadError, &sh->dev[i].flags);
+			clear_bit(R5_ReWrite, &sh->dev[i].flags);
+		}
+		if (atomic_read(&conf->disks[i].rdev->read_errors))
+			atomic_set(&conf->disks[i].rdev->read_errors, 0);
 	} else {
-		md_error(conf->mddev, conf->disks[i].rdev);
+		int retry = 0;
 		clear_bit(R5_UPTODATE, &sh->dev[i].flags);
+		atomic_inc(&conf->disks[i].rdev->read_errors);
+		if (conf->mddev->degraded)
+			printk("R5: read error not correctable.\n");
+		else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
+			/* Oh, no!!! */
+			printk("R5: read error NOT corrected!!\n");
+		else if (atomic_read(&conf->disks[i].rdev->read_errors)
+			 > conf->max_nr_stripes)
+			printk("raid5: Too many read errors, failing device.\n");
+		else
+			retry = 1;
+		if (retry)
+			set_bit(R5_ReadError, &sh->dev[i].flags);
+		else {
+			clear_bit(R5_ReadError, &sh->dev[i].flags);
+			clear_bit(R5_ReWrite, &sh->dev[i].flags);
+			md_error(conf->mddev, conf->disks[i].rdev);
+		}
 	}
 	rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
 #if 0
@@ -487,19 +525,19 @@
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 	PRINTK("raid5: error called\n");
 
-	if (!rdev->faulty) {
+	if (!test_bit(Faulty, &rdev->flags)) {
 		mddev->sb_dirty = 1;
-		if (rdev->in_sync) {
+		if (test_bit(In_sync, &rdev->flags)) {
 			conf->working_disks--;
 			mddev->degraded++;
 			conf->failed_disks++;
-			rdev->in_sync = 0;
+			clear_bit(In_sync, &rdev->flags);
 			/*
 			 * if recovery was running, make sure it aborts.
 			 */
 			set_bit(MD_RECOVERY_ERR, &mddev->recovery);
 		}
-		rdev->faulty = 1;
+		set_bit(Faulty, &rdev->flags);
 		printk (KERN_ALERT
 			"raid5: Disk failure on %s, disabling device."
 			" Operation continuing on %d devices\n",
@@ -965,7 +1003,13 @@
 		}
 		if (dev->written) written++;
 		rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
-		if (!rdev || !rdev->in_sync) {
+		if (!rdev || !test_bit(In_sync, &rdev->flags)) {
+			/* The ReadError flag wil just be confusing now */
+			clear_bit(R5_ReadError, &dev->flags);
+			clear_bit(R5_ReWrite, &dev->flags);
+		}
+		if (!rdev || !test_bit(In_sync, &rdev->flags)
+		    || test_bit(R5_ReadError, &dev->flags)) {
 			failed++;
 			failed_num = i;
 		} else
@@ -980,6 +1024,14 @@
 	if (failed > 1 && to_read+to_write+written) {
 		for (i=disks; i--; ) {
 			int bitmap_end = 0;
+
+			if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
+				mdk_rdev_t *rdev = conf->disks[i].rdev;
+				if (rdev && test_bit(In_sync, &rdev->flags))
+					/* multiple read failures in one stripe */
+					md_error(conf->mddev, rdev);
+			}
+
 			spin_lock_irq(&conf->device_lock);
 			/* fail all writes first */
 			bi = sh->dev[i].towrite;
@@ -1015,7 +1067,8 @@
 			}
 
 			/* fail any reads if this device is non-operational */
-			if (!test_bit(R5_Insync, &sh->dev[i].flags)) {
+			if (!test_bit(R5_Insync, &sh->dev[i].flags) ||
+			    test_bit(R5_ReadError, &sh->dev[i].flags)) {
 				bi = sh->dev[i].toread;
 				sh->dev[i].toread = NULL;
 				if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
@@ -1247,6 +1300,11 @@
 			    !memcmp(pagea, pagea+4, STRIPE_SIZE-4)) {
 				/* parity is correct (on disc, not in buffer any more) */
 				set_bit(STRIPE_INSYNC, &sh->state);
+			} else {
+				conf->mddev->resync_mismatches += STRIPE_SECTORS;
+				if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
+					/* don't try to repair!! */
+					set_bit(STRIPE_INSYNC, &sh->state);
 			}
 		}
 		if (!test_bit(STRIPE_INSYNC, &sh->state)) {
@@ -1274,7 +1332,27 @@
 		md_done_sync(conf->mddev, STRIPE_SECTORS,1);
 		clear_bit(STRIPE_SYNCING, &sh->state);
 	}
-	
+
+	/* If the failed drive is just a ReadError, then we might need to progress
+	 * the repair/check process
+	 */
+	if (failed == 1 && ! conf->mddev->ro &&
+	    test_bit(R5_ReadError, &sh->dev[failed_num].flags)
+	    && !test_bit(R5_LOCKED, &sh->dev[failed_num].flags)
+	    && test_bit(R5_UPTODATE, &sh->dev[failed_num].flags)
+		) {
+		dev = &sh->dev[failed_num];
+		if (!test_bit(R5_ReWrite, &dev->flags)) {
+			set_bit(R5_Wantwrite, &dev->flags);
+			set_bit(R5_ReWrite, &dev->flags);
+			set_bit(R5_LOCKED, &dev->flags);
+		} else {
+			/* let's read it back */
+			set_bit(R5_Wantread, &dev->flags);
+			set_bit(R5_LOCKED, &dev->flags);
+		}
+	}
+
 	spin_unlock(&sh->lock);
 
 	while ((bi=return_bi)) {
@@ -1305,8 +1383,8 @@
 			bi->bi_end_io = raid5_end_read_request;
  
 		rcu_read_lock();
-		rdev = conf->disks[i].rdev;
-		if (rdev && rdev->faulty)
+		rdev = rcu_dereference(conf->disks[i].rdev);
+		if (rdev && test_bit(Faulty, &rdev->flags))
 			rdev = NULL;
 		if (rdev)
 			atomic_inc(&rdev->nr_pending);
@@ -1379,8 +1457,8 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks; i++) {
-		mdk_rdev_t *rdev = conf->disks[i].rdev;
-		if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
 			request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
 			atomic_inc(&rdev->nr_pending);
@@ -1424,8 +1502,8 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-		mdk_rdev_t *rdev = conf->disks[i].rdev;
-		if (rdev && !rdev->faulty) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct block_device *bdev = rdev->bdev;
 			request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -1567,6 +1645,7 @@
 		return rv;
 	}
 	if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) &&
+	    !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
 	    !conf->fullsync && sync_blocks >= STRIPE_SECTORS) {
 		/* we can skip this block, and probably more */
 		sync_blocks /= STRIPE_SECTORS;
@@ -1663,6 +1742,74 @@
 	PRINTK("--- raid5d inactive\n");
 }
 
+static ssize_t
+raid5_show_stripe_cache_size(mddev_t *mddev, char *page)
+{
+	raid5_conf_t *conf = mddev_to_conf(mddev);
+	if (conf)
+		return sprintf(page, "%d\n", conf->max_nr_stripes);
+	else
+		return 0;
+}
+
+static ssize_t
+raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
+{
+	raid5_conf_t *conf = mddev_to_conf(mddev);
+	char *end;
+	int new;
+	if (len >= PAGE_SIZE)
+		return -EINVAL;
+	if (!conf)
+		return -ENODEV;
+
+	new = simple_strtoul(page, &end, 10);
+	if (!*page || (*end && *end != '\n') )
+		return -EINVAL;
+	if (new <= 16 || new > 32768)
+		return -EINVAL;
+	while (new < conf->max_nr_stripes) {
+		if (drop_one_stripe(conf))
+			conf->max_nr_stripes--;
+		else
+			break;
+	}
+	while (new > conf->max_nr_stripes) {
+		if (grow_one_stripe(conf))
+			conf->max_nr_stripes++;
+		else break;
+	}
+	return len;
+}
+
+static struct md_sysfs_entry
+raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
+				raid5_show_stripe_cache_size,
+				raid5_store_stripe_cache_size);
+
+static ssize_t
+stripe_cache_active_show(mddev_t *mddev, char *page)
+{
+	raid5_conf_t *conf = mddev_to_conf(mddev);
+	if (conf)
+		return sprintf(page, "%d\n", atomic_read(&conf->active_stripes));
+	else
+		return 0;
+}
+
+static struct md_sysfs_entry
+raid5_stripecache_active = __ATTR_RO(stripe_cache_active);
+
+static struct attribute *raid5_attrs[] =  {
+	&raid5_stripecache_size.attr,
+	&raid5_stripecache_active.attr,
+	NULL,
+};
+static struct attribute_group raid5_attrs_group = {
+	.name = NULL,
+	.attrs = raid5_attrs,
+};
+
 static int run(mddev_t *mddev)
 {
 	raid5_conf_t *conf;
@@ -1709,7 +1856,7 @@
 
 		disk->rdev = rdev;
 
-		if (rdev->in_sync) {
+		if (test_bit(In_sync, &rdev->flags)) {
 			char b[BDEVNAME_SIZE];
 			printk(KERN_INFO "raid5: device %s operational as raid"
 				" disk %d\n", bdevname(rdev->bdev,b),
@@ -1804,6 +1951,7 @@
 	}
 
 	/* Ok, everything is just fine now */
+	sysfs_create_group(&mddev->kobj, &raid5_attrs_group);
 
 	if (mddev->bitmap)
 		mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ;
@@ -1828,7 +1976,7 @@
 
 
 
-static int stop (mddev_t *mddev)
+static int stop(mddev_t *mddev)
 {
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 
@@ -1837,6 +1985,7 @@
 	shrink_stripes(conf);
 	free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
 	blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+	sysfs_remove_group(&mddev->kobj, &raid5_attrs_group);
 	kfree(conf);
 	mddev->private = NULL;
 	return 0;
@@ -1887,7 +2036,7 @@
 	for (i = 0; i < conf->raid_disks; i++)
 		seq_printf (seq, "%s",
 			       conf->disks[i].rdev &&
-			       conf->disks[i].rdev->in_sync ? "U" : "_");
+			       test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
 	seq_printf (seq, "]");
 #if RAID5_DEBUG
 #define D(x) \
@@ -1914,7 +2063,7 @@
 		tmp = conf->disks + i;
 		if (tmp->rdev)
 		printk(" disk %d, o:%d, dev:%s\n",
-			i, !tmp->rdev->faulty,
+			i, !test_bit(Faulty, &tmp->rdev->flags),
 			bdevname(tmp->rdev->bdev,b));
 	}
 }
@@ -1928,12 +2077,12 @@
 	for (i = 0; i < conf->raid_disks; i++) {
 		tmp = conf->disks + i;
 		if (tmp->rdev
-		    && !tmp->rdev->faulty
-		    && !tmp->rdev->in_sync) {
+		    && !test_bit(Faulty, &tmp->rdev->flags)
+		    && !test_bit(In_sync, &tmp->rdev->flags)) {
 			mddev->degraded--;
 			conf->failed_disks--;
 			conf->working_disks++;
-			tmp->rdev->in_sync = 1;
+			set_bit(In_sync, &tmp->rdev->flags);
 		}
 	}
 	print_raid5_conf(conf);
@@ -1950,7 +2099,7 @@
 	print_raid5_conf(conf);
 	rdev = p->rdev;
 	if (rdev) {
-		if (rdev->in_sync ||
+		if (test_bit(In_sync, &rdev->flags) ||
 		    atomic_read(&rdev->nr_pending)) {
 			err = -EBUSY;
 			goto abort;
@@ -1985,12 +2134,12 @@
 	 */
 	for (disk=0; disk < mddev->raid_disks; disk++)
 		if ((p=conf->disks + disk)->rdev == NULL) {
-			rdev->in_sync = 0;
+			clear_bit(In_sync, &rdev->flags);
 			rdev->raid_disk = disk;
 			found = 1;
 			if (rdev->saved_raid_disk != disk)
 				conf->fullsync = 1;
-			p->rdev = rdev;
+			rcu_assign_pointer(p->rdev, rdev);
 			break;
 		}
 	print_raid5_conf(conf);
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index 7757869..eae5a35 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -507,19 +507,19 @@
 	raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
 	PRINTK("raid6: error called\n");
 
-	if (!rdev->faulty) {
+	if (!test_bit(Faulty, &rdev->flags)) {
 		mddev->sb_dirty = 1;
-		if (rdev->in_sync) {
+		if (test_bit(In_sync, &rdev->flags)) {
 			conf->working_disks--;
 			mddev->degraded++;
 			conf->failed_disks++;
-			rdev->in_sync = 0;
+			clear_bit(In_sync, &rdev->flags);
 			/*
 			 * if recovery was running, make sure it aborts.
 			 */
 			set_bit(MD_RECOVERY_ERR, &mddev->recovery);
 		}
-		rdev->faulty = 1;
+		set_bit(Faulty, &rdev->flags);
 		printk (KERN_ALERT
 			"raid6: Disk failure on %s, disabling device."
 			" Operation continuing on %d devices\n",
@@ -1071,7 +1071,7 @@
 		}
 		if (dev->written) written++;
 		rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
-		if (!rdev || !rdev->in_sync) {
+		if (!rdev || !test_bit(In_sync, &rdev->flags)) {
 			if ( failed < 2 )
 				failed_num[failed] = i;
 			failed++;
@@ -1464,8 +1464,8 @@
 			bi->bi_end_io = raid6_end_read_request;
 
 		rcu_read_lock();
-		rdev = conf->disks[i].rdev;
-		if (rdev && rdev->faulty)
+		rdev = rcu_dereference(conf->disks[i].rdev);
+		if (rdev && test_bit(Faulty, &rdev->flags))
 			rdev = NULL;
 		if (rdev)
 			atomic_inc(&rdev->nr_pending);
@@ -1538,8 +1538,8 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks; i++) {
-		mdk_rdev_t *rdev = conf->disks[i].rdev;
-		if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
 			request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
 			atomic_inc(&rdev->nr_pending);
@@ -1583,8 +1583,8 @@
 
 	rcu_read_lock();
 	for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-		mdk_rdev_t *rdev = conf->disks[i].rdev;
-		if (rdev && !rdev->faulty) {
+		mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct block_device *bdev = rdev->bdev;
 			request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -1868,7 +1868,7 @@
 
 		disk->rdev = rdev;
 
-		if (rdev->in_sync) {
+		if (test_bit(In_sync, &rdev->flags)) {
 			char b[BDEVNAME_SIZE];
 			printk(KERN_INFO "raid6: device %s operational as raid"
 			       " disk %d\n", bdevname(rdev->bdev,b),
@@ -2052,7 +2052,7 @@
 	for (i = 0; i < conf->raid_disks; i++)
  		seq_printf (seq, "%s",
 			    conf->disks[i].rdev &&
-			    conf->disks[i].rdev->in_sync ? "U" : "_");
+			    test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
 	seq_printf (seq, "]");
 #if RAID6_DUMPSTATE
 	seq_printf (seq, "\n");
@@ -2078,7 +2078,7 @@
 		tmp = conf->disks + i;
 		if (tmp->rdev)
 		printk(" disk %d, o:%d, dev:%s\n",
-			i, !tmp->rdev->faulty,
+			i, !test_bit(Faulty, &tmp->rdev->flags),
 			bdevname(tmp->rdev->bdev,b));
 	}
 }
@@ -2092,12 +2092,12 @@
 	for (i = 0; i < conf->raid_disks; i++) {
 		tmp = conf->disks + i;
 		if (tmp->rdev
-		    && !tmp->rdev->faulty
-		    && !tmp->rdev->in_sync) {
+		    && !test_bit(Faulty, &tmp->rdev->flags)
+		    && !test_bit(In_sync, &tmp->rdev->flags)) {
 			mddev->degraded--;
 			conf->failed_disks--;
 			conf->working_disks++;
-			tmp->rdev->in_sync = 1;
+			set_bit(In_sync, &tmp->rdev->flags);
 		}
 	}
 	print_raid6_conf(conf);
@@ -2114,7 +2114,7 @@
 	print_raid6_conf(conf);
 	rdev = p->rdev;
 	if (rdev) {
-		if (rdev->in_sync ||
+		if (test_bit(In_sync, &rdev->flags) ||
 		    atomic_read(&rdev->nr_pending)) {
 			err = -EBUSY;
 			goto abort;
@@ -2149,12 +2149,12 @@
 	 */
 	for (disk=0; disk < mddev->raid_disks; disk++)
 		if ((p=conf->disks + disk)->rdev == NULL) {
-			rdev->in_sync = 0;
+			clear_bit(In_sync, &rdev->flags);
 			rdev->raid_disk = disk;
 			found = 1;
 			if (rdev->saved_raid_disk != disk)
 				conf->fullsync = 1;
-			p->rdev = rdev;
+			rcu_assign_pointer(p->rdev, rdev);
 			break;
 		}
 	print_raid6_conf(conf);
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c
index 31fccb4..4b71fd6 100644
--- a/drivers/media/common/ir-common.c
+++ b/drivers/media/common/ir-common.c
@@ -116,7 +116,7 @@
 	[ 46 ] = KEY_BLUE,
 	[ 24 ] = KEY_KPPLUS,		/* fine tune + */
 	[ 25 ] = KEY_KPMINUS,		/* fine tune - */
-        [ 33 ] = KEY_KPDOT,
+	[ 33 ] = KEY_KPDOT,
 	[ 19 ] = KEY_KPENTER,
 	[ 34 ] = KEY_BACK,
 	[ 35 ] = KEY_PLAYPAUSE,
@@ -239,7 +239,7 @@
 	dprintk(1,"%s: key event code=%d down=%d\n",
 		dev->name,ir->keycode,ir->keypressed);
 	input_report_key(dev,ir->keycode,ir->keypressed);
-        input_sync(dev);
+	input_sync(dev);
 }
 
 /* -------------------------------------------------------------------------- */
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 47e28b0..a353303 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -13,6 +13,8 @@
 #include "bcm3510.h"
 #include "stv0297.h"
 #include "mt312.h"
+#include "lgdt330x.h"
+#include "dvb-pll.h"
 
 /* lnb control */
 
@@ -234,7 +236,6 @@
 	.inittab = samsung_tbmu24112_inittab,
 	.mclk = 88000000UL,
 	.invert = 0,
-	.enhanced_tuning = 0,
 	.skip_reinit = 0,
 	.lock_output = STV0229_LOCKOUTPUT_LK,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -296,6 +297,52 @@
 	return request_firmware(fw, name, fc->dev);
 }
 
+static int lgdt3303_pll_set(struct dvb_frontend* fe,
+                            struct dvb_frontend_parameters* params)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	u8 buf[4];
+	struct i2c_msg msg =
+		{ .addr = 0x61, .flags = 0, .buf = buf, .len = 4 };
+	int err;
+
+	dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0);
+	dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+			__FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+	if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
+		printk(KERN_WARNING "lgdt3303: %s error "
+			   "(addr %02x <- %02x, err = %i)\n",
+			   __FUNCTION__, buf[0], buf[1], err);
+		if (err < 0)
+			return err;
+		else
+			return -EREMOTEIO;
+	}
+
+	buf[0] = 0x86 | 0x18;
+	buf[1] = 0x50;
+	msg.len = 2;
+	if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
+		printk(KERN_WARNING "lgdt3303: %s error "
+			   "(addr %02x <- %02x, err = %i)\n",
+			   __FUNCTION__, buf[0], buf[1], err);
+		if (err < 0)
+			return err;
+		else
+			return -EREMOTEIO;
+	}
+
+        return 0;
+}
+
+static struct lgdt330x_config air2pc_atsc_hd5000_config = {
+	.demod_address       = 0x59,
+	.demod_chip          = LGDT3303,
+	.serial_mpeg         = 0x04,
+	.pll_set             = lgdt3303_pll_set,
+	.clock_polarity_flip = 1,
+};
+
 static struct nxt2002_config samsung_tbmv_config = {
 	.demod_address    = 0x0a,
 	.request_firmware = flexcop_fe_request_firmware,
@@ -458,6 +505,11 @@
 		fc->dev_type          = FC_AIR_ATSC2;
 		info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
 	} else
+	/* try the air atsc 3nd generation (lgdt3303) */
+	if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
+		fc->dev_type          = FC_AIR_ATSC3;
+		info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
+	} else
 	/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
 	if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC1;
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c
index 3a08d38..62282d8 100644
--- a/drivers/media/dvb/b2c2/flexcop-misc.c
+++ b/drivers/media/dvb/b2c2/flexcop-misc.c
@@ -51,6 +51,7 @@
 	"Sky2PC/SkyStar 2 DVB-S",
 	"Sky2PC/SkyStar 2 DVB-S (old version)",
 	"Cable2PC/CableStar 2 DVB-C",
+	"Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
 };
 
 const char *flexcop_bus_names[] = {
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
index 4ae1eb5..23cc643 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -26,6 +26,7 @@
 	FC_SKY,
 	FC_SKY_OLD,
 	FC_CABLE,
+	FC_AIR_ATSC3,
 } flexcop_device_type_t;
 
 typedef enum {
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 12873d4..123ed96 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -193,6 +193,7 @@
 	v204 = fc->read_ibi_reg(fc,misc_204);
 	v204.misc_204.Per_reset_sig = 0;
 	fc->write_ibi_reg(fc,misc_204,v204);
+	msleep(1);
 	v204.misc_204.Per_reset_sig = 1;
 	fc->write_ibi_reg(fc,misc_204,v204);
 }
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index 1e85d16..2337b41 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -6,10 +6,12 @@
 	select DVB_NXT6000
 	select DVB_CX24110
 	select DVB_OR51211
+	select DVB_LGDT330X
 	help
 	  Support for PCI cards based on the Bt8xx PCI bridge. Examples are
 	  the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
-	  the pcHDTV HD2000 cards, and certain AVerMedia cards.
+	  the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
+	  some AVerMedia cards.
 
 	  Since these cards have no MPEG decoder onboard, they transmit
 	  only compressed MPEG data over the PCI bus, so you need
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index b3c9d73..8977c7a 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -690,8 +690,8 @@
 		.device_id = "DTT-CI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_TERR,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
-		.dst_feature = 0
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE,
+		.dst_feature = DST_TYPE_HAS_CA
 	},
 
 	{
@@ -796,6 +796,56 @@
 	return 0;
 }
 
+static int dst_get_tuner_info(struct dst_state *state)
+{
+	u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
+	get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
+		if (dst_command(state, get_tuner_2, 8) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+			return -1;
+		}
+	} else {
+		if (dst_command(state, get_tuner_1, 8) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+			return -1;
+		}
+	}
+	memset(&state->board_info, '\0', 8);
+	memcpy(&state->board_info, &state->rxbuffer, 8);
+	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
+		if (state->board_info[1] == 0x0b) {
+			if (state->type_flags & DST_TYPE_HAS_TS204)
+				state->type_flags &= ~DST_TYPE_HAS_TS204;
+			state->type_flags |= DST_TYPE_HAS_NEWTUNE;
+			dprintk(verbose, DST_INFO, 1, "DST type has TS=188");
+		} else {
+			if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
+				state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
+			state->type_flags |= DST_TYPE_HAS_TS204;
+			dprintk(verbose, DST_INFO, 1, "DST type has TS=204");
+		}
+	} else {
+		if (state->board_info[0] == 0xbc) {
+			if (state->type_flags & DST_TYPE_HAS_TS204)
+				state->type_flags &= ~DST_TYPE_HAS_TS204;
+			state->type_flags |= DST_TYPE_HAS_NEWTUNE;
+			dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]);
+
+		} else if (state->board_info[0] == 0xcc) {
+			if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
+				state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
+			state->type_flags |= DST_TYPE_HAS_TS204;
+			dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]);
+		}
+	}
+
+	return 0;
+}
+
 static int dst_get_device_id(struct dst_state *state)
 {
 	u8 reply;
@@ -855,15 +905,12 @@
 	state->dst_type = use_dst_type;
 	dst_type_flags_print(state->type_flags);
 
-	if (state->type_flags & DST_TYPE_HAS_TS204) {
-		dst_packsize(state, 204);
-	}
-
 	return 0;
 }
 
 static int dst_probe(struct dst_state *state)
 {
+	sema_init(&state->dst_mutex, 1);
 	if ((rdc_8820_reset(state)) < 0) {
 		dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
 		return -1;
@@ -886,6 +933,13 @@
 		dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command");
 		return 0;
 	}
+	if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
+		if (dst_get_tuner_info(state) < 0)
+			dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command");
+	}
+	if (state->type_flags & DST_TYPE_HAS_TS204) {
+		dst_packsize(state, 204);
+	}
 	if (state->type_flags & DST_TYPE_HAS_FW_BUILD) {
 		if (dst_fw_ver(state) < 0) {
 			dprintk(verbose, DST_INFO, 1, "FW: Unsupported command");
@@ -907,21 +961,23 @@
 int dst_command(struct dst_state *state, u8 *data, u8 len)
 {
 	u8 reply;
+
+	down(&state->dst_mutex);
 	if ((dst_comm_init(state)) < 0) {
 		dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed.");
-		return -1;
+		goto error;
 	}
 	if (write_dst(state, data, len)) {
 		dprintk(verbose, DST_INFO, 1, "Tring to recover.. ");
 		if ((dst_error_recovery(state)) < 0) {
 			dprintk(verbose, DST_ERROR, 1, "Recovery Failed.");
-			return -1;
+			goto error;
 		}
-		return -1;
+		goto error;
 	}
 	if ((dst_pio_disable(state)) < 0) {
 		dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed.");
-		return -1;
+		goto error;
 	}
 	if (state->type_flags & DST_TYPE_HAS_FW_1)
 		udelay(3000);
@@ -929,36 +985,41 @@
 		dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
 		if ((dst_error_recovery(state)) < 0) {
 			dprintk(verbose, DST_INFO, 1, "Recovery Failed.");
-			return -1;
+			goto error;
 		}
-		return -1;
+		goto error;
 	}
 	if (reply != ACK) {
 		dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply);
-		return -1;
+		goto error;
 	}
 	if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
-		return 0;
+		goto error;
 	if (state->type_flags & DST_TYPE_HAS_FW_1)
 		udelay(3000);
 	else
 		udelay(2000);
 	if (!dst_wait_dst_ready(state, NO_DELAY))
-		return -1;
+		goto error;
 	if (read_dst(state, state->rxbuffer, FIXED_COMM)) {
 		dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
 		if ((dst_error_recovery(state)) < 0) {
 			dprintk(verbose, DST_INFO, 1, "Recovery failed.");
-			return -1;
+			goto error;
 		}
-		return -1;
+		goto error;
 	}
 	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
 		dprintk(verbose, DST_INFO, 1, "checksum failure");
-		return -1;
+		goto error;
 	}
-
+	up(&state->dst_mutex);
 	return 0;
+
+error:
+	up(&state->dst_mutex);
+	return -EIO;
+
 }
 EXPORT_SYMBOL(dst_command);
 
@@ -1016,7 +1077,7 @@
 		return 0;
 	state->diseq_flags &= ~(HAS_LOCK);
 	if (!dst_wait_dst_ready(state, NO_DELAY))
-		return 0;
+		return -EIO;
 	if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
 		/* how to get variable length reply ???? */
 		retval = read_dst(state, state->rx_tuna, 10);
@@ -1024,22 +1085,27 @@
 		retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
 	if (retval < 0) {
 		dprintk(verbose, DST_DEBUG, 1, "read not successful");
-		return 0;
+		return retval;
 	}
 	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
 		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
 			dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
-			return 0;
+			return -EIO;
 		}
 	} else {
 		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) {
 			dprintk(verbose, DST_INFO, 1, "checksum failure? ");
-			return 0;
+			return -EIO;
 		}
 	}
 	if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0)
 		return 0;
-	state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+	} else {
+		state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4];
+	}
+	state->decode_freq = state->decode_freq * 1000;
 	state->decode_lock = 1;
 	state->diseq_flags |= HAS_LOCK;
 
@@ -1062,10 +1128,10 @@
 			dst_set_voltage(fe, SEC_VOLTAGE_13);
 	}
 	state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
-
+	down(&state->dst_mutex);
 	if ((dst_comm_init(state)) < 0) {
 		dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
-		return -1;
+		goto error;
 	}
 	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
 		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
@@ -1077,23 +1143,29 @@
 	if (retval < 0) {
 		dst_pio_disable(state);
 		dprintk(verbose, DST_DEBUG, 1, "write not successful");
-		return retval;
+		goto werr;
 	}
 	if ((dst_pio_disable(state)) < 0) {
 		dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !");
-		return -1;
+		goto error;
 	}
 	if ((read_dst(state, &reply, GET_ACK) < 0)) {
 		dprintk(verbose, DST_DEBUG, 1, "read verify not successful.");
-		return -1;
+		goto error;
 	}
 	if (reply != ACK) {
 		dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply);
-		return 0;
+		goto error;
 	}
 	state->diseq_flags |= ATTEMPT_TUNE;
+	retval = dst_get_tuna(state);
+werr:
+	up(&state->dst_mutex);
+	return retval;
 
-	return dst_get_tuna(state);
+error:
+	up(&state->dst_mutex);
+	return -EIO;
 }
 
 /*
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 6776a59..e6541af 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -69,62 +69,53 @@
 }
 
 
-static int put_checksum(u8 *check_string, int length)
+static void put_checksum(u8 *check_string, int length)
 {
-	u8 i = 0, checksum = 0;
-
-	dprintk(verbose, DST_CA_DEBUG, 1, " ========================= Checksum calculation ===========================");
-	dprintk(verbose, DST_CA_DEBUG, 1, " String Length=[0x%02x]", length);
-	dprintk(verbose, DST_CA_DEBUG, 1, " String=[");
-
-	while (i < length) {
-		dprintk(verbose, DST_CA_DEBUG, 0, " %02x", check_string[i]);
-		checksum += check_string[i];
-		i++;
-	}
-	dprintk(verbose, DST_CA_DEBUG, 0, " ]\n");
-	dprintk(verbose, DST_CA_DEBUG, 1, "Sum=[%02x]\n", checksum);
-	check_string[length] = ~checksum + 1;
-	dprintk(verbose, DST_CA_DEBUG, 1, " Checksum=[%02x]", check_string[length]);
-	dprintk(verbose, DST_CA_DEBUG, 1, " ==========================================================================");
-
-	return 0;
+	dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
+	dprintk(verbose, DST_CA_DEBUG, 1, "  -> string length : 0x%02x", length);
+	check_string[length] = dst_check_sum (check_string, length);
+	dprintk(verbose, DST_CA_DEBUG, 1, "  -> checksum      : 0x%02x", check_string[length]);
 }
 
 static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
 {
 	u8 reply;
 
+	down(&state->dst_mutex);
 	dst_comm_init(state);
 	msleep(65);
 
 	if (write_dst(state, data, len)) {
 		dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
 		dst_error_recovery(state);
-		return -1;
+		goto error;
 	}
 	if ((dst_pio_disable(state)) < 0) {
 		dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
-		return -1;
+		goto error;
 	}
 	if (read_dst(state, &reply, GET_ACK) < 0) {
 		dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
 		dst_error_recovery(state);
-		return -1;
+		goto error;
 	}
 	if (read) {
 		if (! dst_wait_dst_ready(state, LONG_DELAY)) {
 			dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
-			return -1;
+			goto error;
 		}
 		if (read_dst(state, ca_string, 128) < 0) {	/*	Try to make this dynamic	*/
 			dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
 			dst_error_recovery(state);
-			return -1;
+			goto error;
 		}
 	}
-
+	up(&state->dst_mutex);
 	return 0;
+
+error:
+	up(&state->dst_mutex);
+	return -EIO;
 }
 
 
@@ -166,7 +157,7 @@
 	return 0;
 }
 
-static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void *arg)
+static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
 {
 	int i;
 	u8 slot_cap[256];
@@ -192,25 +183,25 @@
 	p_ca_caps->descr_num = slot_cap[7];
 	p_ca_caps->descr_type = 1;
 
-	if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps)))
+	if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
 		return -EFAULT;
 
 	return 0;
 }
 
 /*	Need some more work	*/
-static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
 {
 	return -EOPNOTSUPP;
 }
 
 
-static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void *arg)
+static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
 {
 	int i;
 	static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
 
-	u8 *slot_info = state->rxbuffer;
+	u8 *slot_info = state->messages;
 
 	put_checksum(&slot_command[0], 7);
 	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
@@ -238,19 +229,19 @@
 	} else
 		p_ca_slot_info->flags = 0;
 
-	if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
+	if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
 		return -EFAULT;
 
 	return 0;
 }
 
 
-static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
 {
 	u8 i = 0;
 	u32 command = 0;
 
-	if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
+	if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
 		return -EFAULT;
 
 	if (p_ca_message->msg) {
@@ -266,7 +257,7 @@
 		switch (command) {
 		case CA_APP_INFO:
 			memcpy(p_ca_message->msg, state->messages, 128);
-			if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) )
+			if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
 				return -EFAULT;
 			break;
 		}
@@ -315,7 +306,7 @@
 	return 0;
 }
 
-u32 asn_1_decode(u8 *asn_1_array)
+static u32 asn_1_decode(u8 *asn_1_array)
 {
 	u8 length_field = 0, word_count = 0, count = 0;
 	u32 length = 0;
@@ -328,7 +319,8 @@
 	} else {
 		word_count = length_field & 0x7f;
 		for (count = 0; count < word_count; count++) {
-			length = (length | asn_1_array[count + 1]) << 8;
+			length = length  << 8;
+			length += asn_1_array[count + 1];
 			dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
 		}
 	}
@@ -399,13 +391,14 @@
 	return 0;
 }
 
-static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
 {
 	int i = 0;
 	unsigned int ca_message_header_len;
 
 	u32 command = 0;
 	struct ca_msg *hw_buffer;
+	int result = 0;
 
 	if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
 		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
@@ -413,8 +406,11 @@
 	}
 	dprintk(verbose, DST_CA_DEBUG, 1, " ");
 
-	if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
-		return -EFAULT;
+	if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) {
+		result = -EFAULT;
+		goto free_mem_and_exit;
+	}
+
 
 	if (p_ca_message->msg) {
 		ca_message_header_len = p_ca_message->length;	/*	Restore it back when you are done	*/
@@ -433,7 +429,8 @@
 			dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
 			if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {	// code simplification started
 				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
-				return -1;
+				result = -1;
+				goto free_mem_and_exit;
 			}
 			dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
 			break;
@@ -442,7 +439,8 @@
 			/*      Have to handle the 2 basic types of cards here  */
 			if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
 				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
-				return -1;
+				result = -1;
+				goto free_mem_and_exit;
 			}
 			dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
 			break;
@@ -451,22 +449,28 @@
 
 			if ((ca_get_app_info(state)) < 0) {
 				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
-				return -1;
+				result = -1;
+				goto free_mem_and_exit;
 			}
 			dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
 			break;
 		}
 	}
-	return 0;
+free_mem_and_exit:
+	kfree (hw_buffer);
+
+	return result;
 }
 
-static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ioctl_arg)
 {
 	struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
 	struct dst_state* state = (struct dst_state*) dvbdev->priv;
 	struct ca_slot_info *p_ca_slot_info;
 	struct ca_caps *p_ca_caps;
 	struct ca_msg *p_ca_message;
+	void __user *arg = (void __user *)ioctl_arg;
+	int result = 0;
 
 	if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
 		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
@@ -486,14 +490,16 @@
 		dprintk(verbose, DST_CA_INFO, 1, " Sending message");
 		if ((ca_send_message(state, p_ca_message, arg)) < 0) {
 			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
-			return -1;
+			result = -1;
+			goto free_mem_and_exit;
 		}
 		break;
 	case CA_GET_MSG:
 		dprintk(verbose, DST_CA_INFO, 1, " Getting message");
 		if ((ca_get_message(state, p_ca_message, arg)) < 0) {
 			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
-			return -1;
+			result = -1;
+			goto free_mem_and_exit;
 		}
 		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
 		break;
@@ -506,7 +512,8 @@
 		dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
 		if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
 			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
-			return -1;
+			result = -1;
+			goto free_mem_and_exit;
 		}
 		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
 		break;
@@ -514,7 +521,8 @@
 		dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
 		if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
 			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
-			return -1;
+			result = -1;
+			goto free_mem_and_exit;
 		}
 		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
 		break;
@@ -522,7 +530,8 @@
 		dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
 		if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
 			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
-			return -1;
+			result = -1;
+			goto free_mem_and_exit;
 		}
 		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
 		break;
@@ -530,7 +539,8 @@
 		dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
 		if ((ca_set_slot_descr()) < 0) {
 			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
-			return -1;
+			result = -1;
+			goto free_mem_and_exit;
 		}
 		dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
 		break;
@@ -538,14 +548,19 @@
 		dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
 		if ((ca_set_pid()) < 0) {
 			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
-			return -1;
+			result = -1;
+			goto free_mem_and_exit;
 		}
 		dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
 	default:
-		return -EOPNOTSUPP;
+		result = -EOPNOTSUPP;
 	};
+ free_mem_and_exit:
+	kfree (p_ca_message);
+	kfree (p_ca_slot_info);
+	kfree (p_ca_caps);
 
-	return 0;
+	return result;
 }
 
 static int dst_ca_open(struct inode *inode, struct file *file)
@@ -582,7 +597,7 @@
 
 static struct file_operations dst_ca_fops = {
 	.owner = THIS_MODULE,
-	.ioctl = (void *)dst_ca_ioctl,
+	.ioctl = dst_ca_ioctl,
 	.open = dst_ca_open,
 	.release = dst_ca_release,
 	.read = dst_ca_read,
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 3281a6c..81557f3 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -22,6 +22,7 @@
 #ifndef DST_COMMON_H
 #define DST_COMMON_H
 
+#include <linux/smp_lock.h>
 #include <linux/dvb/frontend.h>
 #include <linux/device.h>
 #include "bt878.h"
@@ -49,6 +50,7 @@
 #define DST_TYPE_HAS_FW_BUILD	64
 #define DST_TYPE_HAS_OBS_REGS	128
 #define DST_TYPE_HAS_INC_COUNT	256
+#define DST_TYPE_HAS_MULTI_FE	512
 
 /*	Card capability list	*/
 
@@ -117,6 +119,9 @@
 	u8 fw_version[8];
 	u8 card_info[8];
 	u8 vendor[8];
+	u8 board_info[8];
+
+	struct semaphore dst_mutex;
 };
 
 struct dst_types {
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index c5c7672..2e39809 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -34,6 +34,7 @@
 #include "dvb_frontend.h"
 #include "dvb-bt8xx.h"
 #include "bt878.h"
+#include "dvb-pll.h"
 
 static int debug;
 
@@ -279,7 +280,7 @@
 	data[0] = (div >> 8) & 0x7f;
 	data[1] = div & 0xff;
 	data[2] = ((div >> 10) & 0x60) | cfg;
-	data[3] = cpump | band_select;
+	data[3] = (cpump << 6) | band_select;
 
 	i2c_transfer(card->i2c_adapter, &msg, 1);
 	return (div * 166666 - 36000000);
@@ -522,9 +523,7 @@
 	/*
 	 * Reset the frontend, must be called before trying
 	 * to initialise the MT352 or mt352_attach
-	 * will fail.
-	 *
-	 * Presumably not required for the NXT6000 frontend.
+	 * will fail. Same goes for the nxt6000 frontend.
 	 *
 	 */
 
@@ -546,14 +545,63 @@
 	.pll_set = digitv_alps_tded4_pll_set,
 };
 
+static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
+	u8 buf[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	int err;
+
+	dvb_pll_configure(&dvb_pll_tdvs_tua6034, buf, params->frequency, 0);
+	dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		__FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+	if ((err = i2c_transfer(card->i2c_adapter, &msg, 1)) != 1) {
+	        printk(KERN_WARNING "dvb-bt8xx: %s error "
+		        "(addr %02x <- %02x, err = %i)\n",
+		        __FUNCTION__, buf[0], buf[1], err);
+		if (err < 0)
+			return err;
+		else
+			return -EREMOTEIO;
+	}
+
+	/* Set the Auxiliary Byte. */
+	buf[2] &= ~0x20;
+	buf[2] |= 0x18;
+	buf[3] = 0x50;
+	i2c_transfer(card->i2c_adapter, &msg, 1);
+
+	return 0;
+}
+
+static struct lgdt330x_config tdvs_tua6034_config = {
+	.demod_address    = 0x0e,
+	.demod_chip       = LGDT3303,
+	.serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+	.pll_set          = tdvs_tua6034_pll_set,
+};
+
+static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
+{
+	/* Set pin 27 of the lgdt3303 chip high to reset the frontend */
+
+	/* Pulse the reset line */
+	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
+	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low  */
+	msleep(100);
+
+	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
+	msleep(100);
+}
+
 static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 {
 	int ret;
 	struct dst_state* state = NULL;
 
 	switch(type) {
-#ifdef BTTV_DVICO_DVBT_LITE
-	case BTTV_DVICO_DVBT_LITE:
+#ifdef BTTV_BOARD_DVICO_DVBT_LITE
+	case BTTV_BOARD_DVICO_DVBT_LITE:
 		card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
 		if (card->fe != NULL) {
 			card->fe->ops->info.frequency_min = 174000000;
@@ -562,10 +610,19 @@
 		break;
 #endif
 
-#ifdef BTTV_TWINHAN_VP3021
-	case BTTV_TWINHAN_VP3021:
+#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
+	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
+		lgdt330x_reset(card);
+		card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
+		if (card->fe != NULL)
+			dprintk ("dvb_bt8xx: lgdt330x detected\n");
+		break;
+#endif
+
+#ifdef BTTV_BOARD_TWINHAN_VP3021
+	case BTTV_BOARD_TWINHAN_VP3021:
 #else
-	case BTTV_NEBULA_DIGITV:
+	case BTTV_BOARD_NEBULA_DIGITV:
 #endif
 		/*
 		 * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
@@ -573,6 +630,7 @@
 		 */
 
 		/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
+		digitv_alps_tded4_reset(card);
 		card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
 		if (card->fe != NULL) {
 			dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
@@ -587,11 +645,11 @@
 			dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
 		break;
 
-	case BTTV_AVDVBT_761:
+	case BTTV_BOARD_AVDVBT_761:
 		card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
 		break;
 
-	case BTTV_AVDVBT_771:
+	case BTTV_BOARD_AVDVBT_771:
 		card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
 		if (card->fe != NULL) {
 			card->fe->ops->info.frequency_min = 174000000;
@@ -599,7 +657,7 @@
 		}
 		break;
 
-	case BTTV_TWINHAN_DST:
+	case BTTV_BOARD_TWINHAN_DST:
 		/*	DST is not a frontend driver !!!		*/
 		state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL);
 		/*	Setup the Card					*/
@@ -620,11 +678,11 @@
 			ret = dst_ca_attach(state, &card->dvb_adapter);
 		break;
 
-	case BTTV_PINNACLESAT:
+	case BTTV_BOARD_PINNACLESAT:
 		card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
 		break;
 
-	case BTTV_PC_HDTV:
+	case BTTV_BOARD_PC_HDTV:
 		card->fe = or51211_attach(&or51211_config, card->i2c_adapter);
 		break;
 	}
@@ -746,7 +804,7 @@
 	card->i2c_adapter = &sub->core->i2c_adap;
 
 	switch(sub->core->type) {
-	case BTTV_PINNACLESAT:
+	case BTTV_BOARD_PINNACLESAT:
 		card->gpio_mode = 0x0400c060;
 		/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
 			      BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
@@ -754,8 +812,8 @@
 		card->irq_err_ignore = 0;
 		break;
 
-#ifdef BTTV_DVICO_DVBT_LITE
-	case BTTV_DVICO_DVBT_LITE:
+#ifdef BTTV_BOARD_DVICO_DVBT_LITE
+	case BTTV_BOARD_DVICO_DVBT_LITE:
 #endif
 		card->gpio_mode = 0x0400C060;
 		card->op_sync_orin = 0;
@@ -765,26 +823,34 @@
 		 * DA_APP(parallel) */
 		break;
 
-#ifdef BTTV_TWINHAN_VP3021
-	case BTTV_TWINHAN_VP3021:
-#else
-	case BTTV_NEBULA_DIGITV:
+#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
+	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
 #endif
-	case BTTV_AVDVBT_761:
+		card->gpio_mode = 0x0400c060;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
+		break;
+
+#ifdef BTTV_BOARD_TWINHAN_VP3021
+	case BTTV_BOARD_TWINHAN_VP3021:
+#else
+	case BTTV_BOARD_NEBULA_DIGITV:
+#endif
+	case BTTV_BOARD_AVDVBT_761:
 		card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
 		card->op_sync_orin = 0;
 		card->irq_err_ignore = 0;
 		/* A_PWRDN DA_SBR DA_APP (high speed serial) */
 		break;
 
-	case BTTV_AVDVBT_771: //case 0x07711461:
+	case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
 		card->gpio_mode = 0x0400402B;
 		card->op_sync_orin = BT878_RISC_SYNC_MASK;
 		card->irq_err_ignore = 0;
 		/* A_PWRDN DA_SBR  DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
 		break;
 
-	case BTTV_TWINHAN_DST:
+	case BTTV_BOARD_TWINHAN_DST:
 		card->gpio_mode = 0x2204f2c;
 		card->op_sync_orin = BT878_RISC_SYNC_MASK;
 		card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
@@ -802,7 +868,7 @@
 		 * RISC+FIFO ENABLE */
 		break;
 
-	case BTTV_PC_HDTV:
+	case BTTV_BOARD_PC_HDTV:
 		card->gpio_mode = 0x0100EC7B;
 		card->op_sync_orin = 0;
 		card->irq_err_ignore = 0;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index 9ec8e5b..cf035a8 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -35,6 +35,7 @@
 #include "nxt6000.h"
 #include "cx24110.h"
 #include "or51211.h"
+#include "lgdt330x.h"
 
 struct dvb_bt8xx_card {
 	struct semaphore lock;
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 9719a3b..7d7b006 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -48,8 +48,11 @@
  * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
  */
 
+#ifndef DMX_MAX_SECTION_SIZE
+#define DMX_MAX_SECTION_SIZE 4096
+#endif
 #ifndef DMX_MAX_SECFEED_SIZE
-#define DMX_MAX_SECFEED_SIZE 4096
+#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
 #endif
 
 
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index dc476dd..b4c899b 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -246,7 +246,7 @@
 
 	for (n = 0; sec->secbufp + 2 < limit; n++) {
 		seclen = section_length(sec->secbuf);
-		if (seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE
+		if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
 		    || seclen + sec->secbufp > limit)
 			return 0;
 		sec->seclen = seclen;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index a8bc842..6ffa6b2 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -42,8 +42,6 @@
 #include "dvb_frontend.h"
 #include "dvbdev.h"
 
-// #define DEBUG_LOCKLOSS 1
-
 static int dvb_frontend_debug;
 static int dvb_shutdown_timeout = 5;
 static int dvb_force_auto_inversion;
@@ -438,25 +436,6 @@
 			if (s & FE_HAS_LOCK)
 				continue;
 			else { /* if we _WERE_ tuned, but now don't have a lock */
-#ifdef DEBUG_LOCKLOSS
-				/* first of all try setting the tone again if it was on - this
-				 * sometimes works around problems with noisy power supplies */
-				if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) {
-					fe->ops->set_tone(fe, fepriv->tone);
-					mdelay(100);
-					s = 0;
-					fe->ops->read_status(fe, &s);
-					if (s & FE_HAS_LOCK) {
-						printk("DVB%i: Lock was lost, but regained by setting "
-						       "the tone. This may indicate your power supply "
-						       "is noisy/slightly incompatable with this DVB-S "
-						       "adapter\n", fe->dvb->num);
-						fepriv->state = FESTATE_TUNED;
-						continue;
-					}
-				}
-#endif
-				/* some other reason for losing the lock - start zigzagging */
 				fepriv->state = FESTATE_ZIGZAG_FAST;
 				fepriv->started_auto_step = fepriv->auto_step;
 				check_wrapped = 0;
@@ -577,6 +556,49 @@
 				fepriv->thread_pid);
 }
 
+s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
+{
+	return ((curtime.tv_usec < lasttime.tv_usec) ?
+		1000000 - lasttime.tv_usec + curtime.tv_usec :
+		curtime.tv_usec - lasttime.tv_usec);
+}
+EXPORT_SYMBOL(timeval_usec_diff);
+
+static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
+{
+	curtime->tv_usec += add_usec;
+	if (curtime->tv_usec >= 1000000) {
+		curtime->tv_usec -= 1000000;
+		curtime->tv_sec++;
+	}
+}
+
+/*
+ * Sleep until gettimeofday() > waketime + add_usec
+ * This needs to be as precise as possible, but as the delay is
+ * usually between 2ms and 32ms, it is done using a scheduled msleep
+ * followed by usleep (normally a busy-wait loop) for the remainder
+ */
+void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
+{
+	struct timeval lasttime;
+	s32 delta, newdelta;
+
+	timeval_usec_add(waketime, add_usec);
+
+	do_gettimeofday(&lasttime);
+	delta = timeval_usec_diff(lasttime, *waketime);
+	if (delta > 2500) {
+		msleep((delta - 1500) / 1000);
+		do_gettimeofday(&lasttime);
+		newdelta = timeval_usec_diff(lasttime, *waketime);
+		delta = (newdelta > delta) ? 0 : newdelta;
+	}
+	if (delta > 0)
+		udelay(delta);
+}
+EXPORT_SYMBOL(dvb_frontend_sleep_until);
+
 static int dvb_frontend_start(struct dvb_frontend *fe)
 {
 	int ret;
@@ -728,6 +750,60 @@
 			err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
+		} else if (fe->ops->set_voltage) {
+			/*
+			 * NOTE: This is a fallback condition.  Some frontends
+			 * (stv0299 for instance) take longer than 8msec to
+			 * respond to a set_voltage command.  Those switches
+			 * need custom routines to switch properly.  For all
+			 * other frontends, the following shoule work ok.
+			 * Dish network legacy switches (as used by Dish500)
+			 * are controlled by sending 9-bit command words
+			 * spaced 8msec apart.
+			 * the actual command word is switch/port dependant
+			 * so it is up to the userspace application to send
+			 * the right command.
+			 * The command must always start with a '0' after
+			 * initialization, so parg is 8 bits and does not
+			 * include the initialization or start bit
+			 */
+			unsigned int cmd = ((unsigned int) parg) << 1;
+			struct timeval nexttime;
+			struct timeval tv[10];
+			int i;
+			u8 last = 1;
+			if (dvb_frontend_debug)
+				printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd);
+			do_gettimeofday(&nexttime);
+			if (dvb_frontend_debug)
+				memcpy(&tv[0], &nexttime, sizeof(struct timeval));
+			/* before sending a command, initialize by sending
+			 * a 32ms 18V to the switch
+			 */
+			fe->ops->set_voltage(fe, SEC_VOLTAGE_18);
+			dvb_frontend_sleep_until(&nexttime, 32000);
+
+			for (i = 0; i < 9; i++) {
+				if (dvb_frontend_debug)
+					do_gettimeofday(&tv[i + 1]);
+				if ((cmd & 0x01) != last) {
+					/* set voltage to (last ? 13V : 18V) */
+					fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+					last = (last) ? 0 : 1;
+				}
+				cmd = cmd >> 1;
+				if (i != 8)
+					dvb_frontend_sleep_until(&nexttime, 8000);
+			}
+			if (dvb_frontend_debug) {
+				printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
+					__FUNCTION__, fe->dvb->num);
+				for (i = 1; i < 10; i++)
+					printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
+			}
+			err = 0;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
 		}
 		break;
 
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 9c2c1d1..348c9b0 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -101,4 +101,7 @@
 
 extern int dvb_unregister_frontend(struct dvb_frontend* fe);
 
+extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
+extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
+
 #endif
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index e55322e..49f541d 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -43,11 +43,9 @@
 	{ 0x02, 0x13, KEY_RIGHT },       /* R / CH RTN */
 	{ 0x02, 0x17, KEY_PROG2 },       /* SNAP SHOT */
 	{ 0x02, 0x10, KEY_PROG3 },       /* 16-CH PREV */
-	{ 0x02, 0x03, KEY_CHANNELUP },   /* CH UP */
 	{ 0x02, 0x1e, KEY_VOLUMEDOWN },  /* VOL DOWN */
 	{ 0x02, 0x0c, KEY_ZOOM },        /* FULL SCREEN */
 	{ 0x02, 0x1f, KEY_VOLUMEUP },    /* VOL UP */
-	{ 0x02, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
 	{ 0x02, 0x14, KEY_MUTE },        /* MUTE */
 	{ 0x02, 0x08, KEY_AUDIO },       /* AUDIO */
 	{ 0x02, 0x19, KEY_RECORD },      /* RECORD */
@@ -57,8 +55,6 @@
 	{ 0x02, 0x1d, KEY_BACK },        /* << / RED */
 	{ 0x02, 0x1c, KEY_FORWARD },     /* >> / YELLOW */
 	{ 0x02, 0x03, KEY_TEXT },        /* TELETEXT */
-	{ 0x02, 0x01, KEY_FIRST },       /* |<< / GREEN */
-	{ 0x02, 0x00, KEY_LAST },        /* >>| / BLUE */
 	{ 0x02, 0x04, KEY_EPG },         /* EPG */
 	{ 0x02, 0x15, KEY_MENU },        /* MENU */
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 0058505..aa271a2 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -82,13 +82,15 @@
 static struct dvb_usb_properties dibusb1_1_properties;
 static struct dvb_usb_properties dibusb1_1_an2235_properties;
 static struct dvb_usb_properties dibusb2_0b_properties;
+static struct dvb_usb_properties artec_t1_usb2_properties;
 
 static int dibusb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0)
+		dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&artec_t1_usb2_properties,THIS_MODULE,NULL) == 0)
 		return 0;
 
 	return -EINVAL;
@@ -128,10 +130,13 @@
 
 /* 27 */	{ USB_DEVICE(USB_VID_KWORLD,		USB_PID_KWORLD_VSTREAM_COLD) },
 
+/* 28 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,		USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 29 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,		USB_PID_ULTIMA_TVBOX_USB2_WARM) },
+
 // #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
 
 #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
-/* 28 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+/* 30 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
 #endif
 			{ }		/* Terminating entry */
 };
@@ -264,7 +269,7 @@
 		},
 #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
 		{	"Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
-			{ &dibusb_dib3000mb_table[28], NULL },
+			{ &dibusb_dib3000mb_table[30], NULL },
 			{ NULL },
 		},
 #endif
@@ -273,7 +278,7 @@
 
 static struct dvb_usb_properties dibusb2_0b_properties = {
 	.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
-	.pid_filter_count = 32,
+	.pid_filter_count = 16,
 
 	.usb_ctrl = CYPRESS_FX2,
 
@@ -321,6 +326,52 @@
 	}
 };
 
+static struct dvb_usb_properties artec_t1_usb2_properties = {
+	.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+	.pid_filter_count = 16,
+
+	.usb_ctrl = CYPRESS_FX2,
+
+	.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
+
+	.size_of_priv     = sizeof(struct dibusb_state),
+
+	.streaming_ctrl   = dibusb2_0_streaming_ctrl,
+	.pid_filter       = dibusb_pid_filter,
+	.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+	.power_ctrl       = dibusb2_0_power_ctrl,
+	.frontend_attach  = dibusb_dib3000mb_frontend_attach,
+	.tuner_attach     = dibusb_tuner_probe_and_attach,
+
+	.rc_interval      = DEFAULT_RC_INTERVAL,
+	.rc_key_map       = dibusb_rc_keys,
+	.rc_key_map_size  = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+	.rc_query         = dibusb_rc_query,
+
+	.i2c_algo         = &dibusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	/* parameter for the MPEG2-data transfer */
+	.urb = {
+		.type = DVB_USB_BULK,
+		.count = 7,
+		.endpoint = 0x06,
+		.u = {
+			.bulk = {
+				.buffersize = 4096,
+			}
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{	"Artec T1 USB2.0",
+			{ &dibusb_dib3000mb_table[28], NULL },
+			{ &dibusb_dib3000mb_table[29], NULL },
+		},
+	}
+};
+
 static struct usb_driver dibusb_driver = {
 	.owner		= THIS_MODULE,
 	.name		= "dvb_usb_dibusb_mb",
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index 6611f62..2d99d05 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -11,7 +11,9 @@
 #ifndef _DVB_USB_DIBUSB_H_
 #define _DVB_USB_DIBUSB_H_
 
-#define DVB_USB_LOG_PREFIX "dibusb"
+#ifndef DVB_USB_LOG_PREFIX
+ #define DVB_USB_LOG_PREFIX "dibusb"
+#endif
 #include "dvb-usb.h"
 
 #include "dib3000.h"
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 0818996..6be99e5 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -43,10 +43,14 @@
 #define USB_PID_COMPRO_DVBU2000_WARM		0xd001
 #define USB_PID_COMPRO_DVBU2000_UNK_COLD	0x010c
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM	0x010d
+#define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
+#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM	0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
 #define USB_PID_DIBCOM_MOD3000_WARM			0x0bb9
 #define USB_PID_DIBCOM_MOD3001_COLD			0x0bc6
 #define USB_PID_DIBCOM_MOD3001_WARM			0x0bc7
+#define USB_PID_DIBCOM_STK7700				0x1e14
+#define USB_PID_DIBCOM_STK7700_REENUM		0x1e15
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD		0x2131
 #define USB_PID_GRANDTEC_DVBT_USB_COLD		0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM		0x0fa1
@@ -68,6 +72,7 @@
 #define USB_PID_ULTIMA_TVBOX_AN2235_WARM	0x8108
 #define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD	0x2235
 #define USB_PID_ULTIMA_TVBOX_USB2_COLD		0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_WARM		0x810a
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD	0x8613
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM	0x1002
 #define USB_PID_UNK_HYPER_PALTEK_COLD		0x005e
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index f5799a4..36b7048 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -196,7 +196,9 @@
 			dvb_usb_free_stream_buffers(d);
 			return -ENOMEM;
 		}
-		deb_mem("buffer %d: %p (dma: %d)\n",d->buf_num,d->buf_list[d->buf_num],d->dma_addr[d->buf_num]);
+		deb_mem("buffer %d: %p (dma: %llu)\n",
+			d->buf_num, d->buf_list[d->buf_num],
+			(unsigned long long)d->dma_addr[d->buf_num]);
 		memset(d->buf_list[d->buf_num],0,size);
 	}
 	deb_mem("allocation successful\n");
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index a50a41f..8e269e1 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -164,6 +164,14 @@
 	help
 	  An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
 
+config DVB_NXT200X
+	tristate "Nextwave NXT2002/NXT2004 based"
+	depends on DVB_CORE
+	select FW_LOADER
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
 config DVB_OR51211
 	tristate "or51211 based (pcHDTV HD2000 card)"
 	depends on DVB_CORE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index ad8658f..a98760f 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -26,6 +26,7 @@
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
 obj-$(CONFIG_DVB_STV0297) += stv0297.o
 obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
+obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
 obj-$(CONFIG_DVB_OR51211) += or51211.o
 obj-$(CONFIG_DVB_OR51132) += or51132.o
 obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 536c35d..f857b86 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -226,7 +226,7 @@
 EXPORT_SYMBOL(dvb_pll_tua6034);
 
 /* Infineon TUA6034
- * used in LG Innotek TDVS-H062F
+ * used in LG TDVS H061F and LG TDVS H062F
  */
 struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
 	.name  = "LG/Infineon TUA6034",
@@ -292,6 +292,58 @@
 };
 EXPORT_SYMBOL(dvb_pll_tded4);
 
+/* ALPS TDHU2
+ * used in AverTVHD MCE A180
+ */
+struct dvb_pll_desc dvb_pll_tdhu2 = {
+	.name = "ALPS TDHU2",
+	.min = 54000000,
+	.max = 864000000,
+	.count = 4,
+	.entries = {
+		{ 162000000, 44000000, 62500, 0x85, 0x01 },
+		{ 426000000, 44000000, 62500, 0x85, 0x02 },
+		{ 782000000, 44000000, 62500, 0x85, 0x08 },
+		{ 999999999, 44000000, 62500, 0x85, 0x88 },
+	}
+};
+EXPORT_SYMBOL(dvb_pll_tdhu2);
+
+/* Philips TUV1236D
+ * used in ATI HDTV Wonder
+ */
+struct dvb_pll_desc dvb_pll_tuv1236d = {
+	.name  = "Philips TUV1236D",
+	.min   =  54000000,
+	.max   = 864000000,
+	.count = 3,
+	.entries = {
+		{ 157250000, 44000000, 62500, 0xc6, 0x41 },
+		{ 454000000, 44000000, 62500, 0xc6, 0x42 },
+		{ 999999999, 44000000, 62500, 0xc6, 0x44 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_tuv1236d);
+
+/* Samsung TBMV30111IN
+ * used in Air2PC ATSC - 2nd generation (nxt2002)
+ */
+struct dvb_pll_desc dvb_pll_tbmv30111in = {
+	.name = "Samsung TBMV30111IN",
+	.min = 54000000,
+	.max = 860000000,
+	.count = 4,
+	.entries = {
+		{ 172000000, 44000000, 166666, 0xb4, 0x01 },
+		{ 214000000, 44000000, 166666, 0xb4, 0x02 },
+		{ 467000000, 44000000, 166666, 0xbc, 0x02 },
+		{ 721000000, 44000000, 166666, 0xbc, 0x08 },
+		{ 841000000, 44000000, 166666, 0xf4, 0x08 },
+		{ 999999999, 44000000, 166666, 0xfc, 0x02 },
+	}
+};
+EXPORT_SYMBOL(dvb_pll_tbmv30111in);
+
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 205b2d1..497d31d 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -36,6 +36,10 @@
 extern struct dvb_pll_desc dvb_pll_fmd1216me;
 extern struct dvb_pll_desc dvb_pll_tded4;
 
+extern struct dvb_pll_desc dvb_pll_tuv1236d;
+extern struct dvb_pll_desc dvb_pll_tdhu2;
+extern struct dvb_pll_desc dvb_pll_tbmv30111in;
+
 int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 		      u32 freq, int bandwidth);
 
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 7852b83..6a33f5a 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -26,6 +26,8 @@
  *   DViCO FusionHDTV 3 Gold-Q
  *   DViCO FusionHDTV 3 Gold-T
  *   DViCO FusionHDTV 5 Gold
+ *   DViCO FusionHDTV 5 Lite
+ *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
  *
  * TODO:
  * signal strength always returns 0.
@@ -222,6 +224,11 @@
 		0x4c, 0x14
 	};
 
+	static u8 flip_lgdt3303_init_data[] = {
+		0x4c, 0x14,
+		0x87, 0xf3
+	};
+
 	struct lgdt330x_state* state = fe->demodulator_priv;
 	char  *chip_name;
 	int    err;
@@ -234,8 +241,13 @@
 		break;
 	case LGDT3303:
 		chip_name = "LGDT3303";
-		err = i2c_write_demod_bytes(state, lgdt3303_init_data,
-					    sizeof(lgdt3303_init_data));
+		if (state->config->clock_polarity_flip) {
+			err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data,
+						    sizeof(flip_lgdt3303_init_data));
+		} else {
+			err = i2c_write_demod_bytes(state, lgdt3303_init_data,
+						    sizeof(lgdt3303_init_data));
+		}
 		break;
 	default:
 		chip_name = "undefined";
@@ -743,9 +755,8 @@
 		.frequency_min= 54000000,
 		.frequency_max= 858000000,
 		.frequency_stepsize= 62500,
-		/* Symbol rate is for all VSB modes need to check QAM */
-		.symbol_rate_min    = 10762000,
-		.symbol_rate_max    = 10762000,
+		.symbol_rate_min    = 5056941,	/* QAM 64 */
+		.symbol_rate_max    = 10762000,	/* VSB 8  */
 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
 	},
 	.init                 = lgdt330x_init,
@@ -767,9 +778,8 @@
 		.frequency_min= 54000000,
 		.frequency_max= 858000000,
 		.frequency_stepsize= 62500,
-		/* Symbol rate is for all VSB modes need to check QAM */
-		.symbol_rate_min    = 10762000,
-		.symbol_rate_max    = 10762000,
+		.symbol_rate_min    = 5056941,	/* QAM 64 */
+		.symbol_rate_max    = 10762000,	/* VSB 8  */
 		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
 	},
 	.init                 = lgdt330x_init,
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
index e209ba1..2a6529c 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb/frontends/lgdt330x.h
@@ -47,6 +47,10 @@
 
 	/* Need to set device param for start_dma */
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+	/* Flip the polarity of the mpeg data transfer clock using alternate init data
+	 * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled */
+	int clock_polarity_flip;
 };
 
 extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
new file mode 100644
index 0000000..bad0933
--- /dev/null
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -0,0 +1,1205 @@
+/*
+ *    Support for NXT2002 and NXT2004 - VSB/QAM
+ *
+ *    Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com)
+ *    based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
+ *    and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.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.
+ *
+*/
+
+/*
+ *                      NOTES ABOUT THIS DRIVER
+ *
+ * This Linux driver supports:
+ *   B2C2/BBTI Technisat Air2PC - ATSC (NXT2002)
+ *   AverTVHD MCE A180 (NXT2004)
+ *   ATI HDTV Wonder (NXT2004)
+ *
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+ * download/extract the appropriate firmware, and then copy it to
+ * /usr/lib/hotplug/firmware/ or /lib/firmware/
+ * (depending on configuration of firmware hotplug).
+ */
+#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
+#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
+#define CRC_CCIT_MASK 0x1021
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "nxt200x.h"
+
+struct nxt200x_state {
+
+	struct i2c_adapter* i2c;
+	struct dvb_frontend_ops ops;
+	const struct nxt200x_config* config;
+	struct dvb_frontend frontend;
+
+	/* demodulator private data */
+	nxt_chip_type demod_chip;
+	u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "nxt200x: " args); \
+	} while (0)
+
+static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len)
+{
+	int err;
+	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
+			__FUNCTION__, addr, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len)
+{
+	int err;
+	struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
+			__FUNCTION__, addr, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, u8 *buf, u8 len)
+{
+	u8 buf2 [len+1];
+	int err;
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
+
+	buf2[0] = reg;
+	memcpy(&buf2[1], buf, len);
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
+			__FUNCTION__, state->config->demod_address, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len)
+{
+	u8 reg2 [] = { reg };
+
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },
+			{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };
+
+	int err;
+
+	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
+		printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
+			__FUNCTION__, state->config->demod_address, err);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static u16 nxt200x_crc(u16 crc, u8 c)
+{
+	u8 i;
+	u16 input = (u16) c & 0xFF;
+
+	input<<=8;
+	for(i=0; i<8; i++) {
+		if((crc^input) & 0x8000)
+			crc=(crc<<1)^CRC_CCIT_MASK;
+		else
+			crc<<=1;
+		input<<=1;
+	}
+	return crc;
+}
+
+static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+	u8 attr, len2, buf;
+	dprintk("%s\n", __FUNCTION__);
+
+	/* set mutli register register */
+	nxt200x_writebytes(state, 0x35, &reg, 1);
+
+	/* send the actual data */
+	nxt200x_writebytes(state, 0x36, data, len);
+
+	switch (state->demod_chip) {
+		case NXT2002:
+			len2 = len;
+			buf = 0x02;
+			break;
+		case NXT2004:
+			/* probably not right, but gives correct values */
+			attr = 0x02;
+			if (reg & 0x80) {
+				attr = attr << 1;
+				if (reg & 0x04)
+					attr = attr >> 1;
+			}
+			/* set write bit */
+			len2 = ((attr << 4) | 0x10) | len;
+			buf = 0x80;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	/* set multi register length */
+	nxt200x_writebytes(state, 0x34, &len2, 1);
+
+	/* toggle the multireg write bit */
+	nxt200x_writebytes(state, 0x21, &buf, 1);
+
+	nxt200x_readbytes(state, 0x21, &buf, 1);
+
+	switch (state->demod_chip) {
+		case NXT2002:
+			if ((buf & 0x02) == 0)
+				return 0;
+			break;
+		case NXT2004:
+			if (buf == 0)
+				return 0;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg);
+
+	return 0;
+}
+
+static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+	int i;
+	u8 buf, len2, attr;
+	dprintk("%s\n", __FUNCTION__);
+
+	/* set mutli register register */
+	nxt200x_writebytes(state, 0x35, &reg, 1);
+
+	switch (state->demod_chip) {
+		case NXT2002:
+			/* set multi register length */
+			len2 = len & 0x80;
+			nxt200x_writebytes(state, 0x34, &len2, 1);
+
+			/* read the actual data */
+			nxt200x_readbytes(state, reg, data, len);
+			return 0;
+			break;
+		case NXT2004:
+			/* probably not right, but gives correct values */
+			attr = 0x02;
+			if (reg & 0x80) {
+				attr = attr << 1;
+				if (reg & 0x04)
+					attr = attr >> 1;
+			}
+
+			/* set multi register length */
+			len2 = (attr << 4) | len;
+			nxt200x_writebytes(state, 0x34, &len2, 1);
+
+			/* toggle the multireg bit*/
+			buf = 0x80;
+			nxt200x_writebytes(state, 0x21, &buf, 1);
+
+			/* read the actual data */
+			for(i = 0; i < len; i++) {
+				nxt200x_readbytes(state, 0x36 + i, &data[i], 1);
+			}
+			return 0;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+}
+
+static void nxt200x_microcontroller_stop (struct nxt200x_state* state)
+{
+	u8 buf, stopval, counter = 0;
+	dprintk("%s\n", __FUNCTION__);
+
+	/* set correct stop value */
+	switch (state->demod_chip) {
+		case NXT2002:
+			stopval = 0x40;
+			break;
+		case NXT2004:
+			stopval = 0x10;
+			break;
+		default:
+			stopval = 0;
+			break;
+	}
+
+	buf = 0x80;
+	nxt200x_writebytes(state, 0x22, &buf, 1);
+
+	while (counter < 20) {
+		nxt200x_readbytes(state, 0x31, &buf, 1);
+		if (buf & stopval)
+			return;
+		msleep(10);
+		counter++;
+	}
+
+	printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n");
+	return;
+}
+
+static void nxt200x_microcontroller_start (struct nxt200x_state* state)
+{
+	u8 buf;
+	dprintk("%s\n", __FUNCTION__);
+
+	buf = 0x00;
+	nxt200x_writebytes(state, 0x22, &buf, 1);
+}
+
+static void nxt2004_microcontroller_init (struct nxt200x_state* state)
+{
+	u8 buf[9];
+	u8 counter = 0;
+	dprintk("%s\n", __FUNCTION__);
+
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x2b, buf, 1);
+	buf[0] = 0x70;
+	nxt200x_writebytes(state, 0x34, buf, 1);
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x35, buf, 1);
+	buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89;
+	buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0;
+	nxt200x_writebytes(state, 0x36, buf, 9);
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x21, buf, 1);
+
+	while (counter < 20) {
+		nxt200x_readbytes(state, 0x21, buf, 1);
+		if (buf[0] == 0)
+			return;
+		msleep(10);
+		counter++;
+	}
+
+	printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n");
+
+	return;
+}
+
+static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
+{
+	u8 buf, count = 0;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+
+	/* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
+	 * direct write is required for Philips TUV1236D and ALPS TDHU2 */
+	switch (state->demod_chip) {
+		case NXT2004:
+			if (i2c_writebytes(state, state->config->pll_address, data, 4))
+	        	        printk(KERN_WARNING "nxt200x: error writing to tuner\n");
+			/* wait until we have a lock */
+			while (count < 20) {
+				i2c_readbytes(state, state->config->pll_address, &buf, 1);
+				if (buf & 0x40)
+					return 0;
+				msleep(100);
+				count++;
+			}
+			printk("nxt2004: timeout waiting for tuner lock\n");
+			break;
+		case NXT2002:
+			/* set the i2c transfer speed to the tuner */
+			buf = 0x03;
+			nxt200x_writebytes(state, 0x20, &buf, 1);
+
+			/* setup to transfer 4 bytes via i2c */
+			buf = 0x04;
+			nxt200x_writebytes(state, 0x34, &buf, 1);
+
+			/* write actual tuner bytes */
+			nxt200x_writebytes(state, 0x36, data, 4);
+
+			/* set tuner i2c address */
+			buf = state->config->pll_address;
+			nxt200x_writebytes(state, 0x35, &buf, 1);
+
+			/* write UC Opmode to begin transfer */
+			buf = 0x80;
+			nxt200x_writebytes(state, 0x21, &buf, 1);
+
+			while (count < 20) {
+				nxt200x_readbytes(state, 0x21, &buf, 1);
+				if ((buf & 0x80)== 0x00)
+					return 0;
+				msleep(100);
+				count++;
+			}
+			printk("nxt2002: timeout error writing tuner\n");
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+	return 0;
+}
+
+static void nxt200x_agc_reset(struct nxt200x_state* state)
+{
+	u8 buf;
+	dprintk("%s\n", __FUNCTION__);
+
+	switch (state->demod_chip) {
+		case NXT2002:
+			buf = 0x08;
+			nxt200x_writebytes(state, 0x08, &buf, 1);
+			buf = 0x00;
+			nxt200x_writebytes(state, 0x08, &buf, 1);
+			break;
+		case NXT2004:
+			nxt200x_readreg_multibyte(state, 0x08, &buf, 1);
+			buf = 0x08;
+			nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+			buf = 0x00;
+			nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+			break;
+		default:
+			break;
+	}
+	return;
+}
+
+static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 buf[3], written = 0, chunkpos = 0;
+	u16 rambase, position, crc = 0;
+
+	dprintk("%s\n", __FUNCTION__);
+	dprintk("Firmware is %zu bytes\n", fw->size);
+
+	/* Get the RAM base for this nxt2002 */
+	nxt200x_readbytes(state, 0x10, buf, 1);
+
+	if (buf[0] & 0x10)
+		rambase = 0x1000;
+	else
+		rambase = 0x0000;
+
+	dprintk("rambase on this nxt2002 is %04X\n", rambase);
+
+	/* Hold the micro in reset while loading firmware */
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x2B, buf, 1);
+
+	for (position = 0; position < fw->size; position++) {
+		if (written == 0) {
+			crc = 0;
+			chunkpos = 0x28;
+			buf[0] = ((rambase + position) >> 8);
+			buf[1] = (rambase + position) & 0xFF;
+			buf[2] = 0x81;
+			/* write starting address */
+			nxt200x_writebytes(state, 0x29, buf, 3);
+		}
+		written++;
+		chunkpos++;
+
+		if ((written % 4) == 0)
+			nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4);
+
+		crc = nxt200x_crc(crc, fw->data[position]);
+
+		if ((written == 255) || (position+1 == fw->size)) {
+			/* write remaining bytes of firmware */
+			nxt200x_writebytes(state, chunkpos+4-(written %4),
+				&fw->data[position-(written %4) + 1],
+				written %4);
+			buf[0] = crc << 8;
+			buf[1] = crc & 0xFF;
+
+			/* write crc */
+			nxt200x_writebytes(state, 0x2C, buf, 2);
+
+			/* do a read to stop things */
+			nxt200x_readbytes(state, 0x2A, buf, 1);
+
+			/* set transfer mode to complete */
+			buf[0] = 0x80;
+			nxt200x_writebytes(state, 0x2B, buf, 1);
+
+			written = 0;
+		}
+	}
+
+	return 0;
+};
+
+static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 buf[3];
+	u16 rambase, position, crc=0;
+
+	dprintk("%s\n", __FUNCTION__);
+	dprintk("Firmware is %zu bytes\n", fw->size);
+
+	/* set rambase */
+	rambase = 0x1000;
+
+	/* hold the micro in reset while loading firmware */
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x2B, buf,1);
+
+	/* calculate firmware CRC */
+	for (position = 0; position < fw->size; position++) {
+	        crc = nxt200x_crc(crc, fw->data[position]);
+	}
+
+	buf[0] = rambase >> 8;
+	buf[1] = rambase & 0xFF;
+	buf[2] = 0x81;
+	/* write starting address */
+	nxt200x_writebytes(state,0x29,buf,3);
+
+	for (position = 0; position < fw->size;) {
+		nxt200x_writebytes(state, 0x2C, &fw->data[position],
+			fw->size-position > 255 ? 255 : fw->size-position);
+		position += (fw->size-position > 255 ? 255 : fw->size-position);
+	}
+	buf[0] = crc >> 8;
+	buf[1] = crc & 0xFF;
+
+	dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]);
+
+	/* write crc */
+	nxt200x_writebytes(state, 0x2C, buf,2);
+
+	/* do a read to stop things */
+	nxt200x_readbytes(state, 0x2C, buf, 1);
+
+	/* set transfer mode to complete */
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x2B, buf,1);
+
+	return 0;
+};
+
+static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
+					     struct dvb_frontend_parameters *p)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 buf[4];
+
+	/* stop the micro first */
+	nxt200x_microcontroller_stop(state);
+
+	if (state->demod_chip == NXT2004) {
+		/* make sure demod is set to digital */
+		buf[0] = 0x04;
+		nxt200x_writebytes(state, 0x14, buf, 1);
+		buf[0] = 0x00;
+		nxt200x_writebytes(state, 0x17, buf, 1);
+	}
+
+	/* get tuning information */
+	dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);
+
+	/* set additional params */
+	switch (p->u.vsb.modulation) {
+		case QAM_64:
+		case QAM_256:
+			/* Set punctured clock for QAM */
+			/* This is just a guess since I am unable to test it */
+			if (state->config->set_ts_params)
+				state->config->set_ts_params(fe, 1);
+
+			/* set input */
+			if (state->config->set_pll_input)
+				state->config->set_pll_input(buf, 1);
+			break;
+		case VSB_8:
+			/* Set non-punctured clock for VSB */
+			if (state->config->set_ts_params)
+				state->config->set_ts_params(fe, 0);
+
+			/* set input */
+			if (state->config->set_pll_input)
+				state->config->set_pll_input(buf, 0);
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+
+	/* write frequency information */
+	nxt200x_writetuner(state, buf);
+
+	/* reset the agc now that tuning has been completed */
+	nxt200x_agc_reset(state);
+
+	/* set target power level */
+	switch (p->u.vsb.modulation) {
+		case QAM_64:
+		case QAM_256:
+			buf[0] = 0x74;
+			break;
+		case VSB_8:
+			buf[0] = 0x70;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+	nxt200x_writebytes(state, 0x42, buf, 1);
+
+	/* configure sdm */
+	switch (state->demod_chip) {
+		case NXT2002:
+			buf[0] = 0x87;
+			break;
+		case NXT2004:
+			buf[0] = 0x07;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+	nxt200x_writebytes(state, 0x57, buf, 1);
+
+	/* write sdm1 input */
+	buf[0] = 0x10;
+	buf[1] = 0x00;
+	nxt200x_writebytes(state, 0x58, buf, 2);
+
+	/* write sdmx input */
+	switch (p->u.vsb.modulation) {
+		case QAM_64:
+				buf[0] = 0x68;
+				break;
+		case QAM_256:
+				buf[0] = 0x64;
+				break;
+		case VSB_8:
+				buf[0] = 0x60;
+				break;
+		default:
+				return -EINVAL;
+				break;
+	}
+	buf[1] = 0x00;
+	nxt200x_writebytes(state, 0x5C, buf, 2);
+
+	/* write adc power lpf fc */
+	buf[0] = 0x05;
+	nxt200x_writebytes(state, 0x43, buf, 1);
+
+	if (state->demod_chip == NXT2004) {
+		/* write ??? */
+		buf[0] = 0x00;
+		buf[1] = 0x00;
+		nxt200x_writebytes(state, 0x46, buf, 2);
+	}
+
+	/* write accumulator2 input */
+	buf[0] = 0x80;
+	buf[1] = 0x00;
+	nxt200x_writebytes(state, 0x4B, buf, 2);
+
+	/* write kg1 */
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x4D, buf, 1);
+
+	/* write sdm12 lpf fc */
+	buf[0] = 0x44;
+	nxt200x_writebytes(state, 0x55, buf, 1);
+
+	/* write agc control reg */
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x41, buf, 1);
+
+	if (state->demod_chip == NXT2004) {
+		nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+		buf[0] = 0x24;
+		nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+		/* soft reset? */
+		nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+		buf[0] = 0x10;
+		nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+		nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+		buf[0] = 0x00;
+		nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+		nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+		buf[0] = 0x04;
+		nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+		buf[0] = 0x00;
+		nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+		buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+		nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+		nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+		buf[0] = 0x11;
+		nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+		nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+		buf[0] = 0x44;
+		nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+	}
+
+	/* write agc ucgp0 */
+	switch (p->u.vsb.modulation) {
+		case QAM_64:
+				buf[0] = 0x02;
+				break;
+		case QAM_256:
+				buf[0] = 0x03;
+				break;
+		case VSB_8:
+				buf[0] = 0x00;
+				break;
+		default:
+				return -EINVAL;
+				break;
+	}
+	nxt200x_writebytes(state, 0x30, buf, 1);
+
+	/* write agc control reg */
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x41, buf, 1);
+
+	/* write accumulator2 input */
+	buf[0] = 0x80;
+	buf[1] = 0x00;
+	nxt200x_writebytes(state, 0x49, buf,2);
+	nxt200x_writebytes(state, 0x4B, buf,2);
+
+	/* write agc control reg */
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x41, buf, 1);
+
+	nxt200x_microcontroller_start(state);
+
+	if (state->demod_chip == NXT2004) {
+		nxt2004_microcontroller_init(state);
+
+		/* ???? */
+		buf[0] = 0xF0;
+		buf[1] = 0x00;
+		nxt200x_writebytes(state, 0x5C, buf, 2);
+	}
+
+	/* adjacent channel detection should be done here, but I don't
+	have any stations with this need so I cannot test it */
+
+	return 0;
+}
+
+static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 lock;
+	nxt200x_readbytes(state, 0x31, &lock, 1);
+
+	*status = 0;
+	if (lock & 0x20) {
+		*status |= FE_HAS_SIGNAL;
+		*status |= FE_HAS_CARRIER;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;
+		*status |= FE_HAS_LOCK;
+	}
+	return 0;
+}
+
+static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 b[3];
+
+	nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+
+	*ber = ((b[0] << 8) + b[1]) * 8;
+
+	return 0;
+}
+
+static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 b[2];
+	u16 temp = 0;
+
+	/* setup to read cluster variance */
+	b[0] = 0x00;
+	nxt200x_writebytes(state, 0xA1, b, 1);
+
+	/* get multreg val */
+	nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+	temp = (b[0] << 8) | b[1];
+	*strength = ((0x7FFF - temp) & 0x0FFF) * 16;
+
+	return 0;
+}
+
+static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 b[2];
+	u16 temp = 0, temp2;
+	u32 snrdb = 0;
+
+	/* setup to read cluster variance */
+	b[0] = 0x00;
+	nxt200x_writebytes(state, 0xA1, b, 1);
+
+	/* get multreg val from 0xA6 */
+	nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+	temp = (b[0] << 8) | b[1];
+	temp2 = 0x7FFF - temp;
+
+	/* snr will be in db */
+	if (temp2 > 0x7F00)
+		snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) );
+	else if (temp2 > 0x7EC0)
+		snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) );
+	else if (temp2 > 0x7C00)
+		snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) );
+	else
+		snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) );
+
+	/* the value reported back from the frontend will be FFFF=32db 0000=0db */
+	*snr = snrdb * (0xFFFF/32000);
+
+	return 0;
+}
+
+static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	u8 b[3];
+
+	nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+	*ucblocks = b[2];
+
+	return 0;
+}
+
+static int nxt200x_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int nxt2002_init(struct dvb_frontend* fe)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret;
+	u8 buf[2];
+
+	/* request the firmware, this will block until someone uploads it */
+	printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
+	ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev);
+	printk("nxt2002: Waiting for firmware upload(2)...\n");
+	if (ret) {
+		printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
+		return ret;
+	}
+
+	ret = nxt2002_load_firmware(fe, fw);
+	if (ret) {
+		printk("nxt2002: Writing firmware to device failed\n");
+		release_firmware(fw);
+		return ret;
+	}
+	printk("nxt2002: Firmware upload complete\n");
+
+	/* Put the micro into reset */
+	nxt200x_microcontroller_stop(state);
+
+	/* ensure transfer is complete */
+	buf[0]=0x00;
+	nxt200x_writebytes(state, 0x2B, buf, 1);
+
+	/* Put the micro into reset for real this time */
+	nxt200x_microcontroller_stop(state);
+
+	/* soft reset everything (agc,frontend,eq,fec)*/
+	buf[0] = 0x0F;
+	nxt200x_writebytes(state, 0x08, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x08, buf, 1);
+
+	/* write agc sdm configure */
+	buf[0] = 0xF1;
+	nxt200x_writebytes(state, 0x57, buf, 1);
+
+	/* write mod output format */
+	buf[0] = 0x20;
+	nxt200x_writebytes(state, 0x09, buf, 1);
+
+	/* write fec mpeg mode */
+	buf[0] = 0x7E;
+	buf[1] = 0x00;
+	nxt200x_writebytes(state, 0xE9, buf, 2);
+
+	/* write mux selection */
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0xCC, buf, 1);
+
+	return 0;
+}
+
+static int nxt2004_init(struct dvb_frontend* fe)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret;
+	u8 buf[3];
+
+	/* ??? */
+	buf[0]=0x00;
+	nxt200x_writebytes(state, 0x1E, buf, 1);
+
+	/* request the firmware, this will block until someone uploads it */
+	printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
+	ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev);
+	printk("nxt2004: Waiting for firmware upload(2)...\n");
+	if (ret) {
+		printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");
+		return ret;
+	}
+
+	ret = nxt2004_load_firmware(fe, fw);
+	if (ret) {
+		printk("nxt2004: Writing firmware to device failed\n");
+		release_firmware(fw);
+		return ret;
+	}
+	printk("nxt2004: Firmware upload complete\n");
+
+	/* ensure transfer is complete */
+	buf[0] = 0x01;
+	nxt200x_writebytes(state, 0x19, buf, 1);
+
+	nxt2004_microcontroller_init(state);
+	nxt200x_microcontroller_stop(state);
+	nxt200x_microcontroller_stop(state);
+	nxt2004_microcontroller_init(state);
+	nxt200x_microcontroller_stop(state);
+
+	/* soft reset everything (agc,frontend,eq,fec)*/
+	buf[0] = 0xFF;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+	/* write agc sdm configure */
+	buf[0] = 0xD7;
+	nxt200x_writebytes(state, 0x57, buf, 1);
+
+	/* ???*/
+	buf[0] = 0x07;
+	buf[1] = 0xfe;
+	nxt200x_writebytes(state, 0x35, buf, 2);
+	buf[0] = 0x12;
+	nxt200x_writebytes(state, 0x34, buf, 1);
+	buf[0] = 0x80;
+	nxt200x_writebytes(state, 0x21, buf, 1);
+
+	/* ???*/
+	buf[0] = 0x21;
+	nxt200x_writebytes(state, 0x0A, buf, 1);
+
+	/* ???*/
+	buf[0] = 0x01;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	/* write fec mpeg mode */
+	buf[0] = 0x7E;
+	buf[1] = 0x00;
+	nxt200x_writebytes(state, 0xE9, buf, 2);
+
+	/* write mux selection */
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0xCC, buf, 1);
+
+	/* ???*/
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	/* soft reset? */
+	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x10;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+	/* ???*/
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x01;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x70;
+	nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+	buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66;
+	nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+	nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+	buf[0] = 0x11;
+	nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x40;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	nxt200x_readbytes(state, 0x10, buf, 1);
+	buf[0] = 0x10;
+	nxt200x_writebytes(state, 0x10, buf, 1);
+	nxt200x_readbytes(state, 0x0A, buf, 1);
+	buf[0] = 0x21;
+	nxt200x_writebytes(state, 0x0A, buf, 1);
+
+	nxt2004_microcontroller_init(state);
+
+	buf[0] = 0x21;
+	nxt200x_writebytes(state, 0x0A, buf, 1);
+	buf[0] = 0x7E;
+	nxt200x_writebytes(state, 0xE9, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0xEA, buf, 1);
+
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	/* soft reset? */
+	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x10;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+	nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x04;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+	buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+	nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+	nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+	buf[0] = 0x11;
+	nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+
+	nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+	buf[0] = 0x44;
+	nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+	/* initialize tuner */
+	nxt200x_readbytes(state, 0x10, buf, 1);
+	buf[0] = 0x12;
+	nxt200x_writebytes(state, 0x10, buf, 1);
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x13, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x16, buf, 1);
+	buf[0] = 0x04;
+	nxt200x_writebytes(state, 0x14, buf, 1);
+	buf[0] = 0x00;
+	nxt200x_writebytes(state, 0x14, buf, 1);
+	nxt200x_writebytes(state, 0x17, buf, 1);
+	nxt200x_writebytes(state, 0x14, buf, 1);
+	nxt200x_writebytes(state, 0x17, buf, 1);
+
+	return 0;
+}
+
+static int nxt200x_init(struct dvb_frontend* fe)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	int ret = 0;
+
+	if (!state->initialised) {
+		switch (state->demod_chip) {
+			case NXT2002:
+				ret = nxt2002_init(fe);
+				break;
+			case NXT2004:
+				ret = nxt2004_init(fe);
+				break;
+			default:
+				return -EINVAL;
+				break;
+		}
+		state->initialised = 1;
+	}
+	return ret;
+}
+
+static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 500;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static void nxt200x_release(struct dvb_frontend* fe)
+{
+	struct nxt200x_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops nxt200x_ops;
+
+struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+				   struct i2c_adapter* i2c)
+{
+	struct nxt200x_state* state = NULL;
+	u8 buf [] = {0,0,0,0,0};
+
+	/* allocate memory for the internal state */
+	state = (struct nxt200x_state*) kmalloc(sizeof(struct nxt200x_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+	memset(state,0,sizeof(*state));
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
+	state->initialised = 0;
+
+	/* read card id */
+	nxt200x_readbytes(state, 0x00, buf, 5);
+	dprintk("NXT info: %02X %02X %02X %02X %02X\n",
+		buf[0], buf[1], buf[2],	buf[3], buf[4]);
+
+	/* set demod chip */
+	switch (buf[0]) {
+		case 0x04:
+			state->demod_chip = NXT2002;
+			printk("nxt200x: NXT2002 Detected\n");
+			break;
+		case 0x05:
+			state->demod_chip = NXT2004;
+			printk("nxt200x: NXT2004 Detected\n");
+			break;
+		default:
+			goto error;
+	}
+
+	/* make sure demod chip is supported */
+	switch (state->demod_chip) {
+		case NXT2002:
+			if (buf[0] != 0x04) goto error;		/* device id */
+			if (buf[1] != 0x02) goto error;		/* fab id */
+			if (buf[2] != 0x11) goto error;		/* month */
+			if (buf[3] != 0x20) goto error;		/* year msb */
+			if (buf[4] != 0x00) goto error;		/* year lsb */
+			break;
+		case NXT2004:
+			if (buf[0] != 0x05) goto error;		/* device id */
+			break;
+		default:
+			goto error;
+	}
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	printk("Unknown/Unsupported NXT chip: %02X %02X %02X %02X %02X\n",
+		buf[0], buf[1], buf[2], buf[3], buf[4]);
+	return NULL;
+}
+
+static struct dvb_frontend_ops nxt200x_ops = {
+
+	.info = {
+		.name = "Nextwave NXT200X VSB/QAM frontend",
+		.type = FE_ATSC,
+		.frequency_min =  54000000,
+		.frequency_max = 860000000,
+		.frequency_stepsize = 166666,	/* stepsize is just a guess */
+		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256
+	},
+
+	.release = nxt200x_release,
+
+	.init = nxt200x_init,
+	.sleep = nxt200x_sleep,
+
+	.set_frontend = nxt200x_setup_frontend_parameters,
+	.get_tune_settings = nxt200x_get_tune_settings,
+
+	.read_status = nxt200x_read_status,
+	.read_ber = nxt200x_read_ber,
+	.read_signal_strength = nxt200x_read_signal_strength,
+	.read_snr = nxt200x_read_snr,
+	.read_ucblocks = nxt200x_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray, Jean-Francois Thibert, and Taylor Jacob");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(nxt200x_attach);
+
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
new file mode 100644
index 0000000..1d9d70b
--- /dev/null
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -0,0 +1,61 @@
+/*
+ *    Support for NXT2002 and NXT2004 - VSB/QAM
+ *
+ *    Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com)
+ *    based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
+ *    and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.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.
+ *
+*/
+
+#ifndef NXT200X_H
+#define NXT200X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+typedef enum nxt_chip_t {
+		NXTUNDEFINED,
+		NXT2002,
+		NXT2004
+}nxt_chip_type;
+
+struct nxt200x_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* tuner information */
+	u8 pll_address;
+	struct dvb_pll_desc *pll_desc;
+
+	/* used to set pll input */
+	int (*set_pll_input)(u8* buf, int input);
+
+	/* need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+};
+
+extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+					   struct i2c_adapter* i2c);
+
+#endif /* NXT200X_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index fc74c40..78bded8 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -468,6 +468,7 @@
 	unsigned char snd_buf[2];
 	u8 rcvr_stat;
 	u16 snr_equ;
+	u32 signal_strength;
 	int usK;
 
 	snd_buf[0]=0x04;
@@ -503,7 +504,11 @@
 	usK = (rcvr_stat & 0x10) ? 3 : 0;
 
         /* The value reported back from the frontend will be FFFF=100% 0000=0% */
-	*strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000;
+	signal_strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000;
+	if (signal_strength > 0xffff)
+		*strength = 0xffff;
+	else
+		*strength = signal_strength;
 	dprintk("read_signal_strength %i\n",*strength);
 
 	return 0;
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 8a9db23..531f762 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -339,6 +339,7 @@
 	u8 rec_buf[2];
 	u8 snd_buf[4];
 	u8 snr_equ;
+	u32 signal_strength;
 
 	/* SNR after Equalizer */
 	snd_buf[0] = 0x04;
@@ -358,8 +359,11 @@
 	snr_equ = rec_buf[0] & 0xff;
 
 	/* The value reported back from the frontend will be FFFF=100% 0000=0% */
-	*strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
-
+	signal_strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
+	if (signal_strength > 0xffff)
+		*strength = 0xffff;
+	else
+		*strength = signal_strength;
 	dprintk("read_signal_strength %i\n",*strength);
 
 	return 0;
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 889d925..29c4866 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -64,8 +64,12 @@
 	u32 tuner_frequency;
 	u32 symbol_rate;
 	fe_code_rate_t fec_inner;
+	int errmode;
 };
 
+#define STATUS_BER 0
+#define STATUS_UCBLOCKS 1
+
 static int debug;
 static int debug_legacy_dish_switch;
 #define dprintk(args...) \
@@ -383,36 +387,6 @@
 	};
 }
 
-static inline s32 stv0299_calc_usec_delay (struct timeval lasttime, struct timeval curtime)
-{
-	return ((curtime.tv_usec < lasttime.tv_usec) ?
-		1000000 - lasttime.tv_usec + curtime.tv_usec :
-		curtime.tv_usec - lasttime.tv_usec);
-}
-
-static void stv0299_sleep_until (struct timeval *waketime, u32 add_usec)
-{
-	struct timeval lasttime;
-	s32 delta, newdelta;
-
-	waketime->tv_usec += add_usec;
-	if (waketime->tv_usec >= 1000000) {
-		waketime->tv_usec -= 1000000;
-		waketime->tv_sec++;
-	}
-
-	do_gettimeofday (&lasttime);
-	delta = stv0299_calc_usec_delay (lasttime, *waketime);
-	if (delta > 2500) {
-		msleep ((delta - 1500) / 1000);
-		do_gettimeofday (&lasttime);
-		newdelta = stv0299_calc_usec_delay (lasttime, *waketime);
-		delta = (newdelta > delta) ? 0 : newdelta;
-	}
-	if (delta > 0)
-		udelay (delta);
-}
-
 static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
 {
 	struct stv0299_state* state = fe->demodulator_priv;
@@ -440,7 +414,7 @@
 		memcpy (&tv[0], &nexttime, sizeof (struct timeval));
 	stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
 
-	stv0299_sleep_until (&nexttime, 32000);
+	dvb_frontend_sleep_until(&nexttime, 32000);
 
 	for (i=0; i<9; i++) {
 		if (debug_legacy_dish_switch)
@@ -454,13 +428,13 @@
 		cmd = cmd >> 1;
 
 		if (i != 8)
-			stv0299_sleep_until (&nexttime, 8000);
+			dvb_frontend_sleep_until(&nexttime, 8000);
 	}
 	if (debug_legacy_dish_switch) {
 		printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
 			__FUNCTION__, fe->dvb->num);
-		for (i=1; i < 10; i++)
-			printk ("%d: %d\n", i, stv0299_calc_usec_delay (tv[i-1] , tv[i]));
+		for (i = 1; i < 10; i++)
+			printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
 	}
 
 	return 0;
@@ -517,8 +491,7 @@
 {
         struct stv0299_state* state = fe->demodulator_priv;
 
-	stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x10);
-	msleep(100);
+	if (state->errmode != STATUS_BER) return 0;
 	*ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
 
 	return 0;
@@ -557,9 +530,8 @@
 {
         struct stv0299_state* state = fe->demodulator_priv;
 
-	stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x30);
-	msleep(100);
-	*ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
+	if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0;
+	else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
 
 	return 0;
 }
@@ -581,49 +553,14 @@
 	if (state->config->invert) invval = (~invval) & 1;
 	stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
 
-	if (state->config->enhanced_tuning) {
-		/* check if we should do a finetune */
-		int frequency_delta = p->frequency - state->tuner_frequency;
-		int minmax = p->u.qpsk.symbol_rate / 2000;
-		if (minmax < 5000) minmax = 5000;
+	stv0299_writeregI(state, 0x05, 0xb5);	/*  enable i2c repeater on stv0299  */
+	state->config->pll_set(fe, state->i2c, p);
+	stv0299_writeregI(state, 0x05, 0x35);	/*  disable i2c repeater on stv0299  */
 
-		if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) &&
-		    (state->fec_inner == p->u.qpsk.fec_inner) &&
-		    (state->symbol_rate == p->u.qpsk.symbol_rate)) {
-			int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000);
-
-			// zap the derotator registers first
-			stv0299_writeregI(state, 0x22, 0x00);
-			stv0299_writeregI(state, 0x23, 0x00);
-
-			// now set them as we want
-			stv0299_writeregI(state, 0x22, Drot_freq >> 8);
-			stv0299_writeregI(state, 0x23, Drot_freq);
-		} else {
-			/* A "normal" tune is requested */
-			stv0299_writeregI(state, 0x05, 0xb5);	/*  enable i2c repeater on stv0299  */
-			state->config->pll_set(fe, state->i2c, p);
-			stv0299_writeregI(state, 0x05, 0x35);	/*  disable i2c repeater on stv0299  */
-
-			stv0299_writeregI(state, 0x32, 0x80);
-			stv0299_writeregI(state, 0x22, 0x00);
-			stv0299_writeregI(state, 0x23, 0x00);
-			stv0299_writeregI(state, 0x32, 0x19);
-			stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
-			stv0299_set_FEC (state, p->u.qpsk.fec_inner);
-		}
-	} else {
-		stv0299_writeregI(state, 0x05, 0xb5);	/*  enable i2c repeater on stv0299  */
-		state->config->pll_set(fe, state->i2c, p);
-		stv0299_writeregI(state, 0x05, 0x35);	/*  disable i2c repeater on stv0299  */
-
-		stv0299_set_FEC (state, p->u.qpsk.fec_inner);
-		stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
-		stv0299_writeregI(state, 0x22, 0x00);
-		stv0299_writeregI(state, 0x23, 0x00);
-		stv0299_readreg (state, 0x23);
-		stv0299_writeregI(state, 0x12, 0xb9);
-	}
+	stv0299_set_FEC (state, p->u.qpsk.fec_inner);
+	stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
+	stv0299_writeregI(state, 0x22, 0x00);
+	stv0299_writeregI(state, 0x23, 0x00);
 
 	state->tuner_frequency = p->frequency;
 	state->fec_inner = p->u.qpsk.fec_inner;
@@ -708,6 +645,7 @@
 	state->tuner_frequency = 0;
 	state->symbol_rate = 0;
 	state->fec_inner = 0;
+	state->errmode = STATUS_BER;
 
 	/* check if the demod is there */
 	stv0299_writeregI(state, 0x02, 0x34); /* standby off */
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index d0c4484..9af3d71 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -73,9 +73,6 @@
 	/* does the inversion require inversion? */
 	u8 invert:1;
 
-	/* Should the enhanced tuning code be used? */
-	u8 enhanced_tuning:1;
-
 	/* Skip reinitialisation? */
 	u8 skip_reinit:1;
 
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 3529c61..7968743 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -420,7 +420,7 @@
 	struct tda1004x_state* state = fe->demodulator_priv;
 
 	tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
-	tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
+	tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10
 	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
 		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
 		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
@@ -597,7 +597,10 @@
 	// Init the tuner PLL
 	if (state->config->pll_init) {
 		tda1004x_enable_tuner_i2c(state);
-		state->config->pll_init(fe);
+		if (state->config->pll_init(fe)) {
+			printk(KERN_ERR "tda1004x: pll init failed\n");
+			return 	-EIO;
+		}
 		tda1004x_disable_tuner_i2c(state);
 	}
 
@@ -667,7 +670,10 @@
 
 	// set frequency
 	tda1004x_enable_tuner_i2c(state);
-	state->config->pll_set(fe, fe_params);
+	if (state->config->pll_set(fe, fe_params)) {
+		printk(KERN_ERR "tda1004x: pll set failed\n");
+		return 	-EIO;
+	}
 	tda1004x_disable_tuner_i2c(state);
 
 	// Hardcoded to use auto as much as possible on the TDA10045 as it
@@ -832,6 +838,8 @@
 
 	case TDA1004X_DEMOD_TDA10046:
 		tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
+		msleep(1);
+		tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1);
 		break;
 	}
 
@@ -1129,7 +1137,12 @@
 		if (state->config->pll_sleep != NULL) {
 			tda1004x_enable_tuner_i2c(state);
 			state->config->pll_sleep(fe);
-			tda1004x_disable_tuner_i2c(state);
+			if (state->config->if_freq != TDA10046_FREQ_052) {
+				/* special hack for Philips EUROPA Based boards:
+				 * keep the I2c bridge open for tuner access in analog mode
+				 */
+				tda1004x_disable_tuner_i2c(state);
+			}
 		}
 		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
 		break;
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 85b437b..bbebd1c 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -286,15 +286,10 @@
 	 *     although one packet has been transfered.
 	 */
 	if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) {
-		unsigned int i = 0, valid;
+		unsigned int i = 0;
 		while (pluto->dma_buf[i] == 0x47)
 			i += 188;
-		valid = i / 188;
-		if (nbpackets != valid) {
-			dev_err(&pluto->pdev->dev, "nbpackets=%u valid=%u\n",
-					nbpackets, valid);
-			nbpackets = valid;
-		}
+		nbpackets = i / 188;
 	}
 
 	dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets);
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 22b203f..87ea527 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -1566,7 +1566,7 @@
 	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
 	0x10, 0x3f,   // AGC2  0x3d
 	0x11, 0x84,
-	0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+	0x12, 0xb9,
 	0x15, 0xc9,   // lock detector threshold
 	0x16, 0x00,
 	0x17, 0x00,
@@ -1644,7 +1644,6 @@
 	.inittab = alps_bsru6_inittab,
 	.mclk = 88000000UL,
 	.invert = 1,
-	.enhanced_tuning = 0,
 	.skip_reinit = 0,
 	.lock_output = STV0229_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -1669,7 +1668,7 @@
 	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
 	0x10, 0x3f,   // AGC2  0x3d
 	0x11, 0x84,
-	0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+	0x12, 0xb9,
 	0x15, 0xc9,   // lock detector threshold
 	0x16, 0x00,
 	0x17, 0x00,
@@ -1721,7 +1720,6 @@
 	.inittab = alps_bsbe1_inittab,
 	.mclk = 88000000UL,
 	.invert = 1,
-	.enhanced_tuning = 0,
 	.skip_reinit = 0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = alps_bsru6_set_symbol_rate,
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 7692cd2..aa75dc0 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -499,7 +499,7 @@
 	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
 	0x10, 0x3f,		// AGC2  0x3d
 	0x11, 0x84,
-	0x12, 0xb5,		// Lock detect: -64  Carrier freq detect:on
+	0x12, 0xb9,
 	0x15, 0xc9,		// lock detector threshold
 	0x16, 0x00,
 	0x17, 0x00,
@@ -531,7 +531,6 @@
 	.inittab = typhoon_cinergy1200s_inittab,
 	.mclk = 88000000UL,
 	.invert = 0,
-	.enhanced_tuning = 0,
 	.skip_reinit = 0,
 	.lock_output = STV0229_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
@@ -546,7 +545,6 @@
 	.inittab = typhoon_cinergy1200s_inittab,
 	.mclk = 88000000UL,
 	.invert = 0,
-	.enhanced_tuning = 0,
 	.skip_reinit = 0,
 	.lock_output = STV0229_LOCKOUTPUT_0,
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 51c30ba..75fb92d 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -490,7 +490,7 @@
 	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
 	0x10, 0x3f,		// AGC2  0x3d
 	0x11, 0x84,
-	0x12, 0xb5,		// Lock detect: -64  Carrier freq detect:on
+	0x12, 0xb9,
 	0x15, 0xc9,		// lock detector threshold
 	0x16, 0x00,
 	0x17, 0x00,
@@ -580,7 +580,6 @@
 	.inittab = alps_bsru6_inittab,
 	.mclk = 88000000UL,
 	.invert = 1,
-	.enhanced_tuning = 0,
 	.skip_reinit = 0,
 	.lock_output = STV0229_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -710,7 +709,6 @@
 	.inittab = philips_su1278_tt_inittab,
 	.mclk = 64000000UL,
 	.invert = 0,
-	.enhanced_tuning = 1,
 	.skip_reinit = 1,
 	.lock_output = STV0229_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index b1f21ef..755df81 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -305,7 +305,7 @@
 	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
 	0x10, 0x3f,   // AGC2  0x3d
 	0x11, 0x84,
-	0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+	0x12, 0xb9,
 	0x15, 0xc9,   // lock detector threshold
 	0x16, 0x00,
 	0x17, 0x00,
@@ -379,7 +379,6 @@
 	.inittab = alps_bsru6_inittab,
 	.mclk = 88000000UL,
 	.invert = 1,
-	.enhanced_tuning = 0,
 	.skip_reinit = 0,
 	.lock_output = STV0229_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 43d6c82..4fd8bbc 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -226,12 +226,14 @@
 	return 0;
 }
 
-static void lnbp21_init(struct budget* budget)
+static int lnbp21_init(struct budget* budget)
 {
 	u8 buf = 0x00;
 	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
 
-	i2c_transfer (&budget->i2c_adap, &msg, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
 }
 
 static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -273,7 +275,7 @@
 	0x01, 0x15,
 	0x02, 0x00,
 	0x03, 0x00,
-        0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
 	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
 	0x06, 0x40,   /* DAC not used, set to high impendance mode */
 	0x07, 0x00,   /* DAC LSB */
@@ -284,7 +286,7 @@
 	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
 	0x10, 0x3f,   // AGC2  0x3d
 	0x11, 0x84,
-	0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+	0x12, 0xb9,
 	0x15, 0xc9,   // lock detector threshold
 	0x16, 0x00,
 	0x17, 0x00,
@@ -358,7 +360,6 @@
 	.inittab = alps_bsru6_inittab,
 	.mclk = 88000000UL,
 	.invert = 1,
-	.enhanced_tuning = 0,
 	.skip_reinit = 0,
 	.lock_output = STV0229_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -367,6 +368,79 @@
 	.pll_set = alps_bsru6_pll_set,
 };
 
+static u8 alps_bsbe1_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,  /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,  /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,  /* DAC not used, set to high impendance mode */
+	0x07, 0x00,  /* DAC LSB */
+	0x08, 0x40,  /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,  /* FIFO */
+	0x0c, 0x51,  /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,  /* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,  /* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,  // AGC2 0x3d
+	0x11, 0x84,
+	0x12, 0xb9,
+	0x15, 0xc9,  // lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+	0x29, 0x1e, // 1/2 threshold
+	0x2a, 0x14, // 2/3 threshold
+	0x2b, 0x0f, // 3/4 threshold
+	0x2c, 0x09, // 5/6 threshold
+	0x2d, 0x05, // 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f, // test all FECs
+	0x32, 0x19, // viterbi and synchro search
+	0x33, 0xfc, // rs control
+	0x34, 0x93, // error control
+	0x0f, 0x92, // 0x80 = inverse AGC
+	0xff, 0xff
+};
+
+static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+{
+	int ret;
+	u8 data[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000))
+		return -EINVAL;
+
+	div = (params->frequency + (125 - 1)) / 125; // round correctly
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+
+	ret = i2c_transfer(i2c, &msg, 1);
+	return (ret != 1) ? -EIO : 0;
+}
+
+static struct stv0299_config alps_bsbe1_config = {
+	.demod_address = 0x68,
+	.inittab = alps_bsbe1_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+	.pll_set = alps_bsbe1_pll_set,
+};
+
 static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -500,6 +574,19 @@
 static void frontend_init(struct budget *budget)
 {
 	switch(budget->dev->pci->subsystem_device) {
+	case 0x1017:
+		// try the ALPS BSBE1 now
+		budget->dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
+			budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+			if (lnbp21_init(budget)) {
+				printk("%s: No LNBP21 found!\n", __FUNCTION__);
+				goto error_out;
+			}
+		}
+
+		break;
 	case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
 	case 0x1013:
 		// try the ALPS BSRV2 first of all
@@ -554,7 +641,10 @@
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
 			budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-			lnbp21_init(budget);
+			if (lnbp21_init(budget)) {
+				printk("%s: No LNBP21 found!\n", __FUNCTION__);
+				goto error_out;
+			}
 			break;
 		}
 	}
@@ -566,13 +656,17 @@
 		       budget->dev->pci->subsystem_vendor,
 		       budget->dev->pci->subsystem_device);
 	} else {
-		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
-			printk("budget: Frontend registration failed!\n");
-			if (budget->dvb_frontend->ops->release)
-				budget->dvb_frontend->ops->release(budget->dvb_frontend);
-			budget->dvb_frontend = NULL;
-		}
+		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend))
+			goto error_out;
 	}
+	return;
+
+error_out:
+	printk("budget: Frontend registration failed!\n");
+	if (budget->dvb_frontend->ops->release)
+		budget->dvb_frontend->ops->release(budget->dvb_frontend);
+	budget->dvb_frontend = NULL;
+	return;
 }
 
 static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
@@ -618,6 +712,7 @@
 
 static struct saa7146_extension budget_extension;
 
+MAKE_BUDGET_INFO(ttbs2, "TT-Budget/WinTV-NOVA-S PCI (rev AL/alps bsbe1 lnbp21 frontend)", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbs,	"TT-Budget/WinTV-NOVA-S  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
@@ -630,6 +725,7 @@
 	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
 	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
 	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+	MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
 	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
 	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index d200ab0..fd53d60 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1198,7 +1198,7 @@
         0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
         0x10, 0x3f,             // AGC2  0x3d
         0x11, 0x84,
-        0x12, 0xb5,             // Lock detect: -64  Carrier freq detect:on
+        0x12, 0xb9,
         0x15, 0xc9,             // lock detector threshold
         0x16, 0x00,
         0x17, 0x00,
@@ -1240,7 +1240,7 @@
 	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
 	0x10, 0x3f,		// AGC2  0x3d
 	0x11, 0x84,
-	0x12, 0xb5,		// Lock detect: -64  Carrier freq detect:on
+	0x12, 0xb9,
 	0x15, 0xc9,		// lock detector threshold
 	0x16, 0x00,
 	0x17, 0x00,
@@ -1335,7 +1335,6 @@
 	.inittab = alps_bsru6_inittab,
 	.mclk = 88000000UL,
 	.invert = 1,
-	.enhanced_tuning = 0,
 	.skip_reinit = 0,
 	.lock_output = STV0229_LOCKOUTPUT_1,
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index bbb989d..199b011 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -25,6 +25,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called bttv.
 
+config VIDEO_BT848_DVB
+	tristate "DVB/ATSC Support for bt878 based TV cards"
+	depends on VIDEO_BT848 && DVB_CORE
+	select DVB_BT8XX
+	---help---
+	  This adds support for DVB/ATSC cards based on the BT878 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dvb-bt8xx.
+
 config VIDEO_SAA6588
 	tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards"
 	depends on VIDEO_DEV && I2C && VIDEO_BT848
@@ -243,29 +253,7 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called meye.
 
-config VIDEO_SAA7134
-	tristate "Philips SAA7134 support"
-	depends on VIDEO_DEV && PCI && I2C && SOUND
-	select VIDEO_BUF
-	select VIDEO_IR
-	select VIDEO_TUNER
-	select CRC32
-	---help---
-	  This is a video4linux driver for Philips SAA7130/7134 based
-	  TV cards.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called saa7134.
-
-config VIDEO_SAA7134_DVB
-	tristate "DVB Support for saa7134 based TV cards"
-	depends on VIDEO_SAA7134 && DVB_CORE
-	select VIDEO_BUF_DVB
-	select DVB_MT352
-	select DVB_TDA1004X
-	---help---
-	  This adds support for DVB cards based on the
-	  Philips saa7134 chip.
+source "drivers/media/video/saa7134/Kconfig"
 
 config VIDEO_MXB
 	tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
@@ -316,34 +304,9 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called hexium_gemini.
 
-config VIDEO_CX88
-	tristate "Conexant 2388x (bt878 successor) support"
-	depends on VIDEO_DEV && PCI && I2C && EXPERIMENTAL
-	select I2C_ALGOBIT
-	select FW_LOADER
-	select VIDEO_BTCX
-	select VIDEO_BUF
-	select VIDEO_TUNER
-	select VIDEO_TVEEPROM
-	select VIDEO_IR
-	---help---
-	  This is a video4linux driver for Conexant 2388x based
-	  TV cards.
+source "drivers/media/video/cx88/Kconfig"
 
-	  To compile this driver as a module, choose M here: the
-	  module will be called cx8800
-
-config VIDEO_CX88_DVB
-	tristate "DVB Support for cx2388x based TV cards"
-	depends on VIDEO_CX88 && DVB_CORE
-	select VIDEO_BUF_DVB
-	select DVB_MT352
-	select DVB_OR51132
-	select DVB_CX22702
-	select DVB_LGDT330X
-	---help---
-	  This adds support for DVB/ATSC cards based on the
-	  Connexant 2388x chip.
+source "drivers/media/video/em28xx/Kconfig"
 
 config VIDEO_OVCAMCHIP
 	tristate "OmniVision Camera Chip support"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 046b82d..3ac4659 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -5,7 +5,6 @@
 bttv-objs	:=	bttv-driver.o bttv-cards.o bttv-if.o \
 			bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o
 zoran-objs      :=	zr36120.o zr36120_i2c.o zr36120_mem.o
-rds-objs        :=	saa6588.o
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
 tuner-objs	:=	tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
@@ -16,7 +15,7 @@
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
-obj-$(CONFIG_VIDEO_SAA6588) += rds.o
+obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
 obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
 obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
@@ -39,6 +38,8 @@
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 0823dda..881cdcb 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -22,7 +22,6 @@
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c
index 76c1b63..e406395 100644
--- a/drivers/media/video/bt832.c
+++ b/drivers/media/video/bt832.c
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 
 #include <media/audiochip.h>
-#include <media/id.h>
 #include "bttv.h"
 #include "bt832.h"
 
@@ -54,36 +53,36 @@
 static struct i2c_client client_template;
 
 struct bt832 {
-        struct i2c_client client;
+	struct i2c_client client;
 };
 
 int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
 {
 	int i,rc;
 	buf[0]=0x80; // start at register 0 with auto-increment
-        if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
-                printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
+	if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
+		printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
 
-        for(i=0;i<65;i++)
-                buf[i]=0;
-        if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
-                printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
+	for(i=0;i<65;i++)
+		buf[i]=0;
+	if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
+		printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
 
-        // Note: On READ the first byte is the current index
-        //  (e.g. 0x80, what we just wrote)
+	// Note: On READ the first byte is the current index
+	//  (e.g. 0x80, what we just wrote)
 
-        if(1) {
-                int i;
-                printk("BT832 hexdump:\n");
-                for(i=1;i<65;i++) {
+	if(1) {
+		int i;
+		printk("BT832 hexdump:\n");
+		for(i=1;i<65;i++) {
 			if(i!=1) {
 			  if(((i-1)%8)==0) printk(" ");
-                          if(((i-1)%16)==0) printk("\n");
+			  if(((i-1)%16)==0) printk("\n");
 			}
-                        printk(" %02x",buf[i]);
-                }
-                printk("\n");
-        }
+			printk(" %02x",buf[i]);
+		}
+		printk("\n");
+	}
 	return 0;
 }
 
@@ -102,13 +101,13 @@
 		return 0;
 	}
 
-        printk("Write 0 tp VPSTATUS\n");
-        buf[0]=BT832_VP_STATUS; // Reg.52
-        buf[1]= 0x00;
-        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+	printk("Write 0 tp VPSTATUS\n");
+	buf[0]=BT832_VP_STATUS; // Reg.52
+	buf[1]= 0x00;
+	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+		printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
 
-        bt832_hexdump(i2c_client_s,buf);
+	bt832_hexdump(i2c_client_s,buf);
 
 
 	// Leave low power mode:
@@ -116,17 +115,17 @@
 	buf[0]=BT832_CAM_SETUP0; //0x39 57
 	buf[1]=0x08;
 	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+		printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
 
-        bt832_hexdump(i2c_client_s,buf);
+	bt832_hexdump(i2c_client_s,buf);
 
 	printk("Write 0 tp VPSTATUS\n");
-        buf[0]=BT832_VP_STATUS; // Reg.52
-        buf[1]= 0x00;
-        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+	buf[0]=BT832_VP_STATUS; // Reg.52
+	buf[1]= 0x00;
+	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+		printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
 
-        bt832_hexdump(i2c_client_s,buf);
+	bt832_hexdump(i2c_client_s,buf);
 
 
 	// Enable Output
@@ -134,22 +133,22 @@
 	buf[0]=BT832_VP_CONTROL1; // Reg.40
 	buf[1]= 0x27 & (~0x01); // Default | !skip
 	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
+		printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
 
-        bt832_hexdump(i2c_client_s,buf);
+	bt832_hexdump(i2c_client_s,buf);
 
 
 	// for testing (even works when no camera attached)
 	printk("bt832: *** Generate NTSC M Bars *****\n");
 	buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
 	buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
-        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+		printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
 
 	printk("Bt832: Camera Present: %s\n",
 		(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
 
-        bt832_hexdump(i2c_client_s,buf);
+	bt832_hexdump(i2c_client_s,buf);
 	kfree(buf);
 	return 1;
 }
@@ -162,17 +161,17 @@
 
 	printk("bt832_attach\n");
 
-        client_template.adapter = adap;
-        client_template.addr    = addr;
+	client_template.adapter = adap;
+	client_template.addr    = addr;
 
-        printk("bt832: chip found @ 0x%x\n", addr<<1);
+	printk("bt832: chip found @ 0x%x\n", addr<<1);
 
-        if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
-                return -ENOMEM;
+	if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+		return -ENOMEM;
 	memset(t,0,sizeof(*t));
 	t->client = client_template;
-        i2c_set_clientdata(&t->client, t);
-        i2c_attach_client(&t->client);
+	i2c_set_clientdata(&t->client, t);
+	i2c_attach_client(&t->client);
 
 	if(! bt832_init(&t->client)) {
 		bt832_detach(&t->client);
@@ -211,7 +210,7 @@
 
 	printk("bt832: command %x\n",cmd);
 
-        switch (cmd) {
+	switch (cmd) {
 		case BT832_HEXDUMP: {
 			unsigned char *buf;
 			buf=kmalloc(65,GFP_KERNEL);
diff --git a/drivers/media/video/bt832.h b/drivers/media/video/bt832.h
index 9b6a8d2..1ce8fa71f 100644
--- a/drivers/media/video/bt832.h
+++ b/drivers/media/video/bt832.h
@@ -233,8 +233,8 @@
 /* from web:
  Video Sampling
 Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
-                  Pixel Clock   Horiz    Horiz    Vert
-                   Rate         Total    Active
+		  Pixel Clock   Horiz    Horiz    Vert
+		   Rate         Total    Active
 NTSC square pixel  12.27 MHz    780      640      525
 NTSC CCIR-601      13.5  MHz    858      720      525
 NTSC 4FSc          14.32 MHz    910      768      525
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 0881a17..3413bac 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -6,7 +6,7 @@
     like the big tvcards array for the most part
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
 
     This program is free software; you can redistribute it and/or modify
@@ -145,162 +145,163 @@
 	int cardnr;
 	char *name;
 } cards[] __devinitdata = {
-	{ 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
-	{ 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
-	{ 0x45000070, BTTV_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
-	{ 0xff000070, BTTV_OSPREY1x0,     "Osprey-100" },
-	{ 0xff010070, BTTV_OSPREY2x0_SVID,"Osprey-200" },
-	{ 0xff020070, BTTV_OSPREY500,     "Osprey-500" },
-	{ 0xff030070, BTTV_OSPREY2000,    "Osprey-2000" },
-	{ 0xff040070, BTTV_OSPREY540,     "Osprey-540" },
+	{ 0x13eb0070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV" },
+	{ 0x39000070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV-D" },
+	{ 0x45000070, BTTV_BOARD_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
+	{ 0xff000070, BTTV_BOARD_OSPREY1x0,     "Osprey-100" },
+	{ 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" },
+	{ 0xff020070, BTTV_BOARD_OSPREY500,     "Osprey-500" },
+	{ 0xff030070, BTTV_BOARD_OSPREY2000,    "Osprey-2000" },
+	{ 0xff040070, BTTV_BOARD_OSPREY540,     "Osprey-540" },
+	{ 0xff070070, BTTV_BOARD_OSPREY440,     "Osprey-440" },
 
-	{ 0x00011002, BTTV_ATI_TVWONDER,  "ATI TV Wonder" },
-	{ 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
+	{ 0x00011002, BTTV_BOARD_ATI_TVWONDER,  "ATI TV Wonder" },
+	{ 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
 
-	{ 0x6606107d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-	{ 0x6607107d, BTTV_WINFASTVC100,  "Leadtek WinFast VC 100" },
-	{ 0x6609107d, BTTV_WINFAST2000,   "Leadtek TV 2000 XP" },
-	{ 0x263610b4, BTTV_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
-	{ 0x264510b4, BTTV_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
- 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
-	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
-	{ 0x407010fc, BTTV_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
- 	{ 0xd01810fc, BTTV_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
+	{ 0x6606107d, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x6607107d, BTTV_BOARD_WINFASTVC100,  "Leadtek WinFast VC 100" },
+	{ 0x6609107d, BTTV_BOARD_WINFAST2000,   "Leadtek TV 2000 XP" },
+	{ 0x263610b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
+	{ 0x264510b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
+	{ 0x402010fc, BTTV_BOARD_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
+	{ 0x405010fc, BTTV_BOARD_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
+	{ 0x407010fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
+	{ 0xd01810fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
 
-	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
+	{ 0x001211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
 	/* some cards ship with byteswapped IDs ... */
-	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV [bswap]" },
-	{ 0xff00bd11, BTTV_PINNACLE,      "Pinnacle PCTV [bswap]" },
+	{ 0x1200bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
+	{ 0xff00bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
 	/* this seems to happen as well ... */
-	{ 0xff1211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
+	{ 0xff1211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
 
-	{ 0x3000121a, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
-	{ 0x263710b4, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
-	{ 0x3060121a, BTTV_STB2,	  "3Dfx VoodooTV 100/ STB OEM" },
+	{ 0x3000121a, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+	{ 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+	{ 0x3060121a, BTTV_BOARD_STB2,	  "3Dfx VoodooTV 100/ STB OEM" },
 
-	{ 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
-	{ 0xa005144f, BTTV_MAGICTVIEW063, "CPH06X TView99-Card" },
-	{ 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
-	{ 0x3005144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
-	{ 0x5000144f, BTTV_MAGICTVIEW061, "Askey CPH050" },
-	{ 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
-	{ 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master (CPH060)" },
+	{ 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
+	{ 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" },
+	{ 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
+	{ 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
+	{ 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" },
+	{ 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" },
+	{ 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS,  "Phoebe TV Master (CPH060)" },
 
-	{ 0x00011461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
-	{ 0x00021461, BTTV_AVERMEDIA98,   "AVermedia TVCapture 98" },
-	{ 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
-	{ 0x00041461, BTTV_AVERMEDIA98,   "AVerMedia TVCapture 98" },
-	{ 0x03001461, BTTV_AVERMEDIA98,   "VDOMATE TV TUNER CARD" },
+	{ 0x00011461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
+	{ 0x00021461, BTTV_BOARD_AVERMEDIA98,   "AVermedia TVCapture 98" },
+	{ 0x00031461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
+	{ 0x00041461, BTTV_BOARD_AVERMEDIA98,   "AVerMedia TVCapture 98" },
+	{ 0x03001461, BTTV_BOARD_AVERMEDIA98,   "VDOMATE TV TUNER CARD" },
 
-	{ 0x1117153b, BTTV_TERRATVALUE,   "Terratec TValue (Philips PAL B/G)" },
-	{ 0x1118153b, BTTV_TERRATVALUE,   "Terratec TValue (Temic PAL B/G)" },
-	{ 0x1119153b, BTTV_TERRATVALUE,   "Terratec TValue (Philips PAL I)" },
-	{ 0x111a153b, BTTV_TERRATVALUE,   "Terratec TValue (Temic PAL I)" },
+	{ 0x1117153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL B/G)" },
+	{ 0x1118153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL B/G)" },
+	{ 0x1119153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL I)" },
+	{ 0x111a153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL I)" },
 
-	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV Radio+" },
-	{ 0x1127153b, BTTV_TERRATV,       "Terratec TV+ (V1.05)"    },
+	{ 0x1123153b, BTTV_BOARD_TERRATVRADIO,  "Terratec TV Radio+" },
+	{ 0x1127153b, BTTV_BOARD_TERRATV,       "Terratec TV+ (V1.05)"    },
 	/* clashes with FlyVideo
-	 *{ 0x18521852, BTTV_TERRATV,     "Terratec TV+ (V1.10)"    }, */
-	{ 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue (LR102)" },
-	{ 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" }, /* LR102 */
-	{ 0x5018153b, BTTV_TERRATVALUE,   "Terratec TValue" },       /* ?? */
-	{ 0xff3b153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" }, /* ?? */
+	 *{ 0x18521852, BTTV_BOARD_TERRATV,     "Terratec TV+ (V1.10)"    }, */
+	{ 0x1134153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (LR102)" },
+	{ 0x1135153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* LR102 */
+	{ 0x5018153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue" },       /* ?? */
+	{ 0xff3b153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* ?? */
 
-	{ 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
-	{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
-	{ 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-	{ 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-	{ 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+	{ 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+	{ 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+	{ 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+	{ 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+	{ 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 
-	{ 0x1430aa00, BTTV_PV143,         "Provideo PV143A" },
-	{ 0x1431aa00, BTTV_PV143,         "Provideo PV143B" },
-	{ 0x1432aa00, BTTV_PV143,         "Provideo PV143C" },
-	{ 0x1433aa00, BTTV_PV143,         "Provideo PV143D" },
-	{ 0x1433aa03, BTTV_PV143,         "Security Eyes" },
+	{ 0x1430aa00, BTTV_BOARD_PV143,         "Provideo PV143A" },
+	{ 0x1431aa00, BTTV_BOARD_PV143,         "Provideo PV143B" },
+	{ 0x1432aa00, BTTV_BOARD_PV143,         "Provideo PV143C" },
+	{ 0x1433aa00, BTTV_BOARD_PV143,         "Provideo PV143D" },
+	{ 0x1433aa03, BTTV_BOARD_PV143,         "Security Eyes" },
 
-	{ 0x1460aa00, BTTV_PV150,         "Provideo PV150A-1" },
-	{ 0x1461aa01, BTTV_PV150,         "Provideo PV150A-2" },
-	{ 0x1462aa02, BTTV_PV150,         "Provideo PV150A-3" },
-	{ 0x1463aa03, BTTV_PV150,         "Provideo PV150A-4" },
+	{ 0x1460aa00, BTTV_BOARD_PV150,         "Provideo PV150A-1" },
+	{ 0x1461aa01, BTTV_BOARD_PV150,         "Provideo PV150A-2" },
+	{ 0x1462aa02, BTTV_BOARD_PV150,         "Provideo PV150A-3" },
+	{ 0x1463aa03, BTTV_BOARD_PV150,         "Provideo PV150A-4" },
 
-	{ 0x1464aa04, BTTV_PV150,         "Provideo PV150B-1" },
-	{ 0x1465aa05, BTTV_PV150,         "Provideo PV150B-2" },
-	{ 0x1466aa06, BTTV_PV150,         "Provideo PV150B-3" },
-	{ 0x1467aa07, BTTV_PV150,         "Provideo PV150B-4" },
+	{ 0x1464aa04, BTTV_BOARD_PV150,         "Provideo PV150B-1" },
+	{ 0x1465aa05, BTTV_BOARD_PV150,         "Provideo PV150B-2" },
+	{ 0x1466aa06, BTTV_BOARD_PV150,         "Provideo PV150B-3" },
+	{ 0x1467aa07, BTTV_BOARD_PV150,         "Provideo PV150B-4" },
 
-	{ 0xa132ff00, BTTV_IVC100,        "IVC-100"  },
-	{ 0xa1550000, BTTV_IVC200,        "IVC-200"  },
-	{ 0xa1550001, BTTV_IVC200,        "IVC-200"  },
-	{ 0xa1550002, BTTV_IVC200,        "IVC-200"  },
-	{ 0xa1550003, BTTV_IVC200,        "IVC-200"  },
-	{ 0xa1550100, BTTV_IVC200,        "IVC-200G" },
-	{ 0xa1550101, BTTV_IVC200,        "IVC-200G" },
-	{ 0xa1550102, BTTV_IVC200,        "IVC-200G" },
-	{ 0xa1550103, BTTV_IVC200,        "IVC-200G" },
-	{ 0xa182ff00, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff01, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff02, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff03, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff04, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff05, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff06, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff07, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff08, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff09, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff0a, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff0b, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff0c, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff0d, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff0e, BTTV_IVC120,        "IVC-120G" },
-	{ 0xa182ff0f, BTTV_IVC120,        "IVC-120G" },
+	{ 0xa132ff00, BTTV_BOARD_IVC100,        "IVC-100"  },
+	{ 0xa1550000, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550001, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550002, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550003, BTTV_BOARD_IVC200,        "IVC-200"  },
+	{ 0xa1550100, BTTV_BOARD_IVC200,        "IVC-200G" },
+	{ 0xa1550101, BTTV_BOARD_IVC200,        "IVC-200G" },
+	{ 0xa1550102, BTTV_BOARD_IVC200,        "IVC-200G" },
+	{ 0xa1550103, BTTV_BOARD_IVC200,        "IVC-200G" },
+	{ 0xa182ff00, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff01, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff02, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff03, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff04, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff05, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff06, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff07, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff08, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff09, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0a, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0b, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0c, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0d, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0e, BTTV_BOARD_IVC120,        "IVC-120G" },
+	{ 0xa182ff0f, BTTV_BOARD_IVC120,        "IVC-120G" },
 
-	{ 0x41424344, BTTV_GRANDTEC,      "GrandTec Multi Capture" },
-	{ 0x01020304, BTTV_XGUARD,        "Grandtec Grand X-Guard" },
+	{ 0x41424344, BTTV_BOARD_GRANDTEC,      "GrandTec Multi Capture" },
+	{ 0x01020304, BTTV_BOARD_XGUARD,        "Grandtec Grand X-Guard" },
 
-	{ 0x18501851, BTTV_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
-	{ 0xa0501851, BTTV_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
-	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
-	{ 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
-	{ 0x41a0a051, BTTV_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
-	{ 0x18501f7f, BTTV_FLYVIDEO_98,   "Lifeview Flyvideo 98" },
+	{ 0x18501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+	{ 0xa0501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+	{ 0x18511851, BTTV_BOARD_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
+	{ 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
+	{ 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
+	{ 0x18501f7f, BTTV_BOARD_FLYVIDEO_98,   "Lifeview Flyvideo 98" },
 
-    	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
-	{ 0x010114c7, BTTV_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
+    	{ 0x010115cb, BTTV_BOARD_GMV1,          "AG GMV1" },
+	{ 0x010114c7, BTTV_BOARD_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
 
-	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
-	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-	{ 0xfff6f6ff, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-	{ 0x03116000, BTTV_SENSORAY311,   "Sensoray 311" },
-	{ 0x00790e11, BTTV_WINDVR,        "Canopus WinDVR PCI" },
-	{ 0xa0fca1a0, BTTV_ZOLTRIX,       "Face to Face Tvmax" },
-	{ 0x20007063, BTTV_PC_HDTV,       "pcHDTV HD-2000 TV"},
-	{ 0x82b2aa6a, BTTV_SIMUS_GVC1100, "SIMUS GVC1100" },
-	{ 0x146caa0c, BTTV_PV951,         "ituner spectra8" },
- 	{ 0x200a1295, BTTV_PXC200,        "ImageNation PXC200A" },
+	{ 0x10b42636, BTTV_BOARD_HAUPPAUGE878,  "STB ???" },
+	{ 0x217d6606, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0xfff6f6ff, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x03116000, BTTV_BOARD_SENSORAY311,   "Sensoray 311" },
+	{ 0x00790e11, BTTV_BOARD_WINDVR,        "Canopus WinDVR PCI" },
+	{ 0xa0fca1a0, BTTV_BOARD_ZOLTRIX,       "Face to Face Tvmax" },
+	{ 0x20007063, BTTV_BOARD_PC_HDTV,       "pcHDTV HD-2000 TV"},
+	{ 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
+	{ 0x146caa0c, BTTV_BOARD_PV951,         "ituner spectra8" },
+	{ 0x200a1295, BTTV_BOARD_PXC200,        "ImageNation PXC200A" },
 
-	{ 0x40111554, BTTV_PV_BT878P_9B,  "Prolink Pixelview PV-BT" },
-	{ 0x17de0a01, BTTV_KWORLD,        "Mecer TV/FM/Video Tuner" },
+	{ 0x40111554, BTTV_BOARD_PV_BT878P_9B,  "Prolink Pixelview PV-BT" },
+	{ 0x17de0a01, BTTV_BOARD_KWORLD,        "Mecer TV/FM/Video Tuner" },
 
-	{ 0x01051805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
-	{ 0x01061805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
-	{ 0x01071805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
-	{ 0x01081805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
+	{ 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
+	{ 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
+	{ 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
+	{ 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
 
-	{ 0x15409511, BTTV_ACORP_Y878F, "Acorp Y878F" },
+	{ 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" },
 
 	/* likely broken, vendor id doesn't match the other magic views ...
-	 * { 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
+	 * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
 
 	/* DVB cards (using pci function .1 for mpeg data xfer) */
-	{ 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
-	{ 0x07611461, BTTV_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
-	{ 0x001c11bd, BTTV_PINNACLESAT,   "Pinnacle PCTV Sat" },
-	{ 0x002611bd, BTTV_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
-	{ 0x00011822, BTTV_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
-	{ 0xfc00270f, BTTV_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
-	{ 0x07711461, BTTV_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
-	{ 0xdb1018ac, BTTV_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
-	{ 0xd50018ac, BTTV_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
+	{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+	{ 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
+	{ 0x001c11bd, BTTV_BOARD_PINNACLESAT,   "Pinnacle PCTV Sat" },
+	{ 0x002611bd, BTTV_BOARD_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
+	{ 0x00011822, BTTV_BOARD_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
+	{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
+	{ 0x07711461, BTTV_BOARD_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
+	{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
+	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
 
 	{ 0, -1, NULL }
 };
@@ -309,2116 +310,2494 @@
 /* array with description for bt848 / bt878 tv/grabber cards               */
 
 struct tvcard bttv_tvcards[] = {
-{
-/* ---- card 0x00 ---------------------------------- */
-	.name		= " *** UNKNOWN/GENERIC *** ",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.muxsel		= { 2, 3, 1, 0},
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "MIRO PCTV",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 15,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 2, 0, 0, 0, 10},
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Hauppauge (bt848)",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 7,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 1, 2, 3, 4},
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "STB, Gateway P/N 6000699 (bt848)",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 7,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 4, 0, 2, 3, 1},
-	.no_msp34xx	= 1,
-	.needs_tvaudio	= 1,
-	.tuner_type     = TUNER_PHILIPS_NTSC,
-	.tuner_addr	= ADDR_UNSET,
-	.pll            = PLL_28,
-	.has_radio      = 1,
-},{
+	/* ---- card 0x00 ---------------------------------- */
+	[BTTV_BOARD_UNKNOWN] = {
+		.name		= " *** UNKNOWN/GENERIC *** ",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.muxsel		= { 2, 3, 1, 0},
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_MIRO] = {
+		.name		= "MIRO PCTV",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 2, 0, 0, 0, 10},
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_HAUPPAUGE] = {
+		.name		= "Hauppauge (bt848)",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 7,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 1, 2, 3, 4},
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_STB] = {
+		.name		= "STB, Gateway P/N 6000699 (bt848)",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 7,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 4, 0, 2, 3, 1},
+		.no_msp34xx	= 1,
+		.needs_tvaudio	= 1,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+		.has_radio      = 1,
+	},
 
-/* ---- card 0x04 ---------------------------------- */
-	.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
-	.video_inputs	= 4,
-	.audio_inputs	= 0,
-	.tuner		= -1,
-	.svhs		= 2,
-	.gpiomask	= 0,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0 },
-	.needs_tvaudio	= 0,
-	.tuner_type	= 4,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Diamond DTV2000",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 3,
-	.muxsel		= { 2, 3, 1, 0},
-	.audiomux	= { 0, 1, 0, 1, 3},
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "AVerMedia TVPhone",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 3,
-	.muxsel		= { 2, 3, 1, 1},
-	.gpiomask	= 0x0f,
-	.audiomux	= { 0x0c, 0x04, 0x08, 0x04, 0},
-	/*                0x04 for some cards ?? */
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook	= avermedia_tvphone_audio,
-	.has_remote     = 1,
-},{
-	.name		= "MATRIX-Vision MV-Delta",
-	.video_inputs	= 5,
-	.audio_inputs	= 1,
-	.tuner		= -1,
-	.svhs		= 3,
-	.gpiomask	= 0,
-	.muxsel		= { 2, 3, 1, 0, 0},
-	.audiomux	= {0 },
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
+	/* ---- card 0x04 ---------------------------------- */
+	[BTTV_BOARD_INTEL] = {
+		.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
+		.video_inputs	= 4,
+		.audio_inputs	= 0,
+		.tuner		= -1,
+		.svhs		= 2,
+		.gpiomask	= 0,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0 },
+		.needs_tvaudio	= 0,
+		.tuner_type	= 4,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_DIAMOND] = {
+		.name		= "Diamond DTV2000",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 3,
+		.muxsel		= { 2, 3, 1, 0},
+		.audiomux	= { 0, 1, 0, 1, 3},
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_AVERMEDIA] = {
+		.name		= "AVerMedia TVPhone",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 3,
+		.muxsel		= { 2, 3, 1, 1},
+		.gpiomask	= 0x0f,
+		.audiomux	= { 0x0c, 0x04, 0x08, 0x04, 0},
+		/*                0x04 for some cards ?? */
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook	= avermedia_tvphone_audio,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_MATRIX_VISION] = {
+		.name		= "MATRIX-Vision MV-Delta",
+		.video_inputs	= 5,
+		.audio_inputs	= 1,
+		.tuner		= -1,
+		.svhs		= 3,
+		.gpiomask	= 0,
+		.muxsel		= { 2, 3, 1, 0, 0},
+		.audiomux	= {0 },
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-/* ---- card 0x08 ---------------------------------- */
-	.name		= "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0xc00,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "IMS/IXmicro TurboTV",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 3,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 1, 1, 2, 3, 0},
-	.needs_tvaudio	= 0,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_TEMIC_PAL,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Hauppauge (bt878)",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x0f, /* old: 7 */
-	.muxsel		= { 2, 0, 1, 1},
-	.audiomux	= { 0, 1, 2, 3, 4},
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "MIRO PCTV pro",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x3014f,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0x20001,0x10001, 0, 0,10},
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
+	/* ---- card 0x08 ---------------------------------- */
+	[BTTV_BOARD_FLYVIDEO] = {
+		.name		= "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0xc00,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_TURBOTV] = {
+		.name		= "IMS/IXmicro TurboTV",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 3,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 1, 1, 2, 3, 0},
+		.needs_tvaudio	= 0,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TEMIC_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_HAUPPAUGE878] = {
+		.name		= "Hauppauge (bt878)",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x0f, /* old: 7 */
+		.muxsel		= { 2, 0, 1, 1},
+		.audiomux	= { 0, 1, 2, 3, 4},
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_MIROPRO] = {
+		.name		= "MIRO PCTV pro",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x3014f,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0x20001,0x10001, 0, 0,10},
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-/* ---- card 0x0c ---------------------------------- */
-	.name		= "ADS Technologies Channel Surfer TV (bt848)",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 15,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 13, 14, 11, 7, 0, 0},
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "AVerMedia TVCapture 98",
-	.video_inputs	= 3,
-	.audio_inputs	= 4,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 15,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 13, 14, 11, 7, 0, 0},
-	.needs_tvaudio	= 1,
-	.msp34xx_alt    = 1,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook     = avermedia_tv_stereo_audio,
-},{
-	.name		= "Aimslab Video Highway Xtreme (VHX)",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 7,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Zoltrix TV-Max",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 15,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= {0 , 0, 1 , 0, 10},
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
+	/* ---- card 0x0c ---------------------------------- */
+	[BTTV_BOARD_ADSTECH_TV] = {
+		.name		= "ADS Technologies Channel Surfer TV (bt848)",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 13, 14, 11, 7, 0, 0},
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_AVERMEDIA98] = {
+		.name		= "AVerMedia TVCapture 98",
+		.video_inputs	= 3,
+		.audio_inputs	= 4,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 13, 14, 11, 7, 0, 0},
+		.needs_tvaudio	= 1,
+		.msp34xx_alt    = 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook     = avermedia_tv_stereo_audio,
+		.no_gpioirq     = 1,
+	},
+	[BTTV_BOARD_VHX] = {
+		.name		= "Aimslab Video Highway Xtreme (VHX)",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 7,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_ZOLTRIX] = {
+		.name		= "Zoltrix TV-Max",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= {0 , 0, 1 , 0, 10},
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-/* ---- card 0x10 ---------------------------------- */
-	.name		= "Prolink Pixelview PlayTV (bt878)",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x01fe00,
-	.muxsel		= { 2, 3, 1, 1},
-	/* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
-	.audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-},{
-	.name		= "Leadtek WinView 601",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x8300f8,
-	.muxsel		= { 2, 3, 1, 1,0},
-	.audiomux	= { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook	= winview_audio,
-	.has_radio	= 1,
-},{
-	.name		= "AVEC Intercapture",
-	.video_inputs	= 3,
-	.audio_inputs	= 2,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0,
-	.muxsel		= {2, 3, 1, 1},
-	.audiomux	= {1, 0, 0, 0, 0},
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= -1,
-	.svhs		= -1,
-	.gpiomask	= 0x8dff00,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0 },
-	.no_msp34xx	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
+	/* ---- card 0x10 ---------------------------------- */
+	[BTTV_BOARD_PIXVIEWPLAYTV] = {
+		.name		= "Prolink Pixelview PlayTV (bt878)",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x01fe00,
+		.muxsel		= { 2, 3, 1, 1},
+	#if 0
+		/* old */
+		.audiomux	= { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
+	#else
+		/* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
+		.audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
+	#endif
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+	},
+	[BTTV_BOARD_WINVIEW_601] = {
+		.name		= "Leadtek WinView 601",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x8300f8,
+		.muxsel		= { 2, 3, 1, 1,0},
+		.audiomux	= { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook	= winview_audio,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_AVEC_INTERCAP] = {
+		.name		= "AVEC Intercapture",
+		.video_inputs	= 3,
+		.audio_inputs	= 2,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0,
+		.muxsel		= {2, 3, 1, 1},
+		.audiomux	= {1, 0, 0, 0, 0},
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_LIFE_FLYKIT] = {
+		.name		= "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= -1,
+		.svhs		= -1,
+		.gpiomask	= 0x8dff00,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0 },
+		.no_msp34xx	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-/* ---- card 0x14 ---------------------------------- */
-	.name		= "CEI Raffles Card",
-	.video_inputs	= 3,
-	.audio_inputs	= 3,
-	.tuner		= 0,
-	.svhs		= 2,
-	.muxsel		= {2, 3, 1, 1},
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
-	.video_inputs	= 4,
-	.audio_inputs	= 2,  /* tuner, line in */
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x1800,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800},
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_PHILIPS_PAL_I,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Askey CPH050/ Phoebe Tv Master + FM",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0xc00,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= {0, 1, 0x800, 0x400, 0xc00, 0},
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= -1,
-	.gpiomask	= 7,
-	.muxsel		= { 2, 3, -1 },
-	.digital_mode   = DIGITAL_MODE_CAMERA,
-	.audiomux	= { 0, 0, 0, 0, 0 },
-	.no_msp34xx	= 1,
-	.pll            = PLL_28,
-	.tuner_type     = TUNER_ALPS_TSBB5_PAL_I,
-	.tuner_addr	= ADDR_UNSET,
-},{
+	/* ---- card 0x14 ---------------------------------- */
+	[BTTV_BOARD_CEI_RAFFLES] = {
+		.name		= "CEI Raffles Card",
+		.video_inputs	= 3,
+		.audio_inputs	= 3,
+		.tuner		= 0,
+		.svhs		= 2,
+		.muxsel		= {2, 3, 1, 1},
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_CONFERENCETV] = {
+		.name		= "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+		.video_inputs	= 4,
+		.audio_inputs	= 2,  /* tuner, line in */
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x1800,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800},
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_PHOEBE_TVMAS] = {
+		.name		= "Askey CPH050/ Phoebe Tv Master + FM",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0xc00,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= {0, 1, 0x800, 0x400, 0xc00, 0},
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_MODTEC_205] = {
+		.name		= "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= -1,
+		.gpiomask	= 7,
+		.muxsel		= { 2, 3, -1 },
+		.digital_mode   = DIGITAL_MODE_CAMERA,
+		.audiomux	= { 0, 0, 0, 0, 0 },
+		.no_msp34xx	= 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_ALPS_TSBB5_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-/* ---- card 0x18 ---------------------------------- */
-	.name		= "Askey CPH05X/06X (bt878) [many vendors]",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0xe00,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= {0x400, 0x400, 0x400, 0x400, 0xc00},
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-	.has_remote     = 1,
-},{
-	.name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask       = 0x1f0fff,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux       = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
-	.needs_tvaudio	= 0,
-	.tuner_type	= TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook     = terratv_audio,
-},{
-	.name		= "Hauppauge WinCam newer (bt878)",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 3,
-	.gpiomask	= 7,
-	.muxsel		= { 2, 0, 1, 1},
-	.audiomux	= { 0, 1, 2, 3, 4},
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
-	.video_inputs	= 4,
-	.audio_inputs	= 2,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x1800,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800},
-	.pll            = PLL_28,
-	.tuner_type	= TUNER_PHILIPS_SECAM,
-	.tuner_addr	= ADDR_UNSET,
-},{
+	/* ---- card 0x18 ---------------------------------- */
+	[BTTV_BOARD_MAGICTVIEW061] = {
+		.name		= "Askey CPH05X/06X (bt878) [many vendors]",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0xe00,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= {0x400, 0x400, 0x400, 0x400, 0xc00},
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_VOBIS_BOOSTAR] = {
+		.name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask       = 0x1f0fff,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux       = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
+		.needs_tvaudio	= 0,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook     = terratv_audio,
+	},
+	[BTTV_BOARD_HAUPPAUG_WCAM] = {
+		.name		= "Hauppauge WinCam newer (bt878)",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 3,
+		.gpiomask	= 7,
+		.muxsel		= { 2, 0, 1, 1},
+		.audiomux	= { 0, 1, 2, 3, 4},
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_MAXI] = {
+		.name		= "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+		.video_inputs	= 4,
+		.audio_inputs	= 2,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x1800,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800},
+		.pll            = PLL_28,
+		.tuner_type	= TUNER_PHILIPS_SECAM,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-/* ---- card 0x1c ---------------------------------- */
-	.name           = "Terratec TerraTV+ Version 1.1 (bt878)",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x1f0fff,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
-	.needs_tvaudio	= 0,
-	.tuner_type	= TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook	= terratv_audio,
-	/* GPIO wiring:
-	External 20 pin connector (for Active Radio Upgrade board)
-	gpio00: i2c-sda
-	gpio01: i2c-scl
-	gpio02: om5610-data
-	gpio03: om5610-clk
-	gpio04: om5610-wre
-	gpio05: om5610-stereo
-	gpio06: rds6588-davn
-	gpio07: Pin 7 n.c.
-	gpio08: nIOW
-	gpio09+10: nIOR, nSEL ?? (bt878)
-		gpio09: nIOR (bt848)
-		gpio10: nSEL (bt848)
-	Sound Routing:
-	gpio16: u2-A0 (1st 4052bt)
-	gpio17: u2-A1
-	gpio18: u2-nEN
-	gpio19: u4-A0 (2nd 4052)
-	gpio20: u4-A1
-		u4-nEN - GND
-	Btspy:
-		00000 : Cdrom (internal audio input)
-		10000 : ext. Video audio input
-		20000 : TV Mono
-		a0000 : TV Mono/2
-	1a0000 : TV Stereo
-		30000 : Radio
-		40000 : Mute
-*/
-
-},{
-	/* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
-	.name		= "Imagenation PXC200",
-	.video_inputs	= 5,
-	.audio_inputs	= 1,
-	.tuner		= -1,
-	.svhs		= 1, /* was: 4 */
-	.gpiomask	= 0,
-	.muxsel		= { 2, 3, 1, 0, 0},
-	.audiomux	= { 0 },
-	.needs_tvaudio	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-	.muxsel_hook    = PXC200_muxsel,
-
-},{
-	.name		= "Lifeview FlyVideo 98 LR50",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x1800,  /* 0x8dfe00 */
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
-	.pll            = PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Formac iProTV, Formac ProTV I (bt848)",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 3,
-	.gpiomask	= 1,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 1, 0, 0, 0, 0 },
-	.pll            = PLL_28,
-	.tuner_type	= TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-},{
-
-/* ---- card 0x20 ---------------------------------- */
-	.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
-	.video_inputs	= 4,
-	.audio_inputs	= 0,
-	.tuner		= -1,
-	.svhs		= 2,
-	.gpiomask	= 0,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0 },
-	.needs_tvaudio	= 0,
-	.tuner_type	= 4,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name           = "Terratec TerraTValue Version Bt878",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0xffff00,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0x500, 0, 0x300, 0x900, 0x900},
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Leadtek WinFast 2000/ WinFast 2000 XP",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.muxsel		= { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */
-	/* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
-	.gpiomask	= 0xb33000,
-	.audiomux	= { 0x122000,0x1000,0x0000,0x620000,0x800000 },
-	/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
-		gpio23 -- hef4052:nEnable (0x800000)
-		gpio12 -- hef4052:A1
-		gpio13 -- hef4052:A0
-	0x0000: external audio
-	0x1000: FM
-	0x2000: TV
-	0x3000: n.c.
-	Note: There exists another variant "Winfast 2000" with tv stereo !?
-	Note: eeprom only contains FF and pci subsystem id 107d:6606
+	/* ---- card 0x1c ---------------------------------- */
+	[BTTV_BOARD_TERRATV] = {
+		.name           = "Terratec TerraTV+ Version 1.1 (bt878)",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x1f0fff,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
+		.needs_tvaudio	= 0,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook	= terratv_audio,
+		/* GPIO wiring:
+		External 20 pin connector (for Active Radio Upgrade board)
+		gpio00: i2c-sda
+		gpio01: i2c-scl
+		gpio02: om5610-data
+		gpio03: om5610-clk
+		gpio04: om5610-wre
+		gpio05: om5610-stereo
+		gpio06: rds6588-davn
+		gpio07: Pin 7 n.c.
+		gpio08: nIOW
+		gpio09+10: nIOR, nSEL ?? (bt878)
+			gpio09: nIOR (bt848)
+			gpio10: nSEL (bt848)
+		Sound Routing:
+		gpio16: u2-A0 (1st 4052bt)
+		gpio17: u2-A1
+		gpio18: u2-nEN
+		gpio19: u4-A0 (2nd 4052)
+		gpio20: u4-A1
+			u4-nEN - GND
+		Btspy:
+			00000 : Cdrom (internal audio input)
+			10000 : ext. Video audio input
+			20000 : TV Mono
+			a0000 : TV Mono/2
+		1a0000 : TV Stereo
+			30000 : Radio
+			40000 : Mute
 	*/
-	.needs_tvaudio	= 0,
-	.pll		= PLL_28,
-	.has_radio	= 1,
-	.tuner_type	= 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook	= winfast2000_audio,
-	.has_remote     = 1,
-},{
-	.name		= "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
-	.video_inputs	= 4,
-	.audio_inputs	= 3,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x1800,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800},
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
 
-/* ---- card 0x24 ---------------------------------- */
-	.name		= "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
-	.video_inputs	= 4,
-	.audio_inputs	= 3,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x1800,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-	.has_radio	= 1,
-},{
-	.name		= "Prolink PixelView PlayTV pro",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0xff,
-	.muxsel		= { 2, 3, 1, 1 },
-	.audiomux	= { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
-	.no_msp34xx	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Askey CPH06X TView99",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x551e00,
-	.muxsel		= { 2, 3, 1, 0},
-	.audiomux	= { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= 1,
-	.tuner_addr	= ADDR_UNSET,
-	.has_remote     = 1,
-},{
-	.name		= "Pinnacle PCTV Studio/Rave",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x03000F,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 2, 0xd0001, 0, 0, 1},
-	.needs_tvaudio	= 0,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
+	},
+	[BTTV_BOARD_PXC200] = {
+		/* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
+		.name		= "Imagenation PXC200",
+		.video_inputs	= 5,
+		.audio_inputs	= 1,
+		.tuner		= -1,
+		.svhs		= 1, /* was: 4 */
+		.gpiomask	= 0,
+		.muxsel		= { 2, 3, 1, 0, 0},
+		.audiomux	= { 0 },
+		.needs_tvaudio	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.muxsel_hook    = PXC200_muxsel,
 
-/* ---- card 0x28 ---------------------------------- */
-	.name		= "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 7,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 4, 0, 2, 3, 1},
-	.no_msp34xx	= 1,
-	.needs_tvaudio	= 1,
-	.tuner_type     = TUNER_PHILIPS_NTSC,
-	.tuner_addr	= ADDR_UNSET,
-	.pll            = PLL_28,
-	.has_radio      = 1,
-},{
-	.name		= "AVerMedia TVPhone 98",
-	.video_inputs	= 3,
-	.audio_inputs	= 4,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 15,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 13, 4, 11, 7, 0, 0},
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-	.has_radio	= 1,
-	.audio_hook	= avermedia_tvphone_audio,
-},{
-	.name		= "ProVideo PV951", /* pic16c54 */
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 0, 0, 0, 0},
-	.needs_tvaudio	= 1,
-	.no_msp34xx	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= 1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Little OnAir TV",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0xe00b,
-	.muxsel		= {2, 3, 1, 1},
-	.audiomux	= {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
-	.no_msp34xx	= 1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
+	},
+	[BTTV_BOARD_FLYVIDEO_98] = {
+		.name		= "Lifeview FlyVideo 98 LR50",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x1800,  /* 0x8dfe00 */
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
+		.pll            = PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_IPROTV] = {
+		.name		= "Formac iProTV, Formac ProTV I (bt848)",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 3,
+		.gpiomask	= 1,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 1, 0, 0, 0, 0 },
+		.pll            = PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-/* ---- card 0x2c ---------------------------------- */
-	.name		= "Sigma TVII-FM",
-	.video_inputs	= 2,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= -1,
-	.gpiomask	= 3,
-	.muxsel		= {2, 3, 1, 1},
-	.audiomux	= {1, 1, 0, 2, 3},
-	.no_msp34xx	= 1,
-	.pll		= PLL_NONE,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "MATRIX-Vision MV-Delta 2",
-	.video_inputs	= 5,
-	.audio_inputs	= 1,
-	.tuner		= -1,
-	.svhs		= 3,
-	.gpiomask	= 0,
-	.muxsel		= { 2, 3, 1, 0, 0},
-	.audiomux	= {0 },
-	.no_msp34xx	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Zoltrix Genie TV/FM",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0xbcf03f,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
-	.no_msp34xx	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= 21,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Terratec TV/Radio+",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x70000,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
-	.needs_tvaudio	= 1,
-	.no_msp34xx	= 1,
-	.pll		= PLL_35,
-	.tuner_type	= 1,
-	.tuner_addr	= ADDR_UNSET,
-	.has_radio	= 1,
-},{
+	/* ---- card 0x20 ---------------------------------- */
+	[BTTV_BOARD_INTEL_C_S_PCI] = {
+		.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
+		.video_inputs	= 4,
+		.audio_inputs	= 0,
+		.tuner		= -1,
+		.svhs		= 2,
+		.gpiomask	= 0,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0 },
+		.needs_tvaudio	= 0,
+		.tuner_type	= 4,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_TERRATVALUE] = {
+		.name           = "Terratec TerraTValue Version Bt878",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0xffff00,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0x500, 0, 0x300, 0x900, 0x900},
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_WINFAST2000] = {
+		.name		= "Leadtek WinFast 2000/ WinFast 2000 XP",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.muxsel		= { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */
+	#if 0
+		.gpiomask	= 0xc33000,
+		.audiomux	= { 0x422000,0x1000,0x0000,0x620000,0x800000 },
+	#else
+		/* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
+		.gpiomask	= 0xb33000,
+		.audiomux	= { 0x122000,0x1000,0x0000,0x620000,0x800000 },
+	#endif
+		/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
+			gpio23 -- hef4052:nEnable (0x800000)
+			gpio12 -- hef4052:A1
+			gpio13 -- hef4052:A0
+		0x0000: external audio
+		0x1000: FM
+		0x2000: TV
+		0x3000: n.c.
+		Note: There exists another variant "Winfast 2000" with tv stereo !?
+		Note: eeprom only contains FF and pci subsystem id 107d:6606
+		*/
+		.needs_tvaudio	= 0,
+		.pll		= PLL_28,
+		.has_radio	= 1,
+		.tuner_type	= 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook	= winfast2000_audio,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_CHRONOS_VS2] = {
+		.name		= "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+		.video_inputs	= 4,
+		.audio_inputs	= 3,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x1800,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800},
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-/* ---- card 0x30 ---------------------------------- */
-	.name		= "Askey CPH03x/ Dynalink Magic TView",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 15,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= {2,0,0,0,1},
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "IODATA GV-BCTV3/PCI",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x010f00,
-	.muxsel		= {2, 3, 0, 0},
-	.audiomux	= {0x10000, 0, 0x10000, 0, 0, 0},
-	.no_msp34xx	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_ALPS_TSHC6_NTSC,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook	= gvbctv3pci_audio,
-},{
-	.name		= "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
-	.video_inputs	= 5,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 3,
-	.gpiomask	= 0xAA0000,
-	.muxsel		= { 2,3,1,1,-1 },
-	.digital_mode   = DIGITAL_MODE_CAMERA,
-	.audiomux	= { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000  },
-	.no_msp34xx	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_PHILIPS_PAL_I,
-	.tuner_addr	= ADDR_UNSET,
-	.has_remote	= 1,
-	/* GPIO wiring: (different from Rev.4C !)
-		GPIO17: U4.A0 (first hef4052bt)
-		GPIO19: U4.A1
-		GPIO20: U5.A1 (second hef4052bt)
-		GPIO21: U4.nEN
-		GPIO22: BT832 Reset Line
-		GPIO23: A5,A0, U5,nEN
-	Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
+	/* ---- card 0x24 ---------------------------------- */
+	[BTTV_BOARD_TYPHOON_TVIEW] = {
+		.name		= "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+		.video_inputs	= 4,
+		.audio_inputs	= 3,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x1800,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_PXELVWPLTVPRO] = {
+		.name		= "Prolink PixelView PlayTV pro",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0xff,
+		.muxsel		= { 2, 3, 1, 1 },
+		.audiomux	= { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_MAGICTVIEW063] = {
+		.name		= "Askey CPH06X TView99",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x551e00,
+		.muxsel		= { 2, 3, 1, 0},
+		.audiomux	= { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= 1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_PINNACLE] = {
+		.name		= "Pinnacle PCTV Studio/Rave",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x03000F,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 2, 0xd0001, 0, 0, 1},
+		.needs_tvaudio	= 0,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+
+	/* ---- card 0x28 ---------------------------------- */
+	[BTTV_BOARD_STB2] = {
+		.name		= "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 7,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 4, 0, 2, 3, 1},
+		.no_msp34xx	= 1,
+		.needs_tvaudio	= 1,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+		.has_radio      = 1,
+	},
+	[BTTV_BOARD_AVPHONE98] = {
+		.name		= "AVerMedia TVPhone 98",
+		.video_inputs	= 3,
+		.audio_inputs	= 4,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 13, 4, 11, 7, 0, 0},
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_radio	= 1,
+		.audio_hook	= avermedia_tvphone_audio,
+	},
+	[BTTV_BOARD_PV951] = {
+		.name		= "ProVideo PV951", /* pic16c54 */
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 0, 0, 0, 0},
+		.needs_tvaudio	= 1,
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= 1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_ONAIR_TV] = {
+		.name		= "Little OnAir TV",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0xe00b,
+		.muxsel		= {2, 3, 1, 1},
+		.audiomux	= {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
+		.no_msp34xx	= 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+
+	/* ---- card 0x2c ---------------------------------- */
+	[BTTV_BOARD_SIGMA_TVII_FM] = {
+		.name		= "Sigma TVII-FM",
+		.video_inputs	= 2,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= -1,
+		.gpiomask	= 3,
+		.muxsel		= {2, 3, 1, 1},
+		.audiomux	= {1, 1, 0, 2, 3},
+		.no_msp34xx	= 1,
+		.pll		= PLL_NONE,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_MATRIX_VISION2] = {
+		.name		= "MATRIX-Vision MV-Delta 2",
+		.video_inputs	= 5,
+		.audio_inputs	= 1,
+		.tuner		= -1,
+		.svhs		= 3,
+		.gpiomask	= 0,
+		.muxsel		= { 2, 3, 1, 0, 0},
+		.audiomux	= {0 },
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_ZOLTRIX_GENIE] = {
+		.name		= "Zoltrix Genie TV/FM",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0xbcf03f,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= 21,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_TERRATVRADIO] = {
+		.name		= "Terratec TV/Radio+",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x70000,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
+		.needs_tvaudio	= 1,
+		.no_msp34xx	= 1,
+		.pll		= PLL_35,
+		.tuner_type	= 1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_radio	= 1,
+	},
+
+	/* ---- card 0x30 ---------------------------------- */
+	[BTTV_BOARD_DYNALINK] = {
+		.name		= "Askey CPH03x/ Dynalink Magic TView",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= {2,0,0,0,1},
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_GVBCTV3PCI] = {
+		.name		= "IODATA GV-BCTV3/PCI",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x010f00,
+		.muxsel		= {2, 3, 0, 0},
+		.audiomux	= {0x10000, 0, 0x10000, 0, 0, 0},
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_ALPS_TSHC6_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook	= gvbctv3pci_audio,
+	},
+	[BTTV_BOARD_PXELVWPLTVPAK] = {
+		.name		= "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
+		.video_inputs	= 5,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 3,
+		.gpiomask	= 0xAA0000,
+		.muxsel		= { 2,3,1,1,-1 },
+		.digital_mode   = DIGITAL_MODE_CAMERA,
+		.audiomux	= { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000  },
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_remote	= 1,
+		/* GPIO wiring: (different from Rev.4C !)
+			GPIO17: U4.A0 (first hef4052bt)
+			GPIO19: U4.A1
+			GPIO20: U5.A1 (second hef4052bt)
+			GPIO21: U4.nEN
+			GPIO22: BT832 Reset Line
+			GPIO23: A5,A0, U5,nEN
+		Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
+		*/
+	},
+	[BTTV_BOARD_EAGLE] = {
+		.name           = "Eagle Wireless Capricorn2 (bt878A)",
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 7,
+		.muxsel         = { 2, 0, 1, 1},
+		.audiomux       = { 0, 1, 2, 3, 4},
+		.pll            = PLL_28,
+		.tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+
+	/* ---- card 0x34 ---------------------------------- */
+	[BTTV_BOARD_PINNACLEPRO] = {
+		/* David Härdeman <david@2gen.com> */
+		.name           = "Pinnacle PCTV Studio Pro",
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 3,
+		.gpiomask       = 0x03000F,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 1, 0xd0001, 0, 0, 10},
+				/* sound path (5 sources):
+				MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
+					0= ext. Audio IN
+					1= from MUX2
+					2= Mono TV sound from Tuner
+					3= not connected
+				MUX2 (mask 0x30000):
+					0,2,3= from MSP34xx
+					1= FM stereo Radio from Tuner */
+		.needs_tvaudio  = 0,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_TVIEW_RDS_FM] = {
+		/* Claas Langbehn <claas@bigfoot.com>,
+		Sven Grothklags <sven@upb.de> */
+		.name		= "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
+		.video_inputs	= 4,
+		.audio_inputs	= 3,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x1c,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0, 0, 0x10, 8, 4 },
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_LIFETEC_9415] = {
+		/* Tim Röstermundt <rosterm@uni-muenster.de>
+		in de.comp.os.unix.linux.hardware:
+			options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
+			audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
+			options tuner type=5 */
+		.name		= "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x18e0,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
+			/* For cards with tda9820/tda9821:
+				0x0000: Tuner normal stereo
+				0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
+				0x0880: Tuner A2 stereo */
+		.pll		= PLL_28,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_BESTBUY_EASYTV] = {
+		/* Miguel Angel Alvarez <maacruz@navegalia.com>
+		old Easy TV BT848 version (model CPH031) */
+		.name           = "Askey CPH031/ BESTBUY Easy TV",
+		.video_inputs	= 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0xF,
+		.muxsel         = { 2, 3, 1, 0},
+		.audiomux       = { 2, 0, 0, 0, 10},
+		.needs_tvaudio  = 0,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TEMIC_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+
+	/* ---- card 0x38 ---------------------------------- */
+	[BTTV_BOARD_FLYVIDEO_98FM] = {
+		/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
+		.name           = "Lifeview FlyVideo 98FM LR50",
+		.video_inputs   = 4,
+		.audio_inputs   = 3,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x1800,
+		.muxsel         = { 2, 3, 1, 1},
+		.audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+		.pll            = PLL_28,
+		.tuner_type     = 5,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+		/* This is the ultimate cheapo capture card
+		* just a BT848A on a small PCB!
+		* Steve Hosgood <steve@equiinet.com> */
+	[BTTV_BOARD_GRANDTEC] = {
+		.name           = "GrandTec 'Grand Video Capture' (Bt848)",
+		.video_inputs   = 2,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = 1,
+		.gpiomask       = 0,
+		.muxsel         = { 3, 1 },
+		.audiomux       = { 0 },
+		.needs_tvaudio  = 0,
+		.no_msp34xx     = 1,
+		.pll            = PLL_35,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_ASKEY_CPH060] = {
+		/* Daniel Herrington <daniel.herrington@home.com> */
+		.name           = "Askey CPH060/ Phoebe TV Master Only (No FM)",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0xe00,
+		.muxsel         = { 2, 3, 1, 1},
+		.audiomux       = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_ASKEY_CPH03X] = {
+		/* Matti Mottus <mottus@physic.ut.ee> */
+		.name		= "Askey CPH03x TV Capturer",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask       = 0x03000F,
+		.muxsel		= { 2, 3, 1, 0},
+		.audiomux       = { 2,0,0,0,1 },
+		.pll            = PLL_28,
+		.tuner_type	= 0,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+
+	/* ---- card 0x3c ---------------------------------- */
+	[BTTV_BOARD_MM100PCTV] = {
+		/* Philip Blundell <philb@gnu.org> */
+		.name           = "Modular Technology MM100PCTV",
+		.video_inputs   = 2,
+		.audio_inputs   = 2,
+		.tuner		= 0,
+		.svhs		= -1,
+		.gpiomask       = 11,
+		.muxsel         = { 2, 3, 1, 1},
+		.audiomux       = { 2, 0, 0, 1, 8},
+		.pll            = PLL_35,
+		.tuner_type     = TUNER_TEMIC_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_GMV1] = {
+		/* Adrian Cox <adrian@humboldt.co.uk */
+		.name		= "AG Electronics GMV1",
+		.video_inputs   = 2,
+		.audio_inputs   = 0,
+		.tuner		= -1,
+		.svhs		= 1,
+		.gpiomask       = 0xF,
+		.muxsel		= { 2, 2},
+		.audiomux       = { },
+		.no_msp34xx     = 1,
+		.needs_tvaudio  = 0,
+		.pll		= PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_BESTBUY_EASYTV2] = {
+		/* Miguel Angel Alvarez <maacruz@navegalia.com>
+		new Easy TV BT878 version (model CPH061)
+		special thanks to Informatica Mieres for providing the card */
+		.name           = "Askey CPH061/ BESTBUY Easy TV (bt878)",
+		.video_inputs	= 3,
+		.audio_inputs   = 2,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0xFF,
+		.muxsel         = { 2, 3, 1, 0},
+		.audiomux       = { 1, 0, 4, 4, 9},
+		.needs_tvaudio  = 0,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_ATI_TVWONDER] = {
+		/* Lukas Gebauer <geby@volny.cz> */
+		.name		= "ATI TV-Wonder",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0xf03f,
+		.muxsel		= { 2, 3, 1, 0 },
+		.audiomux	= { 0xbffe, 0, 0xbfff, 0, 0xbffe},
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TEMIC_4006FN5_MULTI_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+
+	/* ---- card 0x40 ---------------------------------- */
+	[BTTV_BOARD_ATI_TVWONDERVE] = {
+		/* Lukas Gebauer <geby@volny.cz> */
+		.name		= "ATI TV-Wonder VE",
+		.video_inputs	= 2,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= -1,
+		.gpiomask	= 1,
+		.muxsel		= { 2, 3, 0, 1},
+		.audiomux	= { 0, 0, 1, 0, 0},
+		.no_msp34xx	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TEMIC_4006FN5_MULTI_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_FLYVIDEO2000] = {
+		/* DeeJay <deejay@westel900.net (2000S) */
+		.name           = "Lifeview FlyVideo 2000S LR90",
+		.video_inputs   = 3,
+		.audio_inputs   = 3,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask	= 0x18e0,
+		.muxsel		= { 2, 3, 0, 1},
+				/* Radio changed from 1e80 to 0x800 to make
+				FlyVideo2000S in .hu happy (gm)*/
+				/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
+		.audiomux	= { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
+		.audio_hook	= fv2000s_audio,
+		.no_msp34xx	= 1,
+		.no_tda9875	= 1,
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = 5,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_TERRATVALUER] = {
+		.name		= "Terratec TValueRadio",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0xffff00,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 0x500, 0x500, 0x300, 0x900, 0x900},
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_GVBCTV4PCI] = {
+		/* TANAKA Kei <peg00625@nifty.com> */
+		.name           = "IODATA GV-BCTV4/PCI",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x010f00,
+		.muxsel         = {2, 3, 0, 0},
+		.audiomux       = {0x10000, 0, 0x10000, 0, 0, 0},
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook     = gvbctv3pci_audio,
+	},
+
+	/* ---- card 0x44 ---------------------------------- */
+	[BTTV_BOARD_VOODOOTV_FM] = {
+		.name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+		/* try "insmod msp3400 simple=0" if you have
+		* sound problems with this card. */
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = -1,
+		.gpiomask       = 0x4f8a00,
+		/* 0x100000: 1=MSP enabled (0=disable again)
+		* 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+		.audiomux       = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
+		/* tvtuner, radio,   external,internal, mute,  stereo
+		* tuner, Composit, SVid, Composit-on-Svid-adapter */
+		.muxsel         = { 2, 3 ,0 ,1},
+		.tuner_type     = TUNER_MT2032,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll		= PLL_28,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_AIMMS] = {
+		/* Philip Blundell <pb@nexus.co.uk> */
+		.name           = "Active Imaging AIMMS",
+		.video_inputs   = 1,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+		.muxsel         = { 2 },
+		.gpiomask       = 0
+	},
+	[BTTV_BOARD_PV_BT878P_PLUS] = {
+		/* Tomasz Pyra <hellfire@sedez.iq.pl> */
+		.name           = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
+		.video_inputs   = 3,
+		.audio_inputs   = 4,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 15,
+		.muxsel         = { 2, 3, 1, 1},
+		.audiomux       = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = 25,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_remote     = 1,
+		/* GPIO wiring:
+			GPIO0: U4.A0 (hef4052bt)
+			GPIO1: U4.A1
+			GPIO2: U4.A1 (second hef4052bt)
+			GPIO3: U4.nEN, U5.A0, A5.nEN
+			GPIO8-15: vrd866b ?
+		*/
+	},
+	[BTTV_BOARD_FLYVIDEO98EZ] = {
+		.name		= "Lifeview FlyVideo 98EZ (capture only) LR51",
+		.video_inputs	= 4,
+		.audio_inputs   = 0,
+		.tuner		= -1,
+		.svhs		= 2,
+		.muxsel		= { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+
+	/* ---- card 0x48 ---------------------------------- */
+	[BTTV_BOARD_PV_BT878P_9B] = {
+		/* Dariusz Kowalewski <darekk@automex.pl> */
+		.name		= "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+		.video_inputs	= 4,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x3f,
+		.muxsel		= { 2, 3, 1, 1 },
+		.audiomux	= { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
+		.needs_tvaudio  = 1,
+		.no_msp34xx	= 1,
+		.no_tda9875	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= 5,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook	= pvbt878p9b_audio, /* Note: not all cards have stereo */
+		.has_radio	= 1,  /* Note: not all cards have radio */
+		.has_remote     = 1,
+		/* GPIO wiring:
+			GPIO0: A0 hef4052
+			GPIO1: A1 hef4052
+			GPIO3: nEN hef4052
+			GPIO8-15: vrd866b
+			GPIO20,22,23: R30,R29,R28
+		*/
+	},
+	[BTTV_BOARD_SENSORAY311] = {
+		/* Clay Kunz <ckunz@mail.arc.nasa.gov> */
+		/* you must jumper JP5 for the card to work */
+		.name           = "Sensoray 311",
+		.video_inputs   = 5,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = 4,
+		.gpiomask       = 0,
+		.muxsel         = { 2, 3, 1, 0, 0},
+		.audiomux       = { 0 },
+		.needs_tvaudio  = 0,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_RV605] = {
+		/* Miguel Freitas <miguel@cetuc.puc-rio.br> */
+		.name           = "RemoteVision MX (RV605)",
+		.video_inputs   = 16,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.gpiomask       = 0x00,
+		.gpiomask2      = 0x07ff,
+		.muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
+				0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.muxsel_hook    = rv605_muxsel,
+	},
+	[BTTV_BOARD_POWERCLR_MTV878] = {
+		.name           = "Powercolor MTV878/ MTV878R/ MTV878F",
+		.video_inputs   = 3,
+		.audio_inputs   = 2,
+		.tuner		= 0,
+		.svhs           = 2,
+		.gpiomask       = 0x1C800F,  /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
+		.muxsel         = { 2, 1, 1, },
+		.audiomux       = { 0, 1, 2, 2, 4 },
+		.needs_tvaudio  = 0,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll		= PLL_28,
+		.has_radio	= 1,
+	},
+
+	/* ---- card 0x4c ---------------------------------- */
+	[BTTV_BOARD_WINDVR] = {
+		/* Masaki Suzuki <masaki@btree.org> */
+		.name           = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x140007,
+		.muxsel         = { 2, 3, 1, 1 },
+		.audiomux       = { 0, 1, 2, 3, 4, 0 },
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook     = windvr_audio,
+	},
+	[BTTV_BOARD_GRANDTEC_MULTI] = {
+		.name           = "GrandTec Multi Capture Card (Bt878)",
+		.video_inputs   = 4,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.gpiomask       = 0,
+		.muxsel         = { 2, 3, 1, 0 },
+		.audiomux       = { 0 },
+		.needs_tvaudio  = 0,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_KWORLD] = {
+		.name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+		.video_inputs   = 4,
+		.audio_inputs   = 3,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 7,
+		.muxsel         = { 2, 3, 1, 1 },   /* Tuner, SVid, SVHS, SVid to SVHS connector */
+		.audiomux       = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio!
+						* This card lacks external Audio In, so we mute it on Ext. & Int.
+						* The PCB can take a sbx1637/sbx1673, wiring unknown.
+						* This card lacks PCI subsystem ID, sigh.
+						* audiomux=1: lower volume, 2+3: mute
+						* btwincap uses 0x80000/0x80003
+						*/
+		.needs_tvaudio  = 0,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = 5,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		/* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+		radio signal strength indicators work fine. */
+		.has_radio	= 1,
+		/* GPIO Info:
+			GPIO0,1:   HEF4052 A0,A1
+			GPIO2:     HEF4052 nENABLE
+			GPIO3-7:   n.c.
+			GPIO8-13:  IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
+			GPIO14,15: ??
+			GPIO16-21: n.c.
+			GPIO22,23: ??
+			??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
+	},
+	[BTTV_BOARD_DSP_TCVIDEO] = {
+		/* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+		.name           = "DSP Design TCVIDEO",
+		.video_inputs   = 4,
+		.svhs           = -1,
+		.muxsel         = { 2, 3, 1, 0},
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+
+		/* ---- card 0x50 ---------------------------------- */
+	[BTTV_BOARD_HAUPPAUGEPVR] = {
+		.name           = "Hauppauge WinTV PVR",
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.muxsel         = { 2, 0, 1, 1},
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+
+		.gpiomask       = 7,
+		.audiomux       = {7},
+	},
+	[BTTV_BOARD_GVBCTV5PCI] = {
+		.name           = "IODATA GV-BCTV5/PCI",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x0f0f80,
+		.muxsel         = {2, 3, 1, 0},
+		.audiomux       = {0x030000, 0x010000, 0, 0, 0x020000, 0},
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook     = gvbctv5pci_audio,
+		.has_radio      = 1,
+	},
+	[BTTV_BOARD_OSPREY1x0] = {
+		.name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
+		.video_inputs   = 4,                  /* id-inputs-clock */
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = 3,
+		.muxsel         = { 3, 2, 0, 1 },
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY1x0_848] = {
+		.name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
+		.video_inputs   = 3,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = 2,
+		.muxsel         = { 2, 3, 1 },
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+
+		/* ---- card 0x54 ---------------------------------- */
+	[BTTV_BOARD_OSPREY101_848] = {
+		.name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
+		.video_inputs   = 2,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = 1,
+		.muxsel         = { 3, 1 },
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY1x1] = {
+		.name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
+		.video_inputs   = 1,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.muxsel         = { 0 },
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY1x1_SVID] = {
+		.name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
+		.video_inputs   = 2,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = 1,
+		.muxsel         = { 0, 1 },
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY2xx] = {
+		.name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
+		.video_inputs   = 1,
+		.audio_inputs   = 1,
+		.tuner          = -1,
+		.svhs           = -1,
+		.muxsel         = { 0 },
+		.pll            = PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+
+		/* ---- card 0x58 ---------------------------------- */
+	[BTTV_BOARD_OSPREY2x0_SVID] = {
+		.name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
+		.video_inputs   = 2,
+		.audio_inputs   = 1,
+		.tuner          = -1,
+		.svhs           = 1,
+		.muxsel         = { 0, 1 },
+		.pll            = PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY2x0] = {
+		.name           = "Osprey 210/220",   /* 0x1(A|B)-04C0-C1 */
+		.video_inputs   = 2,
+		.audio_inputs   = 1,
+		.tuner          = -1,
+		.svhs           = 1,
+		.muxsel         = { 2, 3 },
+		.pll            = PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY500] = {
+		.name           = "Osprey 500",   /* 500 */
+		.video_inputs   = 2,
+		.audio_inputs   = 1,
+		.tuner          = -1,
+		.svhs           = 1,
+		.muxsel         = { 2, 3 },
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+	[BTTV_BOARD_OSPREY540] = {
+		.name           = "Osprey 540",   /* 540 */
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = -1,
+	#if 0 /* TODO ... */
+		.svhs           = OSPREY540_SVID_ANALOG,
+		.muxsel         = {       [OSPREY540_COMP_ANALOG] = 2,
+					[OSPREY540_SVID_ANALOG] = 3, },
+	#endif
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	#if 0 /* TODO ... */
+		.muxsel_hook    = osprey_540_muxsel,
+		.picture_hook   = osprey_540_set_picture,
+	#endif
+	},
+
+		/* ---- card 0x5C ---------------------------------- */
+	[BTTV_BOARD_OSPREY2000] = {
+		.name           = "Osprey 2000",  /* 2000 */
+		.video_inputs   = 2,
+		.audio_inputs   = 1,
+		.tuner          = -1,
+		.svhs           = 1,
+		.muxsel         = { 2, 3 },
+		.pll            = PLL_28,
+		.tuner_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
+	},
+	[BTTV_BOARD_IDS_EAGLE] = {
+		/* M G Berberich <berberic@forwiss.uni-passau.de> */
+		.name           = "IDS Eagle",
+		.video_inputs   = 4,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.svhs           = -1,
+		.gpiomask       = 0,
+		.muxsel         = { 0, 1, 2, 3 },
+		.muxsel_hook    = eagle_muxsel,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_PINNACLESAT] = {
+		.name           = "Pinnacle PCTV Sat",
+		.video_inputs   = 2,
+		.audio_inputs   = 0,
+		.svhs           = 1,
+		.tuner          = -1,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.muxsel         = { 3, 0, 1, 2},
+		.pll            = PLL_28,
+		.no_gpioirq     = 1,
+		.has_dvb        = 1,
+	},
+	[BTTV_BOARD_FORMAC_PROTV] = {
+		.name           = "Formac ProTV II (bt878)",
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 3,
+		.gpiomask       = 2,
+		/* TV, Comp1, Composite over SVID con, SVID */
+		.muxsel         = { 2, 3, 1, 1},
+		.audiomux       = { 2, 2, 0, 0, 0 },
+		.pll            = PLL_28,
+		.has_radio      = 1,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	/* sound routing:
+		GPIO=0x00,0x01,0x03: mute (?)
+		0x02: both TV and radio (tuner: FM1216/I)
+		The card has onboard audio connectors labeled "cdrom" and "board",
+		not soldered here, though unknown wiring.
+		Card lacks: external audio in, pci subsystem id.
 	*/
-},{
-	.name           = "Eagle Wireless Capricorn2 (bt878A)",
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 7,
-	.muxsel         = { 2, 0, 1, 1},
-	.audiomux       = { 0, 1, 2, 3, 4},
-	.pll            = PLL_28,
-	.tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
-	.tuner_addr	= ADDR_UNSET,
-},{
+	},
 
-/* ---- card 0x34 ---------------------------------- */
-	/* David Härdeman <david@2gen.com> */
-	.name           = "Pinnacle PCTV Studio Pro",
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 3,
-	.gpiomask       = 0x03000F,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 1, 0xd0001, 0, 0, 10},
-			/* sound path (5 sources):
-			MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
-				0= ext. Audio IN
-				1= from MUX2
-				2= Mono TV sound from Tuner
-				3= not connected
-			MUX2 (mask 0x30000):
-				0,2,3= from MSP34xx
-				1= FM stereo Radio from Tuner */
-	.needs_tvaudio  = 0,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Claas Langbehn <claas@bigfoot.com>,
-	Sven Grothklags <sven@upb.de> */
-	.name		= "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
-	.video_inputs	= 4,
-	.audio_inputs	= 3,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x1c,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0, 0, 0x10, 8, 4 },
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.has_radio	= 1,
-},{
-	/* Tim Röstermundt <rosterm@uni-muenster.de>
-	in de.comp.os.unix.linux.hardware:
-		options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
-		audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
-		options tuner type=5 */
-	.name		= "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x18e0,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
-		/* For cards with tda9820/tda9821:
-			0x0000: Tuner normal stereo
-			0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
-			0x0880: Tuner A2 stereo */
-	.pll		= PLL_28,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Miguel Angel Alvarez <maacruz@navegalia.com>
-	old Easy TV BT848 version (model CPH031) */
-	.name           = "Askey CPH031/ BESTBUY Easy TV",
-	.video_inputs	= 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0xF,
-	.muxsel         = { 2, 3, 1, 0},
-	.audiomux       = { 2, 0, 0, 0, 10},
-	.needs_tvaudio  = 0,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_TEMIC_PAL,
-	.tuner_addr	= ADDR_UNSET,
-},{
+		/* ---- card 0x60 ---------------------------------- */
+	[BTTV_BOARD_MACHTV] = {
+		.name           = "MachTV",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = -1,
+		.gpiomask       = 7,
+		.muxsel         = { 2, 3, 1, 1},
+		.audiomux       = { 0, 1, 2, 3, 4},
+		.needs_tvaudio  = 1,
+		.tuner_type     = 5,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_EURESYS_PICOLO] = {
+		.name           = "Euresys Picolo",
+		.video_inputs   = 3,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = 2,
+		.gpiomask       = 0,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.muxsel         = { 2, 0, 1},
+		.pll            = PLL_28,
+		.tuner_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_PV150] = {
+		/* Luc Van Hoeylandt <luc@e-magic.be> */
+		.name           = "ProVideo PV150", /* 0x4f */
+		.video_inputs   = 2,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.gpiomask       = 0,
+		.muxsel         = { 2, 3 },
+		.audiomux       = { 0 },
+		.needs_tvaudio  = 0,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_AD_TVK503] = {
+		/* Hiroshi Takekawa <sian@big.or.jp> */
+		/* This card lacks subsystem ID */
+		.name           = "AD-TVK503", /* 0x63 */
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x001e8007,
+		.muxsel         = { 2, 3, 1, 0 },
+		/*                  Tuner, Radio, external, internal, off,  on */
+		.audiomux       = { 0x08,  0x0f,  0x0a,     0x08,     0x0f, 0x08 },
+		.needs_tvaudio  = 0,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = 2,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.audio_hook	= adtvk503_audio,
+	},
 
-/* ---- card 0x38 ---------------------------------- */
-	/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
-	.name           = "Lifeview FlyVideo 98FM LR50",
-	.video_inputs   = 4,
-	.audio_inputs   = 3,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x1800,
-	.muxsel         = { 2, 3, 1, 1},
-	.audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	.pll            = PLL_28,
-	.tuner_type     = 5,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* This is the ultimate cheapo capture card
-	* just a BT848A on a small PCB!
-	* Steve Hosgood <steve@equiinet.com> */
-	.name           = "GrandTec 'Grand Video Capture' (Bt848)",
-	.video_inputs   = 2,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = 1,
-	.gpiomask       = 0,
-	.muxsel         = { 3, 1 },
-	.audiomux       = { 0 },
-	.needs_tvaudio  = 0,
-	.no_msp34xx     = 1,
-	.pll            = PLL_35,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Daniel Herrington <daniel.herrington@home.com> */
-	.name           = "Askey CPH060/ Phoebe TV Master Only (No FM)",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0xe00,
-	.muxsel         = { 2, 3, 1, 1},
-	.audiomux       = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
-	.needs_tvaudio  = 1,
-	.pll            = PLL_28,
-	.tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Matti Mottus <mottus@physic.ut.ee> */
-	.name		= "Askey CPH03x TV Capturer",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask       = 0x03000F,
-	.muxsel		= { 2, 3, 1, 0},
-	.audiomux       = { 2,0,0,0,1 },
-	.pll            = PLL_28,
-	.tuner_type	= 0,
-	.tuner_addr	= ADDR_UNSET,
-},{
+		/* ---- card 0x64 ---------------------------------- */
+	[BTTV_BOARD_HERCULES_SM_TV] = {
+		.name           = "Hercules Smart TV Stereo",
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x00,
+		.muxsel         = { 2, 3, 1, 1 },
+		.needs_tvaudio  = 1,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = 5,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		/* Notes:
+		- card lacks subsystem ID
+		- stereo variant w/ daughter board with tda9874a @0xb0
+		- Audio Routing:
+			always from tda9874 independent of GPIO (?)
+			external line in: unknown
+		- Other chips: em78p156elp @ 0x96 (probably IR remote control)
+			hef4053 (instead 4052) for unknown function
+		*/
+	},
+	[BTTV_BOARD_PACETV] = {
+		.name           = "Pace TV & Radio Card",
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.muxsel         = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */
+		.gpiomask       = 0,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.tuner_type     = 1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_radio      = 1,
+		.pll            = PLL_28,
+		/* Bt878, Bt832, FI1246 tuner; no pci subsystem id
+		only internal line out: (4pin header) RGGL
+		Radio must be decoded by msp3410d (not routed through)*/
+		/*
+		.digital_mode   = DIGITAL_MODE_CAMERA,  todo!
+		*/
+	},
+	[BTTV_BOARD_IVC200] = {
+		/* Chris Willing <chris@vislab.usyd.edu.au> */
+		.name           = "IVC-200",
+		.video_inputs   = 1,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.svhs           = -1,
+		.gpiomask       = 0xdf,
+		.muxsel         = { 2 },
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_XGUARD] = {
+		.name           = "Grand X-Guard / Trust 814PCI",
+		.video_inputs   = 16,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.tuner_type     = 4,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask2      = 0xff,
+		.muxsel         = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
+		.muxsel_hook    = xguard_muxsel,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+	},
 
-/* ---- card 0x3c ---------------------------------- */
-	/* Philip Blundell <philb@gnu.org> */
-	.name           = "Modular Technology MM100PCTV",
-	.video_inputs   = 2,
-	.audio_inputs   = 2,
-	.tuner		= 0,
-	.svhs		= -1,
-	.gpiomask       = 11,
-	.muxsel         = { 2, 3, 1, 1},
-	.audiomux       = { 2, 0, 0, 1, 8},
-	.pll            = PLL_35,
-	.tuner_type     = TUNER_TEMIC_PAL,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Adrian Cox <adrian@humboldt.co.uk */
-	.name	        = "AG Electronics GMV1",
-	.video_inputs   = 2,
-	.audio_inputs   = 0,
-	.tuner	        = -1,
-	.svhs	        = 1,
-	.gpiomask       = 0xF,
-	.muxsel	        = { 2, 2},
-	.audiomux       = { },
-	.no_msp34xx     = 1,
-	.needs_tvaudio  = 0,
-	.pll	        = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Miguel Angel Alvarez <maacruz@navegalia.com>
-	new Easy TV BT878 version (model CPH061)
-	special thanks to Informatica Mieres for providing the card */
-	.name           = "Askey CPH061/ BESTBUY Easy TV (bt878)",
-	.video_inputs	= 3,
-	.audio_inputs   = 2,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0xFF,
-	.muxsel         = { 2, 3, 1, 0},
-	.audiomux       = { 1, 0, 4, 4, 9},
-	.needs_tvaudio  = 0,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Lukas Gebauer <geby@volny.cz> */
-	.name		= "ATI TV-Wonder",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0xf03f,
-	.muxsel		= { 2, 3, 1, 0 },
-	.audiomux	= { 0xbffe, 0, 0xbfff, 0, 0xbffe},
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_TEMIC_4006FN5_MULTI_PAL,
-	.tuner_addr	= ADDR_UNSET,
-},{
+		/* ---- card 0x68 ---------------------------------- */
+	[BTTV_BOARD_NEBULA_DIGITV] = {
+		.name           = "Nebula Electronics DigiTV",
+		.video_inputs   = 1,
+		.tuner          = -1,
+		.svhs           = -1,
+		.muxsel         = { 2, 3, 1, 0},
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_dvb        = 1,
+		.no_gpioirq     = 1,
+	},
+	[BTTV_BOARD_PV143] = {
+		/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
+		.name           = "ProVideo PV143",
+		.video_inputs   = 4,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.gpiomask       = 0,
+		.muxsel         = { 2, 3, 1, 0 },
+		.audiomux       = { 0 },
+		.needs_tvaudio  = 0,
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_VD009X1_MINIDIN] = {
+		/* M.Klahr@phytec.de */
+		.name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
+		.video_inputs   = 4,
+		.audio_inputs   = 0,
+		.tuner          = -1, /* card has no tuner */
+		.svhs           = 3,
+		.gpiomask       = 0x00,
+		.muxsel         = { 2, 3, 1, 0},
+		.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_VD009X1_COMBI] = {
+		.name           = "PHYTEC VD-009-X1 Combi (bt878)",
+		.video_inputs   = 4,
+		.audio_inputs   = 0,
+		.tuner          = -1, /* card has no tuner */
+		.svhs           = 3,
+		.gpiomask       = 0x00,
+		.muxsel         = { 2, 3, 1, 1},
+		.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-/* ---- card 0x40 ---------------------------------- */
-	/* Lukas Gebauer <geby@volny.cz> */
-	.name		= "ATI TV-Wonder VE",
-	.video_inputs	= 2,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= -1,
-	.gpiomask	= 1,
-	.muxsel		= { 2, 3, 0, 1},
-	.audiomux	= { 0, 0, 1, 0, 0},
-	.no_msp34xx	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_TEMIC_4006FN5_MULTI_PAL,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* DeeJay <deejay@westel900.net (2000S) */
-	.name           = "Lifeview FlyVideo 2000S LR90",
-	.video_inputs   = 3,
-	.audio_inputs   = 3,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask	= 0x18e0,
-	.muxsel		= { 2, 3, 0, 1},
-			/* Radio changed from 1e80 to 0x800 to make
-			FlyVideo2000S in .hu happy (gm)*/
-			/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
-	.audiomux	= { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
-	.audio_hook	= fv2000s_audio,
-	.no_msp34xx	= 1,
-	.no_tda9875	= 1,
-	.needs_tvaudio  = 1,
-	.pll            = PLL_28,
-	.tuner_type     = 5,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name		= "Terratec TValueRadio",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0xffff00,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux	= { 0x500, 0x500, 0x300, 0x900, 0x900},
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.has_radio	= 1,
-},{
-	/* TANAKA Kei <peg00625@nifty.com> */
-	.name           = "IODATA GV-BCTV4/PCI",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x010f00,
-	.muxsel         = {2, 3, 0, 0},
-	.audiomux       = {0x10000, 0, 0x10000, 0, 0, 0},
-	.no_msp34xx     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook     = gvbctv3pci_audio,
-},{
+		/* ---- card 0x6c ---------------------------------- */
+	[BTTV_BOARD_VD009_MINIDIN] = {
+		.name           = "PHYTEC VD-009 MiniDIN (bt878)",
+		.video_inputs   = 10,
+		.audio_inputs   = 0,
+		.tuner          = -1, /* card has no tuner */
+		.svhs           = 9,
+		.gpiomask       = 0x00,
+		.gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
+					via the upper nibble of muxsel. here: used for
+					xternal video-mux */
+		.muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
+		.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_VD009_COMBI] = {
+		.name           = "PHYTEC VD-009 Combi (bt878)",
+		.video_inputs   = 10,
+		.audio_inputs   = 0,
+		.tuner          = -1, /* card has no tuner */
+		.svhs           = 9,
+		.gpiomask       = 0x00,
+		.gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
+					via the upper nibble of muxsel. here: used for
+					xternal video-mux */
+		.muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
+		.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_IVC100] = {
+		.name           = "IVC-100",
+		.video_inputs   = 4,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.svhs           = -1,
+		.gpiomask       = 0xdf,
+		.muxsel         = { 2, 3, 1, 0 },
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_IVC120] = {
+		/* IVC-120G - Alan Garfield <alan@fromorbit.com> */
+		.name           = "IVC-120G",
+		.video_inputs   = 16,
+		.audio_inputs   = 0,    /* card has no audio */
+		.tuner          = -1,   /* card has no tuner */
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.svhs           = -1,   /* card has no svhs */
+		.needs_tvaudio  = 0,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.gpiomask       = 0x00,
+		.muxsel         = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+				0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
+		.muxsel_hook    = ivc120_muxsel,
+		.pll            = PLL_28,
+	},
 
-/* ---- card 0x44 ---------------------------------- */
-	.name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
-	/* try "insmod msp3400 simple=0" if you have
-	* sound problems with this card. */
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = -1,
-	.gpiomask       = 0x4f8a00,
-	/* 0x100000: 1=MSP enabled (0=disable again)
-	* 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
-	.audiomux       = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
-	/* tvtuner, radio,   external,internal, mute,  stereo
-	* tuner, Composit, SVid, Composit-on-Svid-adapter */
-	.muxsel         = { 2, 3 ,0 ,1},
-	.tuner_type     = TUNER_MT2032,
-	.tuner_addr	= ADDR_UNSET,
-	.pll		= PLL_28,
-	.has_radio	= 1,
-},{
-	/* Philip Blundell <pb@nexus.co.uk> */
-	.name           = "Active Imaging AIMMS",
-	.video_inputs   = 1,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.pll            = PLL_28,
-	.muxsel         = { 2 },
-	.gpiomask       = 0
-},{
-	/* Tomasz Pyra <hellfire@sedez.iq.pl> */
-	.name           = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
-	.video_inputs   = 3,
-	.audio_inputs   = 4,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 15,
-	.muxsel         = { 2, 3, 1, 1},
-	.audiomux       = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */
-	.needs_tvaudio  = 1,
-	.pll            = PLL_28,
-	.tuner_type     = 25,
-	.tuner_addr	= ADDR_UNSET,
-	.has_remote     = 1,
-	/* GPIO wiring:
-		GPIO0: U4.A0 (hef4052bt)
-		GPIO1: U4.A1
-		GPIO2: U4.A1 (second hef4052bt)
-		GPIO3: U4.nEN, U5.A0, A5.nEN
-		GPIO8-15: vrd866b ?
-	*/
-},{
-	.name		= "Lifeview FlyVideo 98EZ (capture only) LR51",
-	.video_inputs	= 4,
-	.audio_inputs   = 0,
-	.tuner		= -1,
-	.svhs		= 2,
-	.muxsel		= { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */
-	.pll		= PLL_28,
-	.no_msp34xx	= 1,
-	.tuner_type	= UNSET,
-	.tuner_addr	= ADDR_UNSET,
-},{
+		/* ---- card 0x70 ---------------------------------- */
+	[BTTV_BOARD_PC_HDTV] = {
+		.name           = "pcHDTV HD-2000 TV",
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.muxsel         = { 2, 3, 1, 0},
+		.tuner_type     = TUNER_PHILIPS_ATSC,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_dvb        = 1,
+	},
+	[BTTV_BOARD_TWINHAN_DST] = {
+		.name           = "Twinhan DST + clones",
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_video       = 1,
+		.has_dvb        = 1,
+	},
+	[BTTV_BOARD_WINFASTVC100] = {
+		.name           = "Winfast VC100",
+		.video_inputs   = 3,
+		.audio_inputs   = 0,
+		.svhs           = 1,
+		.tuner          = -1,
+		.muxsel         = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+	},
+	[BTTV_BOARD_TEV560] = {
+		.name           = "Teppro TEV-560/InterVision IV-560",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 3,
+		.muxsel         = { 2, 3, 1, 1},
+		.audiomux       = { 1, 1, 1, 1, 0},
+		.needs_tvaudio  = 1,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_35,
+	},
 
-/* ---- card 0x48 ---------------------------------- */
-	/* Dariusz Kowalewski <darekk@automex.pl> */
-	.name		= "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
-	.video_inputs	= 4,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x3f,
-	.muxsel		= { 2, 3, 1, 1 },
-	.audiomux	= { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
-	.needs_tvaudio  = 1,
-	.no_msp34xx	= 1,
-	.no_tda9875	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= 5,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook	= pvbt878p9b_audio, /* Note: not all cards have stereo */
-	.has_radio	= 1,  /* Note: not all cards have radio */
-	.has_remote     = 1,
-	/* GPIO wiring:
-		GPIO0: A0 hef4052
-		GPIO1: A1 hef4052
-		GPIO3: nEN hef4052
-		GPIO8-15: vrd866b
-		GPIO20,22,23: R30,R29,R28
-	*/
-},{
-	/* Clay Kunz <ckunz@mail.arc.nasa.gov> */
-	/* you must jumper JP5 for the card to work */
-	.name           = "Sensoray 311",
-	.video_inputs   = 5,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = 4,
-	.gpiomask       = 0,
-	.muxsel         = { 2, 3, 1, 0, 0},
-	.audiomux       = { 0 },
-	.needs_tvaudio  = 0,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Miguel Freitas <miguel@cetuc.puc-rio.br> */
-	.name           = "RemoteVision MX (RV605)",
-	.video_inputs   = 16,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.gpiomask       = 0x00,
-	.gpiomask2      = 0x07ff,
-	.muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
-			0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.muxsel_hook    = rv605_muxsel,
-},{
-	.name           = "Powercolor MTV878/ MTV878R/ MTV878F",
-	.video_inputs   = 3,
-	.audio_inputs   = 2,
-	.tuner		= 0,
-	.svhs           = 2,
-	.gpiomask       = 0x1C800F,  /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
-	.muxsel         = { 2, 1, 1, },
-	.audiomux       = { 0, 1, 2, 2, 4 },
-	.needs_tvaudio  = 0,
-	.tuner_type     = TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.pll		= PLL_28,
-	.has_radio	= 1,
-},{
+		/* ---- card 0x74 ---------------------------------- */
+	[BTTV_BOARD_SIMUS_GVC1100] = {
+		.name           = "SIMUS GVC1100",
+		.video_inputs   = 4,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+		.muxsel         = { 2, 2, 2, 2},
+		.gpiomask       = 0x3F,
+		.muxsel_hook    = gvc1100_muxsel,
+	},
+	[BTTV_BOARD_NGSTV_PLUS] = {
+		/* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
+		.name           = "NGS NGSTV+",
+		.video_inputs   = 3,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x008007,
+		.muxsel         = {2, 3, 0, 0},
+		.audiomux       = {0, 0, 0, 0, 0x000003, 0},
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_LMLBT4] = {
+		/* http://linuxmedialabs.com */
+		.name           = "LMLBT4",
+		.video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.muxsel         = { 2, 3, 1, 0 },
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.needs_tvaudio  = 0,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_TEKRAM_M205] = {
+		/* Helmroos Harri <harri.helmroos@pp.inet.fi> */
+		.name           = "Tekram M205 PRO",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.svhs           = 2,
+		.needs_tvaudio  = 0,
+		.gpiomask       = 0x68,
+		.muxsel         = { 2, 3, 1},
+		.audiomux       = { 0x68, 0x68, 0x61, 0x61, 0x00 },
+		.pll            = PLL_28,
+	},
 
-/* ---- card 0x4c ---------------------------------- */
-	/* Masaki Suzuki <masaki@btree.org> */
-	.name           = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x140007,
-	.muxsel         = { 2, 3, 1, 1 },
-	.audiomux       = { 0, 1, 2, 3, 4, 0 },
-	.tuner_type     = TUNER_PHILIPS_NTSC,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook     = windvr_audio,
-},{
-	.name           = "GrandTec Multi Capture Card (Bt878)",
-	.video_inputs   = 4,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.gpiomask       = 0,
-	.muxsel         = { 2, 3, 1, 0 },
-	.audiomux       = { 0 },
-	.needs_tvaudio  = 0,
-	.no_msp34xx     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
-	.video_inputs   = 4,
-	.audio_inputs   = 3,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 7,
-	.muxsel         = { 2, 3, 1, 1 },   /* Tuner, SVid, SVHS, SVid to SVHS connector */
-	.audiomux       = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio!
-					* This card lacks external Audio In, so we mute it on Ext. & Int.
-					* The PCB can take a sbx1637/sbx1673, wiring unknown.
-					* This card lacks PCI subsystem ID, sigh.
-					* audiomux=1: lower volume, 2+3: mute
-					* btwincap uses 0x80000/0x80003
-					*/
-	.needs_tvaudio  = 0,
-	.no_msp34xx     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = 5,
-	.tuner_addr	= ADDR_UNSET,
-	/* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
-	radio signal strength indicators work fine. */
-	.has_radio	= 1,
-	/* GPIO Info:
-		GPIO0,1:   HEF4052 A0,A1
-		GPIO2:     HEF4052 nENABLE
-		GPIO3-7:   n.c.
-		GPIO8-13:  IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
-		GPIO14,15: ??
-		GPIO16-21: n.c.
-		GPIO22,23: ??
-		??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
-},{
-	/* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
-	.name           = "DSP Design TCVIDEO",
-	.video_inputs   = 4,
-	.svhs           = -1,
-	.muxsel         = { 2, 3, 1, 0},
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
+		/* ---- card 0x78 ---------------------------------- */
+	[BTTV_BOARD_CONTVFMI] = {
+		/* Javier Cendan Ares <jcendan@lycos.es> */
+		/* bt878 TV + FM without subsystem ID */
+		.name           = "Conceptronic CONTVFMi",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x008007,
+		.muxsel         = { 2, 3, 1, 1 },
+		.audiomux       = { 0, 1, 2, 2, 3 },
+		.needs_tvaudio  = 0,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_remote     = 1,
+		.has_radio      = 1,
+	},
+	[BTTV_BOARD_PICOLO_TETRA_CHIP] = {
+		/*Eric DEBIEF <debief@telemsa.com>*/
+		/*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
+		/* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/
+		/*0x79 in bttv.h*/
+		.name           = "Euresys Picolo Tetra",
+		.video_inputs   = 4,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.gpiomask       = 0,
+		.gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.muxsel         = {2,2,2,2},/*878A input is always MUX0, see above.*/
+		.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+		.pll            = PLL_28,
+		.needs_tvaudio  = 0,
+		.muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_SPIRIT_TV] = {
+		/* Spirit TV Tuner from http://spiritmodems.com.au */
+		/* Stafford Goodsell <surge@goliath.homeunix.org> */
+		.name           = "Spirit TV Tuner",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x0000000f,
+		.muxsel         = { 2, 1, 1 },
+		.audiomux       = { 0x02, 0x00, 0x00, 0x00, 0x00},
+		.tuner_type     = TUNER_TEMIC_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+	},
+	[BTTV_BOARD_AVDVBT_771] = {
+		/* Wolfram Joost <wojo@frokaschwei.de> */
+		.name           = "AVerMedia AVerTV DVB-T 771",
+		.video_inputs   = 2,
+		.svhs           = 1,
+		.tuner          = -1,
+		.tuner_type     = TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.muxsel         = { 3 , 3 },
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+		.has_dvb        = 1,
+		.no_gpioirq     = 1,
+		.has_remote     = 1,
+	},
+		/* ---- card 0x7c ---------------------------------- */
+	[BTTV_BOARD_AVDVBT_761] = {
+		/* Matt Jesson <dvb@jesson.eclipse.co.uk> */
+		/* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
+		.name           = "AverMedia AverTV DVB-T 761",
+		.video_inputs   = 2,
+		.tuner          = -1,
+		.svhs           = 1,
+		.muxsel         = { 3, 1, 2, 0}, /* Comp0, S-Video, ?, ? */
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_dvb        = 1,
+		.no_gpioirq     = 1,
+		.has_remote     = 1,
+	},
+	[BTTV_BOARD_MATRIX_VISIONSQ] = {
+		/* andre.schwarz@matrix-vision.de */
+		.name             = "MATRIX Vision Sigma-SQ",
+		.video_inputs     = 16,
+		.audio_inputs     = 0,
+		.tuner            = -1,
+		.svhs             = -1,
+		.gpiomask         = 0x0,
+		.muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
+				3, 3, 3, 3, 3, 3, 3, 3 },
+		.muxsel_hook      = sigmaSQ_muxsel,
+		.audiomux         = { 0 },
+		.no_msp34xx       = 1,
+		.pll              = PLL_28,
+		.tuner_type       = -1,
+		.tuner_addr	  = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_MATRIX_VISIONSLC] = {
+		/* andre.schwarz@matrix-vision.de */
+		.name             = "MATRIX Vision Sigma-SLC",
+		.video_inputs     = 4,
+		.audio_inputs     = 0,
+		.tuner            = -1,
+		.svhs             = -1,
+		.gpiomask         = 0x0,
+		.muxsel           = { 2, 2, 2, 2 },
+		.muxsel_hook      = sigmaSLC_muxsel,
+		.audiomux         = { 0 },
+		.no_msp34xx       = 1,
+		.pll              = PLL_28,
+		.tuner_type       = -1,
+		.tuner_addr	  = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+		/* BTTV_BOARD_APAC_VIEWCOMP */
+	[BTTV_BOARD_APAC_VIEWCOMP] = {
+		/* Attila Kondoros <attila.kondoros@chello.hu> */
+		/* bt878 TV + FM 0x00000000 subsystem ID */
+		.name           = "APAC Viewcomp 878(AMAX)",
+		.video_inputs   = 2,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = -1,
+		.gpiomask       = 0xFF,
+		.muxsel         = { 2, 3, 1, 1},
+		.audiomux       = { 2, 0, 0, 0, 10},
+		.needs_tvaudio  = 0,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_remote     = 1,   /* miniremote works, see ir-kbd-gpio.c */
+		.has_radio      = 1,   /* not every card has radio */
+	},
 
-	/* ---- card 0x50 ---------------------------------- */
-	.name           = "Hauppauge WinTV PVR",
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.muxsel         = { 2, 0, 1, 1},
-	.needs_tvaudio  = 1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
+		/* ---- card 0x80 ---------------------------------- */
+	[BTTV_BOARD_DVICO_DVBT_LITE] = {
+		/* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
+		.name           = "DViCO FusionHDTV DVB-T Lite",
+		.tuner          = -1,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.pll            = PLL_28,
+		.no_video       = 1,
+		.has_dvb        = 1,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_VGEAR_MYVCD] = {
+		/* Steven <photon38@pchome.com.tw> */
+		.name           = "V-Gear MyVCD",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x3f,
+		.muxsel         = {2, 3, 1, 0},
+		.audiomux       = {0x31, 0x31, 0x31, 0x31, 0x31, 0x31},
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_NTSC_M,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_radio      = 0,
+	#if 0
+		.has_remote     = 1,
+	#endif
+	},
+	[BTTV_BOARD_SUPER_TV] = {
+		/* Rick C <cryptdragoon@gmail.com> */
+		.name           = "Super TV Tuner",
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.muxsel         = { 2, 3, 1, 0},
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0x008007,
+		.audiomux       = { 0, 0x000001,0,0, 0},
+		.needs_tvaudio  = 1,
+		.has_radio      = 1,
+	},
+	[BTTV_BOARD_TIBET_CS16] = {
+		/* Chris Fanning <video4linux@haydon.net> */
+		.name           = "Tibet Systems 'Progress DVR' CS16",
+		.video_inputs   = 16,
+		.audio_inputs   = 0,
+		.tuner          = -1,
+		.svhs           = -1,
+		.muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+		.pll		= PLL_28,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432	= 1,
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.muxsel_hook    = tibetCS16_muxsel,
+	},
+	[BTTV_BOARD_KODICOM_4400R] = {
+		/* Bill Brack <wbrack@mmm.com.hk> */
+		/*
+		* Note that, because of the card's wiring, the "master"
+		* BT878A chip (i.e. the one which controls the analog switch
+		* and must use this card type) is the 2nd one detected.  The
+		* other 3 chips should use card type 0x85, whose description
+		* follows this one.  There is a EEPROM on the card (which is
+		* connected to the I2C of one of those other chips), but is
+		* not currently handled.  There is also a facility for a
+		* "monitor", which is also not currently implemented.
+		*/
+		.name           = "Kodicom 4400R (master)",
+		.video_inputs	= 16,
+		.audio_inputs	= 0,
+		.tuner		= -1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.svhs		= -1,
+		/* GPIO bits 0-9 used for analog switch:
+		*   00 - 03:	camera selector
+		*   04 - 06:	channel (controller) selector
+		*   07:	data (1->on, 0->off)
+		*   08:	strobe
+		*   09:	reset
+		* bit 16 is input from sync separator for the channel
+		*/
+		.gpiomask	= 0x0003ff,
+		.no_gpioirq     = 1,
+		.muxsel		= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.no_tda7432	= 1,
+		.no_tda9875	= 1,
+		.muxsel_hook	= kodicom4400r_muxsel,
+	},
+	[BTTV_BOARD_KODICOM_4400R_SL] = {
+		/* Bill Brack <wbrack@mmm.com.hk> */
+		/* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
+		* one which controls the analog switch, and must use the card type)
+		* is the 2nd one detected.  The other 3 chips should use this card
+		* type
+		*/
+		.name		= "Kodicom 4400R (slave)",
+		.video_inputs	= 16,
+		.audio_inputs	= 0,
+		.tuner		= -1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.svhs		= -1,
+		.gpiomask	= 0x010000,
+		.no_gpioirq     = 1,
+		.muxsel		= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.no_tda7432	= 1,
+		.no_tda9875	= 1,
+		.muxsel_hook	= kodicom4400r_muxsel,
+	},
+		/* ---- card 0x86---------------------------------- */
+	[BTTV_BOARD_ADLINK_RTV24] = {
+		/* Michael Henson <mhenson@clarityvi.com> */
+		/* Adlink RTV24 with special unlock codes */
+		.name           = "Adlink RTV24",
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.muxsel         = { 2, 3, 1, 0},
+		.tuner_type     = -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll            = PLL_28,
+	},
+		/* ---- card 0x87---------------------------------- */
+	[BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = {
+		/* Michael Krufky <mkrufky@m1k.net> */
+		.name           = "DViCO FusionHDTV 5 Lite",
+		.tuner          = 0,
+		.tuner_type     = TUNER_LG_TDVS_H062F,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.svhs           = 2,
+		.muxsel		= { 2, 3, 1 },
+		.gpiomask       = 0x00e00007,
+		.audiomux       = { 0x00400005, 0, 0x00000001, 0, 0x00c00007, 0 },
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.has_dvb        = 1,
+	},
+		/* ---- card 0x88---------------------------------- */
+	[BTTV_BOARD_ACORP_Y878F] = {
+		/* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+		.name		= "Acorp Y878F",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x01fe00,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_YMEC_TVF66T5_B_DFF,
+		.tuner_addr	= 0xc1 >>1,
+		.radio_addr     = 0xc1 >>1,
+		.has_radio	= 1,
+	},
+		/* ---- card 0x89 ---------------------------------- */
+	[BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = {
+		.name           = "Conceptronic CTVFMi v2",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x001c0007,
+		.muxsel         = { 2, 3, 1, 1 },
+		.audiomux       = { 0, 1, 2, 2, 3 },
+		.needs_tvaudio  = 0,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_TENA_9533_DI,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_remote     = 1,
+		.has_radio      = 1,
+	},
+		/* ---- card 0x8a ---------------------------------- */
+	[BTTV_BOARD_PV_BT878P_2E] = {
+		.name          = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
+		.video_inputs  = 5,
+		.audio_inputs  = 1,
+		.tuner         = 0,
+		.svhs          = 3,
+		.gpiomask      = 0x01fe00,
+		.muxsel        = { 2,3,1,1,-1 },
+		.digital_mode  = DIGITAL_MODE_CAMERA,
+		.audiomux      = { 0x00400, 0x10400, 0x04400, 0x80000, 0x12400, 0x46000  },
+		.no_msp34xx    = 1,
+		.pll           = PLL_28,
+		.tuner_type    = TUNER_LG_PAL_FM,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_remote    = 1,
+	},
+		/* ---- card 0x8b ---------------------------------- */
+	[BTTV_BOARD_PV_M4900] = {
+		/* Sérgio Fortier <sergiofortier@yahoo.com.br> */
+		.name           = "Prolink PixelView PlayTV MPEG2 PV-M4900",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x3f,
+		.muxsel         = { 2, 3, 1, 1 },
+		.audiomux       = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+		.no_msp34xx     = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_YMEC_TVF_5533MF,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.has_radio      = 1,
+		.has_remote     = 1,
+	},
+		/* ---- card 0x8c ---------------------------------- */
+	[BTTV_BOARD_OSPREY440]  = {
+		.name           = "Osprey 440",
+		.video_inputs   = 1,
+		.audio_inputs   = 1,
+		.tuner          = -1,
+		.svhs           = 1,
+		.muxsel         = { 2 },
+		.pll            = PLL_28,
+		.tuner_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+		/* ---- card 0x8d ---------------------------------- */
+	[BTTV_BOARD_ASOUND_SKYEYE] = {
+		.name		= "Asound Skyeye PCTV",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 15,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= {2,0,0,0,1},
+		.needs_tvaudio	= 1,
+		.pll		= PLL_28,
+		.tuner_type	= 2,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 
-	.gpiomask       = 7,
-	.audiomux       = {7},
-},{
-	.name           = "IODATA GV-BCTV5/PCI",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x0f0f80,
-	.muxsel         = {2, 3, 1, 0},
-	.audiomux       = {0x030000, 0x010000, 0, 0, 0x020000, 0},
-	.no_msp34xx     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = TUNER_PHILIPS_NTSC_M,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook     = gvbctv5pci_audio,
-	.has_radio      = 1,
-},{
-	.name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
-	.video_inputs   = 4,                  /* id-inputs-clock */
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = 3,
-	.muxsel         = { 3, 2, 0, 1 },
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-	.name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
-	.video_inputs   = 3,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = 2,
-	.muxsel         = { 2, 3, 1 },
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-
-	/* ---- card 0x54 ---------------------------------- */
-	.name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
-	.video_inputs   = 2,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = 1,
-	.muxsel         = { 3, 1 },
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-	.name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
-	.video_inputs   = 1,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.muxsel         = { 0 },
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-	.name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
-	.video_inputs   = 2,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = 1,
-	.muxsel         = { 0, 1 },
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-	.name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
-	.video_inputs   = 1,
-	.audio_inputs   = 1,
-	.tuner          = -1,
-	.svhs           = -1,
-	.muxsel         = { 0 },
-	.pll            = PLL_28,
-	.tuner_type	= UNSET,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-
-	/* ---- card 0x58 ---------------------------------- */
-	.name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
-	.video_inputs   = 2,
-	.audio_inputs   = 1,
-	.tuner          = -1,
-	.svhs           = 1,
-	.muxsel         = { 0, 1 },
-	.pll            = PLL_28,
-	.tuner_type	= UNSET,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-	.name           = "Osprey 210/220",   /* 0x1(A|B)-04C0-C1 */
-	.video_inputs   = 2,
-	.audio_inputs   = 1,
-	.tuner          = -1,
-	.svhs           = 1,
-	.muxsel         = { 2, 3 },
-	.pll            = PLL_28,
-	.tuner_type	= UNSET,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-	.name           = "Osprey 500",   /* 500 */
-	.video_inputs   = 2,
-	.audio_inputs   = 1,
-	.tuner          = -1,
-	.svhs           = 1,
-	.muxsel         = { 2, 3 },
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-	.name           = "Osprey 540",   /* 540 */
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = -1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-
-	/* ---- card 0x5C ---------------------------------- */
-	.name           = "Osprey 2000",  /* 2000 */
-	.video_inputs   = 2,
-	.audio_inputs   = 1,
-	.tuner          = -1,
-	.svhs           = 1,
-	.muxsel         = { 2, 3 },
-	.pll            = PLL_28,
-	.tuner_type	= UNSET,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
-},{
-	/* M G Berberich <berberic@forwiss.uni-passau.de> */
-	.name           = "IDS Eagle",
-	.video_inputs   = 4,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.svhs           = -1,
-	.gpiomask       = 0,
-	.muxsel         = { 0, 1, 2, 3 },
-	.muxsel_hook    = eagle_muxsel,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.pll            = PLL_28,
-},{
-	.name           = "Pinnacle PCTV Sat",
-	.video_inputs   = 2,
-	.audio_inputs   = 0,
-	.svhs           = 1,
-	.tuner          = -1,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.gpiomask       = 0x01,
-	.audiomux       = { 0, 0, 0, 0, 1 },
-	.muxsel         = { 3, 0, 1, 2},
-	.needs_tvaudio  = 0,
-	.pll            = PLL_28,
-	.no_gpioirq     = 1,
-	.has_dvb        = 1,
-},{
-	.name           = "Formac ProTV II (bt878)",
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 3,
-	.gpiomask       = 2,
-	/* TV, Comp1, Composite over SVID con, SVID */
-	.muxsel         = { 2, 3, 1, 1},
-	.audiomux       = { 2, 2, 0, 0, 0 },
-	.pll            = PLL_28,
-	.has_radio      = 1,
-	.tuner_type     = TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-/* sound routing:
-	GPIO=0x00,0x01,0x03: mute (?)
-	0x02: both TV and radio (tuner: FM1216/I)
-	The card has onboard audio connectors labeled "cdrom" and "board",
-	not soldered here, though unknown wiring.
-	Card lacks: external audio in, pci subsystem id.
-*/
-},{
-
-	/* ---- card 0x60 ---------------------------------- */
-	.name           = "MachTV",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = -1,
-	.gpiomask       = 7,
-	.muxsel         = { 2, 3, 1, 1},
-	.audiomux       = { 0, 1, 2, 3, 4},
-	.needs_tvaudio  = 1,
-	.tuner_type     = 5,
-	.tuner_addr	= ADDR_UNSET,
-	.pll            = 1,
-},{
-	.name           = "Euresys Picolo",
-	.video_inputs   = 3,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = 2,
-	.gpiomask       = 0,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.muxsel         = { 2, 0, 1},
-	.pll            = PLL_28,
-	.tuner_type     = UNSET,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Luc Van Hoeylandt <luc@e-magic.be> */
-	.name           = "ProVideo PV150", /* 0x4f */
-	.video_inputs   = 2,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.gpiomask       = 0,
-	.muxsel         = { 2, 3 },
-	.audiomux       = { 0 },
-	.needs_tvaudio  = 0,
-	.no_msp34xx     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = UNSET,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Hiroshi Takekawa <sian@big.or.jp> */
-	/* This card lacks subsystem ID */
-	.name           = "AD-TVK503", /* 0x63 */
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x001e8007,
-	.muxsel         = { 2, 3, 1, 0 },
-	/*                  Tuner, Radio, external, internal, off,  on */
-	.audiomux       = { 0x08,  0x0f,  0x0a,     0x08,     0x0f, 0x08 },
-	.needs_tvaudio  = 0,
-	.no_msp34xx     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = 2,
-	.tuner_addr	= ADDR_UNSET,
-	.audio_hook	= adtvk503_audio,
-},{
-
-	/* ---- card 0x64 ---------------------------------- */
-	.name           = "Hercules Smart TV Stereo",
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x00,
-	.muxsel         = { 2, 3, 1, 1 },
-	.needs_tvaudio  = 1,
-	.no_msp34xx     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = 5,
-	.tuner_addr	= ADDR_UNSET,
-	/* Notes:
-	- card lacks subsystem ID
-	- stereo variant w/ daughter board with tda9874a @0xb0
-	- Audio Routing:
-		always from tda9874 independent of GPIO (?)
-		external line in: unknown
-	- Other chips: em78p156elp @ 0x96 (probably IR remote control)
-		hef4053 (instead 4052) for unknown function
-	*/
-},{
-	.name           = "Pace TV & Radio Card",
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.muxsel         = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */
-	.gpiomask       = 0,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.tuner_type     = 1,
-	.tuner_addr	= ADDR_UNSET,
-	.has_radio      = 1,
-	.pll            = PLL_28,
-	/* Bt878, Bt832, FI1246 tuner; no pci subsystem id
-	only internal line out: (4pin header) RGGL
-	Radio must be decoded by msp3410d (not routed through)*/
-	/*
-	.digital_mode   = DIGITAL_MODE_CAMERA,  todo!
-	*/
-},{
-	/* Chris Willing <chris@vislab.usyd.edu.au> */
-	.name           = "IVC-200",
-	.video_inputs   = 1,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.svhs           = -1,
-	.gpiomask       = 0xdf,
-	.muxsel         = { 2 },
-	.pll            = PLL_28,
-},{
-	.name           = "Grand X-Guard / Trust 814PCI",
-	.video_inputs   = 16,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.tuner_type     = 4,
-	.tuner_addr	= ADDR_UNSET,
-	.gpiomask2      = 0xff,
-	.muxsel         = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
-	.muxsel_hook    = xguard_muxsel,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.pll            = PLL_28,
-},{
-
-	/* ---- card 0x68 ---------------------------------- */
-	.name           = "Nebula Electronics DigiTV",
-	.video_inputs   = 1,
-	.tuner          = -1,
-	.svhs           = -1,
-	.muxsel         = { 2, 3, 1, 0},
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.has_dvb        = 1,
-	.no_gpioirq     = 1,
-},{
-	/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
-	.name           = "ProVideo PV143",
-	.video_inputs   = 4,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.gpiomask       = 0,
-	.muxsel         = { 2, 3, 1, 0 },
-	.audiomux       = { 0 },
-	.needs_tvaudio  = 0,
-	.no_msp34xx     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* M.Klahr@phytec.de */
-	.name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
-	.video_inputs   = 4,
-	.audio_inputs   = 0,
-	.tuner          = -1, /* card has no tuner */
-	.svhs           = 3,
-	.gpiomask       = 0x00,
-	.muxsel         = { 2, 3, 1, 0},
-	.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-	.needs_tvaudio  = 1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name           = "PHYTEC VD-009-X1 Combi (bt878)",
-	.video_inputs   = 4,
-	.audio_inputs   = 0,
-	.tuner          = -1, /* card has no tuner */
-	.svhs           = 3,
-	.gpiomask       = 0x00,
-	.muxsel         = { 2, 3, 1, 1},
-	.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-	.needs_tvaudio  = 1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-
-	/* ---- card 0x6c ---------------------------------- */
-	.name           = "PHYTEC VD-009 MiniDIN (bt878)",
-	.video_inputs   = 10,
-	.audio_inputs   = 0,
-	.tuner          = -1, /* card has no tuner */
-	.svhs           = 9,
-	.gpiomask       = 0x00,
-	.gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
-				via the upper nibble of muxsel. here: used for
-				xternal video-mux */
-	.muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
-	.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-	.needs_tvaudio  = 1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name           = "PHYTEC VD-009 Combi (bt878)",
-	.video_inputs   = 10,
-	.audio_inputs   = 0,
-	.tuner          = -1, /* card has no tuner */
-	.svhs           = 9,
-	.gpiomask       = 0x00,
-	.gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
-				via the upper nibble of muxsel. here: used for
-				xternal video-mux */
-	.muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
-	.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-	.needs_tvaudio  = 1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	.name           = "IVC-100",
-	.video_inputs   = 4,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.svhs           = -1,
-	.gpiomask       = 0xdf,
-	.muxsel         = { 2, 3, 1, 0 },
-	.pll            = PLL_28,
-},{
-	/* IVC-120G - Alan Garfield <alan@fromorbit.com> */
-	.name           = "IVC-120G",
-	.video_inputs   = 16,
-	.audio_inputs   = 0,    /* card has no audio */
-	.tuner          = -1,   /* card has no tuner */
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.svhs           = -1,   /* card has no svhs */
-	.needs_tvaudio  = 0,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.gpiomask       = 0x00,
-	.muxsel         = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-			0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
-	.muxsel_hook    = ivc120_muxsel,
-	.pll            = PLL_28,
-},{
-
-	/* ---- card 0x70 ---------------------------------- */
-	.name           = "pcHDTV HD-2000 TV",
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.muxsel         = { 2, 3, 1, 0},
-	.tuner_type     = TUNER_PHILIPS_ATSC,
-	.tuner_addr	= ADDR_UNSET,
-	.has_dvb        = 1,
-},{
-	.name           = "Twinhan DST + clones",
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.tuner_type     = TUNER_ABSENT,
-	.tuner_addr	= ADDR_UNSET,
-	.no_video       = 1,
-	.has_dvb        = 1,
-},{
-	.name           = "Winfast VC100",
-	.video_inputs   = 3,
-	.audio_inputs   = 0,
-	.svhs           = 1,
-	.tuner          = -1,
-	.muxsel         = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.tuner_type     = TUNER_ABSENT,
-	.tuner_addr	= ADDR_UNSET,
-	.pll            = PLL_28,
-},{
-	.name           = "Teppro TEV-560/InterVision IV-560",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 3,
-	.muxsel         = { 2, 3, 1, 1},
-	.audiomux       = { 1, 1, 1, 1, 0},
-	.needs_tvaudio  = 1,
-	.tuner_type     = TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.pll            = PLL_35,
-},{
-
-	/* ---- card 0x74 ---------------------------------- */
-	.name           = "SIMUS GVC1100",
-	.video_inputs   = 4,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.pll            = PLL_28,
-	.muxsel         = { 2, 2, 2, 2},
-	.gpiomask       = 0x3F,
-	.muxsel_hook    = gvc1100_muxsel,
-},{
-	/* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
-	.name           = "NGS NGSTV+",
-	.video_inputs   = 3,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x008007,
-	.muxsel         = {2, 3, 0, 0},
-	.audiomux       = {0, 0, 0, 0, 0x000003, 0},
-	.pll            = PLL_28,
-	.tuner_type     = TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.has_remote     = 1,
-},{
-	/* http://linuxmedialabs.com */
-	.name           = "LMLBT4",
-	.video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.muxsel         = { 2, 3, 1, 0 },
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.needs_tvaudio  = 0,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Helmroos Harri <harri.helmroos@pp.inet.fi> */
-	.name           = "Tekram M205 PRO",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.tuner_type     = TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.svhs           = 2,
-	.needs_tvaudio  = 0,
-	.gpiomask       = 0x68,
-	.muxsel         = { 2, 3, 1},
-	.audiomux       = { 0x68, 0x68, 0x61, 0x61, 0x00 },
-	.pll            = PLL_28,
-},{
-
-	/* ---- card 0x78 ---------------------------------- */
-	/* Javier Cendan Ares <jcendan@lycos.es> */
-	/* bt878 TV + FM without subsystem ID */
-	.name           = "Conceptronic CONTVFMi",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x008007,
-	.muxsel         = { 2, 3, 1, 1 },
-	.audiomux       = { 0, 1, 2, 2, 3 },
-	.needs_tvaudio  = 0,
-	.pll            = PLL_28,
-	.tuner_type     = TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.has_remote     = 1,
-	.has_radio      = 1,
-},{
-	/*Eric DEBIEF <debief@telemsa.com>*/
-	/*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
-	/* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_PICOLO_TETRA_CHIP*/
-	/*0x79 in bttv.h*/
-	.name           = "Euresys Picolo Tetra",
-	.video_inputs   = 4,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.gpiomask       = 0,
-	.gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.muxsel         = {2,2,2,2},/*878A input is always MUX0, see above.*/
-	.audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-	.pll            = PLL_28,
-	.needs_tvaudio  = 0,
-	.muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Spirit TV Tuner from http://spiritmodems.com.au */
-	/* Stafford Goodsell <surge@goliath.homeunix.org> */
-	.name           = "Spirit TV Tuner",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x0000000f,
-	.muxsel         = { 2, 1, 1 },
-	.audiomux       = { 0x02, 0x00, 0x00, 0x00, 0x00},
-	.tuner_type     = TUNER_TEMIC_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-},{
-	/* Wolfram Joost <wojo@frokaschwei.de> */
-	.name           = "AVerMedia AVerTV DVB-T 771",
-	.video_inputs   = 2,
-	.svhs           = 1,
-	.tuner          = -1,
-	.tuner_type     = TUNER_ABSENT,
-	.tuner_addr	= ADDR_UNSET,
-	.muxsel         = { 3 , 3 },
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.pll            = PLL_28,
-	.has_dvb        = 1,
-	.no_gpioirq     = 1,
-	.has_remote     = 1,
-},{
-	/* ---- card 0x7c ---------------------------------- */
-	/* Matt Jesson <dvb@jesson.eclipse.co.uk> */
-	/* Based on the Nebula card data - added remote and new card number - BTTV_AVDVBT_761, see also ir-kbd-gpio.c */
-	.name           = "AverMedia AverTV DVB-T 761",
-	.video_inputs   = 2,
-	.tuner          = -1,
-	.svhs           = 1,
-	.muxsel         = { 3, 1, 2, 0}, /* Comp0, S-Video, ?, ? */
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.has_dvb        = 1,
-	.no_gpioirq     = 1,
-	.has_remote     = 1,
-},{
-	/* andre.schwarz@matrix-vision.de */
-	.name             = "MATRIX Vision Sigma-SQ",
-	.video_inputs     = 16,
-	.audio_inputs     = 0,
-	.tuner            = -1,
-	.svhs             = -1,
-	.gpiomask         = 0x0,
-	.muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
-			3, 3, 3, 3, 3, 3, 3, 3 },
-	.muxsel_hook      = sigmaSQ_muxsel,
-	.audiomux         = { 0 },
-	.no_msp34xx       = 1,
-	.pll              = PLL_28,
-	.tuner_type       = -1,
-	.tuner_addr	  = ADDR_UNSET,
-},{
-	/* andre.schwarz@matrix-vision.de */
-	.name             = "MATRIX Vision Sigma-SLC",
-	.video_inputs     = 4,
-	.audio_inputs     = 0,
-	.tuner            = -1,
-	.svhs             = -1,
-	.gpiomask         = 0x0,
-	.muxsel           = { 2, 2, 2, 2 },
-	.muxsel_hook      = sigmaSLC_muxsel,
-	.audiomux         = { 0 },
-	.no_msp34xx       = 1,
-	.pll              = PLL_28,
-	.tuner_type       = -1,
-	.tuner_addr	  = ADDR_UNSET,
-},{
-	/* BTTV_APAC_VIEWCOMP */
-	/* Attila Kondoros <attila.kondoros@chello.hu> */
-	/* bt878 TV + FM 0x00000000 subsystem ID */
-	.name           = "APAC Viewcomp 878(AMAX)",
-	.video_inputs   = 2,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = -1,
-	.gpiomask       = 0xFF,
-	.muxsel         = { 2, 3, 1, 1},
-	.audiomux       = { 2, 0, 0, 0, 10},
-	.needs_tvaudio  = 0,
-	.pll            = PLL_28,
-	.tuner_type     = TUNER_PHILIPS_PAL,
-	.tuner_addr	= ADDR_UNSET,
-	.has_remote     = 1,   /* miniremote works, see ir-kbd-gpio.c */
-	.has_radio      = 1,   /* not every card has radio */
-},{
-
-	/* ---- card 0x80 ---------------------------------- */
-	/* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
-	.name           = "DViCO FusionHDTV DVB-T Lite",
-	.tuner          = -1,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-	.pll            = PLL_28,
-	.no_video       = 1,
-	.has_dvb        = 1,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-},{
-	/* Steven <photon38@pchome.com.tw> */
-	.name           = "V-Gear MyVCD",
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.gpiomask       = 0x3f,
-	.muxsel         = {2, 3, 1, 0},
-	.audiomux       = {0x31, 0x31, 0x31, 0x31, 0x31, 0x31},
-	.no_msp34xx     = 1,
-	.pll            = PLL_28,
-	.tuner_type     = TUNER_PHILIPS_NTSC_M,
-	.tuner_addr	= ADDR_UNSET,
-	.has_radio      = 0,
-},{
-	/* Rick C <cryptdragoon@gmail.com> */
-	.name           = "Super TV Tuner",
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.muxsel         = { 2, 3, 1, 0},
-	.tuner_type     = TUNER_PHILIPS_NTSC,
-	.tuner_addr	= ADDR_UNSET,
-	.gpiomask       = 0x008007,
-	.audiomux       = { 0, 0x000001,0,0, 0},
-	.needs_tvaudio  = 1,
-	.has_radio      = 1,
-},{
-	/* Chris Fanning <video4linux@haydon.net> */
-	.name           = "Tibet Systems 'Progress DVR' CS16",
-	.video_inputs   = 16,
-	.audio_inputs   = 0,
-	.tuner          = -1,
-	.svhs           = -1,
-	.muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
-	.pll		= PLL_28,
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432	= 1,
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.muxsel_hook    = tibetCS16_muxsel,
-},
-{
-	/* Bill Brack <wbrack@mmm.com.hk> */
-	/*
-	* Note that, because of the card's wiring, the "master"
-	* BT878A chip (i.e. the one which controls the analog switch
-	* and must use this card type) is the 2nd one detected.  The
-	* other 3 chips should use card type 0x85, whose description
-	* follows this one.  There is a EEPROM on the card (which is
-	* connected to the I2C of one of those other chips), but is
-	* not currently handled.  There is also a facility for a
-	* "monitor", which is also not currently implemented.
-	*/
-	.name           = "Kodicom 4400R (master)",
-	.video_inputs	= 16,
-	.audio_inputs	= 0,
-	.tuner		= -1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-	.svhs		= -1,
-	/* GPIO bits 0-9 used for analog switch:
-	*   00 - 03:	camera selector
-	*   04 - 06:	channel (controller) selector
-	*   07:	data (1->on, 0->off)
-	*   08:	strobe
-	*   09:	reset
-	* bit 16 is input from sync separator for the channel
-	*/
-	.gpiomask	= 0x0003ff,
-	.no_gpioirq     = 1,
-	.muxsel		= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
-	.pll		= PLL_28,
-	.no_msp34xx	= 1,
-	.no_tda7432	= 1,
-	.no_tda9875	= 1,
-	.muxsel_hook	= kodicom4400r_muxsel,
-},
-{
-	/* Bill Brack <wbrack@mmm.com.hk> */
-	/* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
-	* one which controls the analog switch, and must use the card type)
-	* is the 2nd one detected.  The other 3 chips should use this card
-	* type
-	*/
-	.name		= "Kodicom 4400R (slave)",
-	.video_inputs	= 16,
-	.audio_inputs	= 0,
-	.tuner		= -1,
-	.tuner_type	= -1,
-	.tuner_addr	= ADDR_UNSET,
-	.svhs		= -1,
-	.gpiomask	= 0x010000,
-	.no_gpioirq     = 1,
-	.muxsel		= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
-	.pll		= PLL_28,
-	.no_msp34xx	= 1,
-	.no_tda7432	= 1,
-	.no_tda9875	= 1,
-	.muxsel_hook	= kodicom4400r_muxsel,
-},
-{
-	/* ---- card 0x86---------------------------------- */
-	/* Michael Henson <mhenson@clarityvi.com> */
-	/* Adlink RTV24 with special unlock codes */
-	.name           = "Adlink RTV24",
-	.video_inputs   = 4,
-	.audio_inputs   = 1,
-	.tuner          = 0,
-	.svhs           = 2,
-	.muxsel         = { 2, 3, 1, 0},
-	.tuner_type     = -1,
-	.tuner_addr	= ADDR_UNSET,
-	.pll            = PLL_28,
-},
-{
-	/* ---- card 0x87---------------------------------- */
-	/* Michael Krufky <mkrufky@m1k.net> */
-	.name           = "DViCO FusionHDTV 5 Lite",
-	.tuner          = 0,
-	.tuner_type     = TUNER_LG_TDVS_H062F,
-	.tuner_addr	= ADDR_UNSET,
-	.video_inputs   = 3,
-	.audio_inputs   = 1,
-	.svhs           = 2,
-	.muxsel		= { 2, 3, 1 },
-	.gpiomask       = 0x00e00007,
-	.audiomux       = { 0x00400005, 0, 0x00000001, 0, 0x00c00007, 0 },
-	.no_msp34xx     = 1,
-	.no_tda9875     = 1,
-	.no_tda7432     = 1,
-},{
-	/* ---- card 0x88---------------------------------- */
-	/* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
-	.name		= "Acorp Y878F",
-	.video_inputs	= 3,
-	.audio_inputs	= 1,
-	.tuner		= 0,
-	.svhs		= 2,
-	.gpiomask	= 0x01fe00,
-	.muxsel		= { 2, 3, 1, 1},
-	.audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
-	.needs_tvaudio	= 1,
-	.pll		= PLL_28,
-	.tuner_type	= TUNER_YMEC_TVF66T5_B_DFF,
-	.tuner_addr	= 0xc1 >>1,
-	.has_radio	= 1,
-}};
+};
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
 
@@ -2461,7 +2840,7 @@
 			       btv->c.nr, btv->cardid & 0xffff,
 			       (btv->cardid >> 16) & 0xffff);
 			printk(KERN_DEBUG "please mail id, board name and "
-			       "the correct card= insmod option to kraxel@bytesex.org\n");
+			       "the correct card= insmod option to video4linux-list@redhat.com\n");
 		}
 	}
 
@@ -2510,11 +2889,11 @@
 	int type = -1;
 
 	if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13))
-		type = BTTV_MODTEC_205;
+		type = BTTV_BOARD_MODTEC_205;
 	else if (0 == strncmp(eeprom_data+20,"Picolo",7))
-		type = BTTV_EURESYS_PICOLO;
+		type = BTTV_BOARD_EURESYS_PICOLO;
 	else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
-                type = BTTV_HAUPPAUGE; /* old bt848 */
+		type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */
 
 	if (-1 != type) {
 		btv->c.type = type;
@@ -2548,7 +2927,7 @@
 	switch(ttype) {
 	case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
 		break;
-        case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
+	case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
 		break;
 	case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
 		break;
@@ -2564,7 +2943,7 @@
 	has_radio	    =   gpio & 0x400000;
 	/*   unknown                   0x200000;
 	 *   unknown2                  0x100000; */
-        is_capture_only     = !(gpio & 0x008000); /* GPIO15 */
+	is_capture_only     = !(gpio & 0x008000); /* GPIO15 */
 	has_tda9820_tda9821 = !(gpio & 0x004000);
 	is_lr90             = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */
 	/*
@@ -2601,7 +2980,7 @@
 	char *info;
 
 	gpio_inout(0xffffff, 0);
-        gpio = gpio_read();
+	gpio = gpio_read();
 	id   = ((gpio>>10) & 63) -1;
 	msp  = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
 	if (id < 32) {
@@ -2620,10 +2999,10 @@
 			btv->has_radio = 0;
 		}
 		if (-1 != msp) {
-			if (btv->c.type == BTTV_MIRO)
-				btv->c.type = BTTV_MIROPRO;
-			if (btv->c.type == BTTV_PINNACLE)
-				btv->c.type = BTTV_PINNACLEPRO;
+			if (btv->c.type == BTTV_BOARD_MIRO)
+				btv->c.type = BTTV_BOARD_MIROPRO;
+			if (btv->c.type == BTTV_BOARD_PINNACLE)
+				btv->c.type = BTTV_BOARD_PINNACLEPRO;
 		}
 		printk(KERN_INFO
 		       "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
@@ -2664,7 +3043,7 @@
 			break;
 		}
 		if (-1 != msp)
-			btv->c.type = BTTV_PINNACLEPRO;
+			btv->c.type = BTTV_BOARD_PINNACLEPRO;
 		printk(KERN_INFO
 		       "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
 		       btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
@@ -2712,7 +3091,7 @@
 
 static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
 {
-        static const int masks[] = {0x30, 0x01, 0x12, 0x23};
+	static const int masks[] = {0x30, 0x01, 0x12, 0x23};
 	gpio_write(masks[input%4]);
 }
 
@@ -2778,26 +3157,27 @@
 void __devinit bttv_init_card1(struct bttv *btv)
 {
 	switch (btv->c.type) {
-	case BTTV_HAUPPAUGE:
-	case BTTV_HAUPPAUGE878:
-                boot_msp34xx(btv,5);
+	case BTTV_BOARD_HAUPPAUGE:
+	case BTTV_BOARD_HAUPPAUGE878:
+		boot_msp34xx(btv,5);
 		break;
-	case BTTV_VOODOOTV_FM:
-                boot_msp34xx(btv,20);
+	case BTTV_BOARD_VOODOOTV_FM:
+		boot_msp34xx(btv,20);
 		break;
-	case BTTV_AVERMEDIA98:
+	case BTTV_BOARD_AVERMEDIA98:
 		boot_msp34xx(btv,11);
 		break;
-	case BTTV_HAUPPAUGEPVR:
+	case BTTV_BOARD_HAUPPAUGEPVR:
 		pvr_boot(btv);
 		break;
-	case BTTV_TWINHAN_DST:
-	case BTTV_AVDVBT_771:
+	case BTTV_BOARD_TWINHAN_DST:
+	case BTTV_BOARD_AVDVBT_771:
+	case BTTV_BOARD_PINNACLESAT:
 		btv->use_i2c_hw = 1;
 		break;
-        case BTTV_ADLINK_RTV24:
-                init_RTV24( btv );
-                break;
+	case BTTV_BOARD_ADLINK_RTV24:
+		init_RTV24( btv );
+		break;
 
 	}
 	if (!bttv_tvcards[btv->c.type].has_dvb)
@@ -2810,53 +3190,53 @@
 	int tda9887;
 	int addr=ADDR_UNSET;
 
-        btv->tuner_type = -1;
+	btv->tuner_type = -1;
 
-	if (BTTV_UNKNOWN == btv->c.type) {
+	if (BTTV_BOARD_UNKNOWN == btv->c.type) {
 		bttv_readee(btv,eeprom_data,0xa0);
 		identify_by_eeprom(btv,eeprom_data);
 	}
 
 	switch (btv->c.type) {
-	case BTTV_MIRO:
-	case BTTV_MIROPRO:
-	case BTTV_PINNACLE:
-	case BTTV_PINNACLEPRO:
+	case BTTV_BOARD_MIRO:
+	case BTTV_BOARD_MIROPRO:
+	case BTTV_BOARD_PINNACLE:
+	case BTTV_BOARD_PINNACLEPRO:
 		/* miro/pinnacle */
 		miro_pinnacle_gpio(btv);
 		break;
-	case BTTV_FLYVIDEO_98:
-	case BTTV_MAXI:
-	case BTTV_LIFE_FLYKIT:
-	case BTTV_FLYVIDEO:
-	case BTTV_TYPHOON_TVIEW:
-	case BTTV_CHRONOS_VS2:
-	case BTTV_FLYVIDEO_98FM:
-	case BTTV_FLYVIDEO2000:
-	case BTTV_FLYVIDEO98EZ:
-	case BTTV_CONFERENCETV:
-	case BTTV_LIFETEC_9415:
+	case BTTV_BOARD_FLYVIDEO_98:
+	case BTTV_BOARD_MAXI:
+	case BTTV_BOARD_LIFE_FLYKIT:
+	case BTTV_BOARD_FLYVIDEO:
+	case BTTV_BOARD_TYPHOON_TVIEW:
+	case BTTV_BOARD_CHRONOS_VS2:
+	case BTTV_BOARD_FLYVIDEO_98FM:
+	case BTTV_BOARD_FLYVIDEO2000:
+	case BTTV_BOARD_FLYVIDEO98EZ:
+	case BTTV_BOARD_CONFERENCETV:
+	case BTTV_BOARD_LIFETEC_9415:
 		flyvideo_gpio(btv);
 		break;
-	case BTTV_HAUPPAUGE:
-	case BTTV_HAUPPAUGE878:
-	case BTTV_HAUPPAUGEPVR:
+	case BTTV_BOARD_HAUPPAUGE:
+	case BTTV_BOARD_HAUPPAUGE878:
+	case BTTV_BOARD_HAUPPAUGEPVR:
 		/* pick up some config infos from the eeprom */
 		bttv_readee(btv,eeprom_data,0xa0);
-                hauppauge_eeprom(btv);
+		hauppauge_eeprom(btv);
 		break;
-	case BTTV_AVERMEDIA98:
-	case BTTV_AVPHONE98:
+	case BTTV_BOARD_AVERMEDIA98:
+	case BTTV_BOARD_AVPHONE98:
 		bttv_readee(btv,eeprom_data,0xa0);
 		avermedia_eeprom(btv);
 		break;
-	case BTTV_PXC200:
+	case BTTV_BOARD_PXC200:
 		init_PXC200(btv);
 		break;
-	case BTTV_PICOLO_TETRA_CHIP:
+	case BTTV_BOARD_PICOLO_TETRA_CHIP:
 		picolo_tetra_init(btv);
 		break;
-	case BTTV_VHX:
+	case BTTV_BOARD_VHX:
 		btv->has_radio    = 1;
 		btv->has_matchbox = 1;
 		btv->mbox_we      = 0x20;
@@ -2865,58 +3245,58 @@
 		btv->mbox_data    = 0x10;
 		btv->mbox_mask    = 0x38;
 		break;
-	case BTTV_VOBIS_BOOSTAR:
-	case BTTV_TERRATV:
+	case BTTV_BOARD_VOBIS_BOOSTAR:
+	case BTTV_BOARD_TERRATV:
 		terratec_active_radio_upgrade(btv);
 		break;
-	case BTTV_MAGICTVIEW061:
+	case BTTV_BOARD_MAGICTVIEW061:
 		if (btv->cardid == 0x3002144f) {
 			btv->has_radio=1;
 			printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
 		}
 		break;
-       case BTTV_STB2:
-                if (btv->cardid == 0x3060121a) {
+       case BTTV_BOARD_STB2:
+		if (btv->cardid == 0x3060121a) {
 			/* Fix up entry for 3DFX VoodooTV 100,
 			   which is an OEM STB card variant. */
 			btv->has_radio=0;
 			btv->tuner_type=TUNER_TEMIC_NTSC;
 		}
 		break;
-	case BTTV_OSPREY1x0:
-	case BTTV_OSPREY1x0_848:
-	case BTTV_OSPREY101_848:
-	case BTTV_OSPREY1x1:
-	case BTTV_OSPREY1x1_SVID:
-	case BTTV_OSPREY2xx:
-	case BTTV_OSPREY2x0_SVID:
-	case BTTV_OSPREY2x0:
-	case BTTV_OSPREY500:
-	case BTTV_OSPREY540:
-	case BTTV_OSPREY2000:
+	case BTTV_BOARD_OSPREY1x0:
+	case BTTV_BOARD_OSPREY1x0_848:
+	case BTTV_BOARD_OSPREY101_848:
+	case BTTV_BOARD_OSPREY1x1:
+	case BTTV_BOARD_OSPREY1x1_SVID:
+	case BTTV_BOARD_OSPREY2xx:
+	case BTTV_BOARD_OSPREY2x0_SVID:
+	case BTTV_BOARD_OSPREY2x0:
+	case BTTV_BOARD_OSPREY500:
+	case BTTV_BOARD_OSPREY540:
+	case BTTV_BOARD_OSPREY2000:
 		bttv_readee(btv,eeprom_data,0xa0);
-                osprey_eeprom(btv);
+		osprey_eeprom(btv);
 		break;
-	case BTTV_IDS_EAGLE:
+	case BTTV_BOARD_IDS_EAGLE:
 		init_ids_eagle(btv);
 		break;
-	case BTTV_MODTEC_205:
+	case BTTV_BOARD_MODTEC_205:
 		bttv_readee(btv,eeprom_data,0xa0);
 		modtec_eeprom(btv);
 		break;
-	case BTTV_LMLBT4:
+	case BTTV_BOARD_LMLBT4:
 		init_lmlbt4x(btv);
 		break;
-	case BTTV_TIBET_CS16:
+	case BTTV_BOARD_TIBET_CS16:
 		tibetCS16_init(btv);
 		break;
-	case BTTV_KODICOM_4400R:
+	case BTTV_BOARD_KODICOM_4400R:
 		kodicom4400r_init(btv);
 		break;
 	}
 
 	/* pll configuration */
-        if (!(btv->id==848 && btv->revision==0x11)) {
+	if (!(btv->id==848 && btv->revision==0x11)) {
 		/* defaults from card list */
 		if (PLL_28 == bttv_tvcards[btv->c.type].pll) {
 			btv->pll.pll_ifreq=28636363;
@@ -2927,26 +3307,26 @@
 			btv->pll.pll_crystal=BT848_IFORM_XT1;
 		}
 		/* insmod options can override */
-                switch (pll[btv->c.nr]) {
-                case 0: /* none */
+		switch (pll[btv->c.nr]) {
+		case 0: /* none */
 			btv->pll.pll_crystal = 0;
 			btv->pll.pll_ifreq   = 0;
 			btv->pll.pll_ofreq   = 0;
-                        break;
-                case 1: /* 28 MHz */
+			break;
+		case 1: /* 28 MHz */
 		case 28:
-                        btv->pll.pll_ifreq   = 28636363;
+			btv->pll.pll_ifreq   = 28636363;
 			btv->pll.pll_ofreq   = 0;
-                        btv->pll.pll_crystal = BT848_IFORM_XT0;
-                        break;
-                case 2: /* 35 MHz */
+			btv->pll.pll_crystal = BT848_IFORM_XT0;
+			break;
+		case 2: /* 35 MHz */
 		case 35:
-                        btv->pll.pll_ifreq   = 35468950;
+			btv->pll.pll_ifreq   = 35468950;
 			btv->pll.pll_ofreq   = 0;
-                        btv->pll.pll_crystal = BT848_IFORM_XT1;
-                        break;
-                }
-        }
+			btv->pll.pll_crystal = BT848_IFORM_XT1;
+			break;
+		}
+	}
 	btv->pll.pll_current = -1;
 
 	/* tuner configuration (from card list / autodetect / insmod option) */
@@ -2955,23 +3335,26 @@
 
 	if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
 		if(UNSET == btv->tuner_type)
-        	       	btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
+			btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
 	if (UNSET != tuner[btv->c.nr])
 		btv->tuner_type = tuner[btv->c.nr];
 	printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
-	if (btv->pinnacle_id != UNSET)
-		bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
-				      &btv->pinnacle_id);
-	if (btv->tuner_type != UNSET) {
-	        struct tuner_setup tun_setup;
 
-	        tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+	if (btv->tuner_type != UNSET) {
+		struct tuner_setup tun_setup;
+
+		tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
 		tun_setup.type = btv->tuner_type;
 		tun_setup.addr = addr;
 
 		bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
 	}
 
+	if (btv->pinnacle_id != UNSET) {
+		bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
+							&btv->pinnacle_id);
+	}
+
 	btv->svhs = bttv_tvcards[btv->c.type].svhs;
 	if (svhs[btv->c.nr] != UNSET)
 		btv->svhs = svhs[btv->c.nr];
@@ -2982,8 +3365,8 @@
 		btv->has_radio=1;
 	if (bttv_tvcards[btv->c.type].has_remote)
 		btv->has_remote=1;
-	if (bttv_tvcards[btv->c.type].no_gpioirq)
-		btv->gpioirq=0;
+	if (!bttv_tvcards[btv->c.type].no_gpioirq)
+		btv->gpioirq=1;
 	if (bttv_tvcards[btv->c.type].audio_hook)
 		btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
 
@@ -3024,6 +3407,9 @@
 	if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
 	    bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0)
 		tda9887 = 1;
+	/* Hybrid DVB card, DOES have a tda9887 */
+	if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
+		tda9887 = 1;
 	if((btv->tuner_type == TUNER_PHILIPS_FM1216ME_MK3) ||
 	   (btv->tuner_type == TUNER_PHILIPS_FM1236_MK3) ||
 	   (btv->tuner_type == TUNER_PHILIPS_FM1256_IH3) ||
@@ -3045,11 +3431,11 @@
 	} else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) {
 		btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I;
 		printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                       btv->c.nr,&eeprom_data[0x1e]);
-        } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
-                btv->tuner_type=TUNER_PHILIPS_NTSC;
-                printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                       btv->c.nr,&eeprom_data[0x1e]);
+		       btv->c.nr,&eeprom_data[0x1e]);
+	} else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
+		btv->tuner_type=TUNER_PHILIPS_NTSC;
+		printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
+		       btv->c.nr,&eeprom_data[0x1e]);
 	} else {
 		printk("bttv%d: Modtec: Unknown TunerString: %s\n",
 		       btv->c.nr,&eeprom_data[0x1e]);
@@ -3114,7 +3500,7 @@
 static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
 {
 	u32 n;
-  	u8 bits;
+	u8 bits;
 	int i;
 
 	gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG);
@@ -3150,19 +3536,19 @@
 
 static int __devinit pvr_boot(struct bttv *btv)
 {
-        const struct firmware *fw_entry;
+	const struct firmware *fw_entry;
 	int rc;
 
 	rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev);
 	if (rc != 0) {
 		printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
 		       btv->c.nr);
-                return rc;
-        }
+		return rc;
+	}
 	rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
 	printk(KERN_INFO "bttv%d: altera firmware upload %s\n",
 	       btv->c.nr, (rc < 0) ? "failed" : "ok");
-        release_firmware(fw_entry);
+	release_firmware(fw_entry);
 	return rc;
 }
 
@@ -3176,33 +3562,33 @@
        unsigned long serial = 0;
 
        if (btv->c.type == 0) {
-               /* this might be an antique... check for MMAC label in eeprom */
-               if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
-                       unsigned char checksum = 0;
-                       for (i =0; i<21; i++)
+	       /* this might be an antique... check for MMAC label in eeprom */
+	       if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
+		       unsigned char checksum = 0;
+		       for (i =0; i<21; i++)
 			       checksum += ee[i];
-                       if (checksum != ee[21])
+		       if (checksum != ee[21])
 			       return;
-		       btv->c.type = BTTV_OSPREY1x0_848;
+		       btv->c.type = BTTV_BOARD_OSPREY1x0_848;
 		       for (i = 12; i < 21; i++)
 			       serial *= 10, serial += ee[i] - '0';
-               }
+	       }
        } else {
 	       unsigned short type;
-               int offset = 4*16;
+	       int offset = 4*16;
 
-               for(; offset < 8*16; offset += 16) {
-                       unsigned short checksum = 0;
-                       /* verify the checksum */
-                       for(i = 0; i<14; i++) checksum += ee[i+offset];
-                               checksum = ~checksum;  /* no idea why */
-                               if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
-                                   ((checksum & 0x0FF) == ee[offset+15])) {
-                               break;
-                       }
-               }
+	       for(; offset < 8*16; offset += 16) {
+		       unsigned short checksum = 0;
+		       /* verify the checksum */
+		       for(i = 0; i<14; i++) checksum += ee[i+offset];
+			       checksum = ~checksum;  /* no idea why */
+			       if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
+				   ((checksum & 0x0FF) == ee[offset+15])) {
+			       break;
+		       }
+	       }
 
-               if (offset >= 8*16)
+	       if (offset >= 8*16)
 		       return;
 
 	       /* found a valid descriptor */
@@ -3212,47 +3598,47 @@
 
 	       /* 848 based */
 	       case 0x0004:
-		       btv->c.type = BTTV_OSPREY1x0_848;
+		       btv->c.type = BTTV_BOARD_OSPREY1x0_848;
 		       break;
 	       case 0x0005:
-		       btv->c.type = BTTV_OSPREY101_848;
+		       btv->c.type = BTTV_BOARD_OSPREY101_848;
 		       break;
 
-               /* 878 based */
+	       /* 878 based */
 	       case 0x0012:
 	       case 0x0013:
-		       btv->c.type = BTTV_OSPREY1x0;
+		       btv->c.type = BTTV_BOARD_OSPREY1x0;
 		       break;
 	       case 0x0014:
 	       case 0x0015:
-		       btv->c.type = BTTV_OSPREY1x1;
+		       btv->c.type = BTTV_BOARD_OSPREY1x1;
 		       break;
 	       case 0x0016:
 	       case 0x0017:
 	       case 0x0020:
-		       btv->c.type = BTTV_OSPREY1x1_SVID;
+		       btv->c.type = BTTV_BOARD_OSPREY1x1_SVID;
 		       break;
 	       case 0x0018:
 	       case 0x0019:
 	       case 0x001E:
 	       case 0x001F:
-		       btv->c.type = BTTV_OSPREY2xx;
+		       btv->c.type = BTTV_BOARD_OSPREY2xx;
 		       break;
 	       case 0x001A:
 	       case 0x001B:
-		       btv->c.type = BTTV_OSPREY2x0_SVID;
+		       btv->c.type = BTTV_BOARD_OSPREY2x0_SVID;
 		       break;
 	       case 0x0040:
-		       btv->c.type = BTTV_OSPREY500;
+		       btv->c.type = BTTV_BOARD_OSPREY500;
 		       break;
 	       case 0x0050:
 	       case 0x0056:
-		       btv->c.type = BTTV_OSPREY540;
+		       btv->c.type = BTTV_BOARD_OSPREY540;
 		       /* bttv_osprey_540_init(btv); */
 		       break;
 	       case 0x0060:
 	       case 0x0070:
-		       btv->c.type = BTTV_OSPREY2x0;
+		       btv->c.type = BTTV_BOARD_OSPREY2x0;
 		       /* enable output on select control lines */
 		       gpio_inout(0xffffff,0x000303);
 		       break;
@@ -3274,27 +3660,27 @@
 /* AVermedia specific stuff, from  bktr_card.c                             */
 
 static int tuner_0_table[] = {
-        TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL /* PAL-BG*/,
-        TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL /* PAL-I*/,
-        TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
-        TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
-        TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
+	TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL /* PAL-BG*/,
+	TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL /* PAL-I*/,
+	TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
+	TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
+	TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
 	TUNER_PHILIPS_FM1216ME_MK3 };
 
 static int tuner_1_table[] = {
-        TUNER_TEMIC_NTSC,  TUNER_TEMIC_PAL,
+	TUNER_TEMIC_NTSC,  TUNER_TEMIC_PAL,
 	TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
 	TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
-        TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
-        TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
+	TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
+	TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
 
 static void __devinit avermedia_eeprom(struct bttv *btv)
 {
-        int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+	int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
 
 	tuner_make      = (eeprom_data[0x41] & 0x7);
-        tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
-        tuner_format    = (eeprom_data[0x42] & 0xf0) >> 4;
+	tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
+	tuner_format    = (eeprom_data[0x42] & 0xf0) >> 4;
 	btv->has_remote = (eeprom_data[0x42] & 0x01);
 
 	if (tuner_make == 0 || tuner_make == 2)
@@ -3325,13 +3711,13 @@
 {
 	/* fix up our card entry */
 	if(norm==VIDEO_MODE_NTSC) {
-		bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x957fff;
-		bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x957fff;
+		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x957fff;
+		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x957fff;
 		dprintk("bttv_tda9880_setnorm to NTSC\n");
 	}
 	else {
-	        bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x947fff;
-                bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x947fff;
+		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x947fff;
+		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x947fff;
 		dprintk("bttv_tda9880_setnorm to PAL\n");
 	}
 	/* set GPIO according */
@@ -3342,7 +3728,7 @@
 
 /*
  * reset/enable the MSP on some Hauppauge cards
- * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
+ * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
  *
  * Hauppauge:  pin  5
  * Voodoo:     pin 20
@@ -3353,7 +3739,7 @@
 
 	gpio_inout(mask,mask);
 	gpio_bits(mask,0);
-        udelay(2500);
+	udelay(2500);
 	gpio_bits(mask,mask);
 
 	if (bttv_gpio)
@@ -3429,7 +3815,7 @@
 	udelay(10);
 	gpio_write(1<<2);
 
-       	for (i = 0; i < ARRAY_SIZE(vals); i++) {
+	for (i = 0; i < ARRAY_SIZE(vals); i++) {
 		tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
 		if (tmp != -1) {
 			printk(KERN_INFO
@@ -3872,30 +4258,30 @@
 static void
 lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
 {
-        int val = 0;
+	int val = 0;
 
-        if (gpio_read() & 0x4000) {
+	if (gpio_read() & 0x4000) {
 		v->mode = VIDEO_SOUND_MONO;
 		return;
 	}
 
-        if (set) {
-                if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
-                        val = 0x0080;
+	if (set) {
+		if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
+			val = 0x0080;
 		if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
-                        val = 0x0880;
-                if ((v->mode & VIDEO_SOUND_LANG1) ||
+			val = 0x0880;
+		if ((v->mode & VIDEO_SOUND_LANG1) ||
 		    (v->mode & VIDEO_SOUND_MONO))
 			val = 0;
 		gpio_bits(0x0880, val);
-                if (bttv_gpio)
-                        bttv_gpio_tracking(btv,"lt9415");
-        } else {
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"lt9415");
+	} else {
 		/* autodetect doesn't work with this card :-( */
-                v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
 			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-                return;
-        }
+		return;
+	}
 }
 
 /* TDA9821 on TerraTV+ Bt848, Bt878 */
@@ -4018,26 +4404,26 @@
 static void
 windvr_audio(struct bttv *btv, struct video_audio *v, int set)
 {
-        unsigned long val = 0;
+	unsigned long val = 0;
 
-        if (set) {
-                if (v->mode & VIDEO_SOUND_MONO)
-                        val = 0x040000;
-                if (v->mode & VIDEO_SOUND_LANG1)
-                        val = 0;
-                if (v->mode & VIDEO_SOUND_LANG2)
-                        val = 0x100000;
-                if (v->mode & VIDEO_SOUND_STEREO)
-                        val = 0;
-                if (val) {
+	if (set) {
+		if (v->mode & VIDEO_SOUND_MONO)
+			val = 0x040000;
+		if (v->mode & VIDEO_SOUND_LANG1)
+			val = 0;
+		if (v->mode & VIDEO_SOUND_LANG2)
+			val = 0x100000;
+		if (v->mode & VIDEO_SOUND_STEREO)
+			val = 0;
+		if (val) {
 			gpio_bits(0x140000, val);
-                        if (bttv_gpio)
-                                bttv_gpio_tracking(btv,"windvr");
-                }
-        } else {
-                v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                          VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-        }
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"windvr");
+		}
+	} else {
+		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	}
 }
 
 /*
@@ -4280,10 +4666,10 @@
 static void xguard_muxsel(struct bttv *btv, unsigned int input)
 {
 	static const int masks[] = {
-                ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
-                ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
-                ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
-                ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
+		ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
+		ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
+		ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
+		ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
 	};
 	gpio_write(masks[input%16]);
 }
@@ -4388,10 +4774,10 @@
 
 static void PXC200_muxsel(struct bttv *btv, unsigned int input)
 {
-        int rc;
+	int rc;
 	long mux;
 	int bitmask;
-        unsigned char buf[2];
+	unsigned char buf[2];
 
 	/* Read PIC config to determine if this is a PXC200F */
 	/* PX_I2C_CMD_CFG*/
@@ -4421,14 +4807,14 @@
 	/* bitmask=0x30f; */
 	bitmask=0x302;
 	/* check whether we have a PXC200A */
- 	if (btv->cardid == PX_PXC200A_CARDID)  {
+	if (btv->cardid == PX_PXC200A_CARDID)  {
 	   bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */
 	   bitmask |= 7<<4; /* the DAC */
 	}
 	btwrite(bitmask, BT848_GPIO_OUT_EN);
 
 	bitmask = btread(BT848_GPIO_DATA);
- 	if (btv->cardid == PX_PXC200A_CARDID)
+	if (btv->cardid == PX_PXC200A_CARDID)
 	  bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7);
 	else /* older device */
 	  bitmask = (bitmask & ~0x300) | ((mux & 3) << 8);
@@ -4441,7 +4827,7 @@
 	 *
 	 * needed because bttv-driver sets mux before calling this function
 	 */
- 	if (btv->cardid == PX_PXC200A_CARDID)
+	if (btv->cardid == PX_PXC200A_CARDID)
 	  btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM);
 	else /* older device */
 	  btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
@@ -4485,10 +4871,9 @@
 	}
 	if (UNSET != latency)
 		printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
-
-	while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+	while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL,
 				      PCI_DEVICE_ID_INTEL_82441, dev))) {
-                unsigned char b;
+		unsigned char b;
 		pci_read_config_byte(dev, 0x53, &b);
 		if (bttv_debug)
 			printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "
@@ -4498,7 +4883,7 @@
 
 int __devinit bttv_handle_chipset(struct bttv *btv)
 {
- 	unsigned char command;
+	unsigned char command;
 
 	if (!triton1 && !vsfx && UNSET == latency)
 		return 0;
@@ -4519,13 +4904,13 @@
 			btv->triton1 = BT848_INT_ETBF;
 	} else {
 		/* bt878 has a bit in the pci config space for it */
-                pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
+		pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
 		if (triton1)
 			command |= BT878_EN_TBFX;
 		if (vsfx)
 			command |= BT878_EN_VSFX;
-                pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
-        }
+		pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
+	}
 	if (UNSET != latency)
 		pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
 	return 0;
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index d538a994..0005741 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -3,7 +3,7 @@
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97,98 Ralph  Metzler <rjkm@thp.uni-koeln.de>
-                           & Marcus Metzler <mocm@thp.uni-koeln.de>
+			   & Marcus Metzler <mocm@thp.uni-koeln.de>
     (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
 
     some v4l2 code lines are taken from Justin's bttv2 driver which is
@@ -192,8 +192,8 @@
 
 const struct bttv_tvnorm bttv_tvnorms[] = {
 	/* PAL-BDGHI */
-        /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
- 	/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
+	/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
+	/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
 	{
 		.v4l2_id        = V4L2_STD_PAL,
 		.name           = "PAL",
@@ -806,9 +806,9 @@
 			btv->c.nr,table_idx);
 
 		/* timing change...reset timing generator address */
-       		btwrite(0x00, BT848_TGCTRL);
-       		btwrite(0x02, BT848_TGCTRL);
-       		btwrite(0x00, BT848_TGCTRL);
+		btwrite(0x00, BT848_TGCTRL);
+		btwrite(0x02, BT848_TGCTRL);
+		btwrite(0x00, BT848_TGCTRL);
 
 		len=SRAM_Table[table_idx][0];
 		for(i = 1; i <= len; i++)
@@ -847,7 +847,7 @@
 
 	/* -128 to 127 */
 	value = (hue >> 8) - 128;
-        btwrite(value & 0xff, BT848_HUE);
+	btwrite(value & 0xff, BT848_HUE);
 }
 
 static void bt848_contrast(struct bttv *btv, int cont)
@@ -859,9 +859,9 @@
 	/* 0-511 */
 	value = (cont  >> 7);
 	hibit = (value >> 6) & 4;
-        btwrite(value & 0xff, BT848_CONTRAST_LO);
-        btaor(hibit, ~4, BT848_E_CONTROL);
-        btaor(hibit, ~4, BT848_O_CONTROL);
+	btwrite(value & 0xff, BT848_CONTRAST_LO);
+	btaor(hibit, ~4, BT848_E_CONTROL);
+	btaor(hibit, ~4, BT848_O_CONTROL);
 }
 
 static void bt848_sat(struct bttv *btv, int color)
@@ -873,12 +873,12 @@
 	/* 0-511 for the color */
 	val_u   = ((color * btv->opt_uv_ratio) / 50) >> 7;
 	val_v   = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
-        hibits  = (val_u >> 7) & 2;
+	hibits  = (val_u >> 7) & 2;
 	hibits |= (val_v >> 8) & 1;
-        btwrite(val_u & 0xff, BT848_SAT_U_LO);
-        btwrite(val_v & 0xff, BT848_SAT_V_LO);
-        btaor(hibits, ~3, BT848_E_CONTROL);
-        btaor(hibits, ~3, BT848_O_CONTROL);
+	btwrite(val_u & 0xff, BT848_SAT_U_LO);
+	btwrite(val_v & 0xff, BT848_SAT_V_LO);
+	btaor(hibits, ~3, BT848_E_CONTROL);
+	btaor(hibits, ~3, BT848_O_CONTROL);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -891,7 +891,7 @@
 	if (input >= bttv_tvcards[btv->c.type].video_inputs)
 		return -EINVAL;
 
-        /* needed by RemoteVideo MX */
+	/* needed by RemoteVideo MX */
 	mask2 = bttv_tvcards[btv->c.type].gpiomask2;
 	if (mask2)
 		gpio_inout(mask2,mask2);
@@ -964,7 +964,7 @@
 	c.norm    = btv->tvnorm;
 	c.channel = btv->input;
 	bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
-	if (btv->c.type == BTTV_VOODOOTV_FM)
+	if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
 		bttv_tda9880_setnorm(btv,c.norm);
 }
 
@@ -988,7 +988,7 @@
 	bt848A_set_timing(btv);
 
 	switch (btv->c.type) {
-	case BTTV_VOODOOTV_FM:
+	case BTTV_BOARD_VOODOOTV_FM:
 		bttv_tda9880_setnorm(btv,norm);
 		break;
 	}
@@ -1055,22 +1055,22 @@
 	btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
 	btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
 
-        /* set planar and packed mode trigger points and         */
-        /* set rising edge of inverted GPINTR pin as irq trigger */
-        btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
-                BT848_GPIO_DMA_CTL_PLTP1_16|
-                BT848_GPIO_DMA_CTL_PLTP23_16|
-                BT848_GPIO_DMA_CTL_GPINTC|
-                BT848_GPIO_DMA_CTL_GPINTI,
-                BT848_GPIO_DMA_CTL);
+	/* set planar and packed mode trigger points and         */
+	/* set rising edge of inverted GPINTR pin as irq trigger */
+	btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
+		BT848_GPIO_DMA_CTL_PLTP1_16|
+		BT848_GPIO_DMA_CTL_PLTP23_16|
+		BT848_GPIO_DMA_CTL_GPINTC|
+		BT848_GPIO_DMA_CTL_GPINTI,
+		BT848_GPIO_DMA_CTL);
 
 	val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
-        btwrite(val, BT848_E_SCLOOP);
-        btwrite(val, BT848_O_SCLOOP);
+	btwrite(val, BT848_E_SCLOOP);
+	btwrite(val, BT848_O_SCLOOP);
 
-        btwrite(0x20, BT848_E_VSCALE_HI);
-        btwrite(0x20, BT848_O_VSCALE_HI);
-        btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+	btwrite(0x20, BT848_E_VSCALE_HI);
+	btwrite(0x20, BT848_O_VSCALE_HI);
+	btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
 		BT848_ADC);
 
 	btwrite(whitecrush_upper, BT848_WC_UP);
@@ -1089,7 +1089,7 @@
 	bt848_contrast(btv, btv->contrast);
 	bt848_sat(btv,      btv->saturation);
 
-        /* interrupt */
+	/* interrupt */
 	init_irqreg(btv);
 }
 
@@ -1105,7 +1105,7 @@
 	spin_unlock_irqrestore(&btv->s_lock,flags);
 
 	init_bt848(btv);
-        btv->pll.pll_current = -1;
+	btv->pll.pll_current = -1;
 	set_input(btv,btv->input);
 }
 
@@ -1398,7 +1398,7 @@
 /* video4linux (1) interface                                               */
 
 static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
- 			       const struct bttv_format *fmt,
+			       const struct bttv_format *fmt,
 			       unsigned int width, unsigned int height,
 			       enum v4l2_field field)
 {
@@ -1521,8 +1521,8 @@
 static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
 {
 	switch (cmd) {
-        case BTTV_VERSION:
-                return BTTV_VERSION_CODE;
+	case BTTV_VERSION:
+		return BTTV_VERSION_CODE;
 
 	/* ***  v4l1  *** ************************************************ */
 	case VIDIOCGFREQ:
@@ -1576,32 +1576,32 @@
 		return 0;
 	}
 
-        case VIDIOCGCHAN:
-        {
-                struct video_channel *v = arg;
+	case VIDIOCGCHAN:
+	{
+		struct video_channel *v = arg;
 		unsigned int channel = v->channel;
 
-                if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-                        return -EINVAL;
-                v->tuners=0;
-                v->flags = VIDEO_VC_AUDIO;
-                v->type = VIDEO_TYPE_CAMERA;
-                v->norm = btv->tvnorm;
+		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
+			return -EINVAL;
+		v->tuners=0;
+		v->flags = VIDEO_VC_AUDIO;
+		v->type = VIDEO_TYPE_CAMERA;
+		v->norm = btv->tvnorm;
 		if (channel == bttv_tvcards[btv->c.type].tuner)  {
-                        strcpy(v->name,"Television");
-                        v->flags|=VIDEO_VC_TUNER;
-                        v->type=VIDEO_TYPE_TV;
-                        v->tuners=1;
-                } else if (channel == btv->svhs) {
-                        strcpy(v->name,"S-Video");
-                } else {
-                        sprintf(v->name,"Composite%d",channel);
+			strcpy(v->name,"Television");
+			v->flags|=VIDEO_VC_TUNER;
+			v->type=VIDEO_TYPE_TV;
+			v->tuners=1;
+		} else if (channel == btv->svhs) {
+			strcpy(v->name,"S-Video");
+		} else {
+			sprintf(v->name,"Composite%d",channel);
 		}
 		return 0;
-        }
-        case VIDIOCSCHAN:
-        {
-                struct video_channel *v = arg;
+	}
+	case VIDIOCSCHAN:
+	{
+		struct video_channel *v = arg;
 		unsigned int channel = v->channel;
 
 		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
@@ -1623,7 +1623,7 @@
 		return 0;
 	}
 
-        case VIDIOCGAUDIO:
+	case VIDIOCGAUDIO:
 	{
 		struct video_audio *v = arg;
 
@@ -1728,7 +1728,7 @@
 		} else if (i->index == btv->svhs) {
 			sprintf(i->name, "S-Video");
 		} else {
-                        sprintf(i->name,"Composite%d",i->index);
+			sprintf(i->name,"Composite%d",i->index);
 		}
 		if (i->index == btv->input) {
 			__u32 dstatus = btread(BT848_DSTATUS);
@@ -1851,6 +1851,11 @@
 		up(&btv->lock);
 		return 0;
 	}
+	case VIDIOC_LOG_STATUS:
+	{
+		bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, 0);
+		return 0;
+	}
 
 	default:
 		return -ENOIOCTLCMD;
@@ -2163,7 +2168,7 @@
 		if (0 != retval)
 			return retval;
 		if (locked_btres(fh->btv, RESOURCE_VBI))
-                        return -EBUSY;
+			return -EBUSY;
 		bttv_vbi_try_fmt(fh,f);
 		bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
 		bttv_vbi_get_fmt(fh,f);
@@ -2201,9 +2206,9 @@
 		bttv_reinit_bt848(btv);
 
 	switch (cmd) {
-        case VIDIOCSFREQ:
-        case VIDIOCSTUNER:
-        case VIDIOCSCHAN:
+	case VIDIOCSFREQ:
+	case VIDIOCSTUNER:
+	case VIDIOCSCHAN:
 	case VIDIOC_S_CTRL:
 	case VIDIOC_S_STD:
 	case VIDIOC_S_INPUT:
@@ -2219,10 +2224,10 @@
 	/* ***  v4l1  *** ************************************************ */
 	case VIDIOCGCAP:
 	{
-                struct video_capability *cap = arg;
+		struct video_capability *cap = arg;
 
 		memset(cap,0,sizeof(*cap));
-                strcpy(cap->name,btv->video_dev->name);
+		strcpy(cap->name,btv->video_dev->name);
 		if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
 			/* vbi */
 			cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
@@ -2242,7 +2247,7 @@
 		}
 		cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
 		cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
-                return 0;
+		return 0;
 	}
 
 	case VIDIOCGPICT:
@@ -2291,7 +2296,7 @@
 		bt848_hue(btv,pic->hue);
 		bt848_sat(btv,pic->colour);
 		up(&fh->cap.lock);
-                return 0;
+		return 0;
 	}
 
 	case VIDIOCGWIN:
@@ -2352,8 +2357,8 @@
 		unsigned long end;
 
 		if(!capable(CAP_SYS_ADMIN) &&
-                   !capable(CAP_SYS_RAWIO))
-                        return -EPERM;
+		   !capable(CAP_SYS_RAWIO))
+			return -EPERM;
 		end = (unsigned long)fbuf->base +
 			fbuf->height * fbuf->bytesperline;
 		down(&fh->cap.lock);
@@ -2427,7 +2432,7 @@
 		}
 
 		/* switch over */
-	        retval = bttv_switch_overlay(btv,fh,new);
+		retval = bttv_switch_overlay(btv,fh,new);
 		up(&fh->cap.lock);
 		return retval;
 	}
@@ -2566,13 +2571,13 @@
 		return 0;
 	}
 
-        case BTTV_VERSION:
-        case VIDIOCGFREQ:
-        case VIDIOCSFREQ:
-        case VIDIOCGTUNER:
-        case VIDIOCSTUNER:
-        case VIDIOCGCHAN:
-        case VIDIOCSCHAN:
+	case BTTV_VERSION:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+	case VIDIOCGCHAN:
+	case VIDIOCSCHAN:
 	case VIDIOCGAUDIO:
 	case VIDIOCSAUDIO:
 		return bttv_common_ioctls(btv,cmd,arg);
@@ -2584,8 +2589,8 @@
 
 		if (0 == v4l2)
 			return -EINVAL;
-                strcpy(cap->driver,"bttv");
-                strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
+		strcpy(cap->driver,"bttv");
+		strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
 		sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci));
 		cap->version = BTTV_VERSION_CODE;
 		cap->capabilities =
@@ -2856,6 +2861,7 @@
 	case VIDIOC_S_TUNER:
 	case VIDIOC_G_FREQUENCY:
 	case VIDIOC_S_FREQUENCY:
+	case VIDIOC_LOG_STATUS:
 		return bttv_common_ioctls(btv,cmd,arg);
 
 	default:
@@ -3091,7 +3097,7 @@
 {
 	.name     = "UNSET",
 	.type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
-	            VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+		    VID_TYPE_CLIPPING|VID_TYPE_SCALES,
 	.hardware = VID_HARDWARE_BT848,
 	.fops     = &bttv_fops,
 	.minor    = -1,
@@ -3137,7 +3143,7 @@
 	audio_mux(btv,AUDIO_RADIO);
 
 	up(&btv->lock);
-        return 0;
+	return 0;
 }
 
 static int radio_release(struct inode *inode, struct file *file)
@@ -3160,34 +3166,34 @@
 	switch (cmd) {
 	case VIDIOCGCAP:
 	{
-                struct video_capability *cap = arg;
+		struct video_capability *cap = arg;
 
 		memset(cap,0,sizeof(*cap));
-                strcpy(cap->name,btv->radio_dev->name);
-                cap->type = VID_TYPE_TUNER;
+		strcpy(cap->name,btv->radio_dev->name);
+		cap->type = VID_TYPE_TUNER;
 		cap->channels = 1;
 		cap->audios = 1;
-                return 0;
+		return 0;
 	}
 
-        case VIDIOCGTUNER:
-        {
-                struct video_tuner *v = arg;
+	case VIDIOCGTUNER:
+	{
+		struct video_tuner *v = arg;
 
-                if(v->tuner)
-                        return -EINVAL;
+		if(v->tuner)
+			return -EINVAL;
 		memset(v,0,sizeof(*v));
-                strcpy(v->name, "Radio");
-                bttv_call_i2c_clients(btv,cmd,v);
-                return 0;
-        }
-        case VIDIOCSTUNER:
+		strcpy(v->name, "Radio");
+		bttv_call_i2c_clients(btv,cmd,v);
+		return 0;
+	}
+	case VIDIOCSTUNER:
 		/* nothing to do */
 		return 0;
 
 	case BTTV_VERSION:
-        case VIDIOCGFREQ:
-        case VIDIOCSFREQ:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
 	case VIDIOCGAUDIO:
 	case VIDIOCSAUDIO:
 		return bttv_common_ioctls(btv,cmd,arg);
@@ -3693,7 +3699,7 @@
 		}
 
 		if (astat&BT848_INT_VSYNC)
-                        btv->field_count++;
+			btv->field_count++;
 
 		if (astat & BT848_INT_GPINT) {
 			wake_up(&btv->gpioq);
@@ -3705,13 +3711,13 @@
 			wake_up(&btv->i2c_queue);
 		}
 
-                if ((astat & BT848_INT_RISCI)  &&  (stat & (4<<28)))
+		if ((astat & BT848_INT_RISCI)  &&  (stat & (4<<28)))
 			bttv_irq_switch_vbi(btv);
 
-                if ((astat & BT848_INT_RISCI)  &&  (stat & (2<<28)))
+		if ((astat & BT848_INT_RISCI)  &&  (stat & (2<<28)))
 			bttv_irq_wakeup_top(btv);
 
-                if ((astat & BT848_INT_RISCI)  &&  (stat & (1<<28)))
+		if ((astat & BT848_INT_RISCI)  &&  (stat & (1<<28)))
 			bttv_irq_switch_video(btv);
 
 		if ((astat & BT848_INT_HLOCK)  &&  btv->opt_automute)
@@ -3736,10 +3742,22 @@
 
 		count++;
 		if (count > 4) {
-			btwrite(0, BT848_INT_MASK);
-			printk(KERN_ERR
-			       "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+
+			if (count > 8 || !(astat & BT848_INT_GPINT)) {
+				btwrite(0, BT848_INT_MASK);
+
+				printk(KERN_ERR
+					   "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+			} else {
+				printk(KERN_ERR
+					   "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
+
+				btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
+						BT848_INT_MASK);
+			};
+
 			bttv_print_irqbits(stat,astat);
+
 			printk("]\n");
 		}
 	}
@@ -3808,7 +3826,7 @@
 
 	/* video */
 	btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
-        if (NULL == btv->video_dev)
+	if (NULL == btv->video_dev)
 		goto err;
 	if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
 		goto err;
@@ -3818,18 +3836,18 @@
 
 	/* vbi */
 	btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
-        if (NULL == btv->vbi_dev)
+	if (NULL == btv->vbi_dev)
 		goto err;
-        if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
+	if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
 		goto err;
 	printk(KERN_INFO "bttv%d: registered device vbi%d\n",
 	       btv->c.nr,btv->vbi_dev->minor & 0x1f);
 
-        if (!btv->has_radio)
+	if (!btv->has_radio)
 		return 0;
 	/* radio */
 	btv->radio_dev = vdev_init(btv, &radio_template, "radio");
-        if (NULL == btv->radio_dev)
+	if (NULL == btv->radio_dev)
 		goto err;
 	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
 		goto err;
@@ -3850,11 +3868,11 @@
 static void pci_set_command(struct pci_dev *dev)
 {
 #if defined(__powerpc__)
-        unsigned int cmd;
+	unsigned int cmd;
 
-        pci_read_config_dword(dev, PCI_COMMAND, &cmd);
-        cmd = (cmd | PCI_COMMAND_MEMORY );
-        pci_write_config_dword(dev, PCI_COMMAND, cmd);
+	pci_read_config_dword(dev, PCI_COMMAND, &cmd);
+	cmd = (cmd | PCI_COMMAND_MEMORY );
+	pci_write_config_dword(dev, PCI_COMMAND, cmd);
 #endif
 }
 
@@ -3868,63 +3886,62 @@
 	if (bttv_num == BTTV_MAX)
 		return -ENOMEM;
 	printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
-        btv=&bttvs[bttv_num];
+	btv=&bttvs[bttv_num];
 	memset(btv,0,sizeof(*btv));
 	btv->c.nr  = bttv_num;
 	sprintf(btv->c.name,"bttv%d",btv->c.nr);
 
 	/* initialize structs / fill in defaults */
-        init_MUTEX(&btv->lock);
-        init_MUTEX(&btv->reslock);
-        spin_lock_init(&btv->s_lock);
-        spin_lock_init(&btv->gpio_lock);
-        init_waitqueue_head(&btv->gpioq);
-        init_waitqueue_head(&btv->i2c_queue);
-        INIT_LIST_HEAD(&btv->c.subs);
-        INIT_LIST_HEAD(&btv->capture);
-        INIT_LIST_HEAD(&btv->vcapture);
+	init_MUTEX(&btv->lock);
+	init_MUTEX(&btv->reslock);
+	spin_lock_init(&btv->s_lock);
+	spin_lock_init(&btv->gpio_lock);
+	init_waitqueue_head(&btv->gpioq);
+	init_waitqueue_head(&btv->i2c_queue);
+	INIT_LIST_HEAD(&btv->c.subs);
+	INIT_LIST_HEAD(&btv->capture);
+	INIT_LIST_HEAD(&btv->vcapture);
 	v4l2_prio_init(&btv->prio);
 
 	init_timer(&btv->timeout);
 	btv->timeout.function = bttv_irq_timeout;
 	btv->timeout.data     = (unsigned long)btv;
 
-        btv->i2c_rc = -1;
-        btv->tuner_type  = UNSET;
-        btv->pinnacle_id = UNSET;
+	btv->i2c_rc = -1;
+	btv->tuner_type  = UNSET;
+	btv->pinnacle_id = UNSET;
 	btv->new_input   = UNSET;
-	btv->gpioirq     = 1;
 	btv->has_radio=radio[btv->c.nr];
 
 	/* pci stuff (init, get irq/mmio, ... */
 	btv->c.pci = dev;
-        btv->id  = dev->device;
+	btv->id  = dev->device;
 	if (pci_enable_device(dev)) {
-                printk(KERN_WARNING "bttv%d: Can't enable device.\n",
+		printk(KERN_WARNING "bttv%d: Can't enable device.\n",
 		       btv->c.nr);
 		return -EIO;
 	}
-        if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
-                printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
+	if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+		printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
 		       btv->c.nr);
 		return -EIO;
-        }
+	}
 	if (!request_mem_region(pci_resource_start(dev,0),
 				pci_resource_len(dev,0),
 				btv->c.name)) {
-                printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
+		printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
 		       btv->c.nr, pci_resource_start(dev,0));
 		return -EBUSY;
 	}
-        pci_set_master(dev);
+	pci_set_master(dev);
 	pci_set_command(dev);
 	pci_set_drvdata(dev,btv);
 
-        pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
-        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-        printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
-               bttv_num,btv->id, btv->revision, pci_name(dev));
-        printk("irq: %d, latency: %d, mmio: 0x%lx\n",
+	pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+	printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
+	       bttv_num,btv->id, btv->revision, pci_name(dev));
+	printk("irq: %d, latency: %d, mmio: 0x%lx\n",
 	       btv->c.pci->irq, lat, pci_resource_start(dev,0));
 	schedule();
 
@@ -3935,23 +3952,23 @@
 		goto fail1;
 	}
 
-        /* identify card */
+	/* identify card */
 	bttv_idcard(btv);
 
-        /* disable irqs, register irq handler */
+	/* disable irqs, register irq handler */
 	btwrite(0, BT848_INT_MASK);
-        result = request_irq(btv->c.pci->irq, bttv_irq,
-                             SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
-        if (result < 0) {
-                printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
+	result = request_irq(btv->c.pci->irq, bttv_irq,
+			     SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
+	if (result < 0) {
+		printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
 		       bttv_num,btv->c.pci->irq);
 		goto fail1;
-        }
+	}
 
 	if (0 != bttv_handle_chipset(btv)) {
 		result = -EIO;
 		goto fail2;
-        }
+	}
 
 	/* init options from insmod args */
 	btv->opt_combfilter = combfilter;
@@ -3977,29 +3994,29 @@
 	btv->input = 0;
 
 	/* initialize hardware */
-        if (bttv_gpio)
-                bttv_gpio_tracking(btv,"pre-init");
+	if (bttv_gpio)
+		bttv_gpio_tracking(btv,"pre-init");
 
 	bttv_risc_init_main(btv);
 	init_bt848(btv);
 
 	/* gpio */
-        btwrite(0x00, BT848_GPIO_REG_INP);
-        btwrite(0x00, BT848_GPIO_OUT_EN);
-        if (bttv_verbose)
-                bttv_gpio_tracking(btv,"init");
+	btwrite(0x00, BT848_GPIO_REG_INP);
+	btwrite(0x00, BT848_GPIO_OUT_EN);
+	if (bttv_verbose)
+		bttv_gpio_tracking(btv,"init");
 
-        /* needs to be done before i2c is registered */
-        bttv_init_card1(btv);
+	/* needs to be done before i2c is registered */
+	bttv_init_card1(btv);
 
-        /* register i2c + gpio */
-        init_bttv_i2c(btv);
+	/* register i2c + gpio */
+	init_bttv_i2c(btv);
 
-        /* some card-specific stuff (needs working i2c) */
-        bttv_init_card2(btv);
+	/* some card-specific stuff (needs working i2c) */
+	bttv_init_card2(btv);
 	init_irqreg(btv);
 
-        /* register video4linux + input */
+	/* register video4linux + input */
 	if (!bttv_tvcards[btv->c.type].no_video) {
 		bttv_register_video(btv);
 		bt848_bright(btv,32768);
@@ -4018,10 +4035,10 @@
 
 	/* everything is fine */
 	bttv_num++;
-        return 0;
+	return 0;
 
  fail2:
-        free_irq(btv->c.pci->irq,btv);
+	free_irq(btv->c.pci->irq,btv);
 
  fail1:
 	if (btv->bt848_mmio)
@@ -4034,12 +4051,12 @@
 
 static void __devexit bttv_remove(struct pci_dev *pci_dev)
 {
-        struct bttv *btv = pci_get_drvdata(pci_dev);
+	struct bttv *btv = pci_get_drvdata(pci_dev);
 
 	if (bttv_verbose)
 		printk("bttv%d: unloading\n",btv->c.nr);
 
-        /* shutdown everything (DMA+IRQs) */
+	/* shutdown everything (DMA+IRQs) */
 	btand(~15, BT848_GPIO_DMA_CTL);
 	btwrite(0, BT848_INT_MASK);
 	btwrite(~0x0, BT848_INT_STAT);
@@ -4052,7 +4069,7 @@
 	wake_up(&btv->gpioq);
 	bttv_sub_del_devices(&btv->c);
 
-        /* unregister i2c_bus + input */
+	/* unregister i2c_bus + input */
 	fini_bttv_i2c(btv);
 
 	/* unregister video4linux */
@@ -4062,18 +4079,18 @@
 	btcx_riscmem_free(btv->c.pci,&btv->main);
 
 	/* free ressources */
-        free_irq(btv->c.pci->irq,btv);
+	free_irq(btv->c.pci->irq,btv);
 	iounmap(btv->bt848_mmio);
-        release_mem_region(pci_resource_start(btv->c.pci,0),
-                           pci_resource_len(btv->c.pci,0));
+	release_mem_region(pci_resource_start(btv->c.pci,0),
+			   pci_resource_len(btv->c.pci,0));
 
 	pci_set_drvdata(pci_dev, NULL);
-        return;
+	return;
 }
 
 static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
-        struct bttv *btv = pci_get_drvdata(pci_dev);
+	struct bttv *btv = pci_get_drvdata(pci_dev);
 	struct bttv_buffer_set idle;
 	unsigned long flags;
 
@@ -4108,7 +4125,7 @@
 
 static int bttv_resume(struct pci_dev *pci_dev)
 {
-        struct bttv *btv = pci_get_drvdata(pci_dev);
+	struct bttv *btv = pci_get_drvdata(pci_dev);
 	unsigned long flags;
 	int err;
 
@@ -4153,24 +4170,24 @@
 }
 
 static struct pci_device_id bttv_pci_tbl[] = {
-        {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-        {0,}
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
 };
 
 MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
 
 static struct pci_driver bttv_pci_driver = {
-        .name     = "bttv",
-        .id_table = bttv_pci_tbl,
-        .probe    = bttv_probe,
-        .remove   = __devexit_p(bttv_remove),
+	.name     = "bttv",
+	.id_table = bttv_pci_tbl,
+	.probe    = bttv_probe,
+	.remove   = __devexit_p(bttv_remove),
 	.suspend  = bttv_suspend,
 	.resume   = bttv_resume,
 };
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
index 6b280c0..575ce8b 100644
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -7,7 +7,7 @@
 
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
     This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c
index e684df3..77619eb 100644
--- a/drivers/media/video/bttv-i2c.c
+++ b/drivers/media/video/bttv-i2c.c
@@ -5,7 +5,7 @@
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
     This program is free software; you can redistribute it and/or modify
@@ -237,7 +237,7 @@
  err:
 	if (i2c_debug)
 		printk(" ERR: %d\n",retval);
-       	return retval;
+	return retval;
 }
 
 static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
@@ -290,7 +290,13 @@
 
 static int attach_inform(struct i2c_client *client)
 {
-        struct bttv *btv = i2c_get_adapdata(client->adapter);
+	struct bttv *btv = i2c_get_adapdata(client->adapter);
+	int addr=ADDR_UNSET;
+
+
+	if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+		addr = bttv_tvcards[btv->c.type].tuner_addr;
+
 
 	if (bttv_debug)
 		printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
@@ -300,19 +306,20 @@
 		return 0;
 
 	if (btv->tuner_type != UNSET) {
-	        struct tuner_setup tun_setup;
+		struct tuner_setup tun_setup;
 
-	        tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
-		tun_setup.type = btv->tuner_type;
-		tun_setup.addr = ADDR_UNSET;
+		if ((addr==ADDR_UNSET) ||
+				(addr==client->addr)) {
 
-		client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
+			tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV | T_RADIO;
+			tun_setup.type = btv->tuner_type;
+			tun_setup.addr = addr;
+			bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+		}
+
 	}
 
-	if (btv->pinnacle_id != UNSET)
-		client->driver->command(client,AUDC_CONFIG_PINNACLE,
-				      &btv->pinnacle_id);
-        return 0;
+	return 0;
 }
 
 void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
@@ -330,43 +337,43 @@
 /* read I2C */
 int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
 {
-        unsigned char buffer = 0;
+	unsigned char buffer = 0;
 
 	if (0 != btv->i2c_rc)
 		return -1;
 	if (bttv_verbose && NULL != probe_for)
 		printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
 		       btv->c.nr,probe_for,addr);
-        btv->i2c_client.addr = addr >> 1;
-        if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
+	btv->i2c_client.addr = addr >> 1;
+	if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
 		if (NULL != probe_for) {
 			if (bttv_verbose)
 				printk("not found\n");
 		} else
 			printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
 			       btv->c.nr,addr);
-                return -1;
+		return -1;
 	}
 	if (bttv_verbose && NULL != probe_for)
 		printk("found\n");
-        return buffer;
+	return buffer;
 }
 
 /* write I2C */
 int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
-                    unsigned char b2, int both)
+		    unsigned char b2, int both)
 {
-        unsigned char buffer[2];
-        int bytes = both ? 2 : 1;
+	unsigned char buffer[2];
+	int bytes = both ? 2 : 1;
 
 	if (0 != btv->i2c_rc)
 		return -1;
-        btv->i2c_client.addr = addr >> 1;
-        buffer[0] = b1;
-        buffer[1] = b2;
-        if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
+	btv->i2c_client.addr = addr >> 1;
+	buffer[0] = b1;
+	buffer[1] = b2;
+	if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
 		return -1;
-        return 0;
+	return 0;
 }
 
 /* read EEPROM content */
@@ -431,8 +438,8 @@
 		 "bt%d #%d [%s]", btv->id, btv->c.nr,
 		 btv->use_i2c_hw ? "hw" : "sw");
 
-        i2c_set_adapdata(&btv->c.i2c_adap, btv);
-        btv->i2c_client.adapter = &btv->c.i2c_adap;
+	i2c_set_adapdata(&btv->c.i2c_adap, btv);
+	btv->i2c_client.adapter = &btv->c.i2c_adap;
 
 #ifdef I2C_CLASS_TV_ANALOG
 	if (bttv_tvcards[btv->c.type].no_video)
diff --git a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c
index e8aada7..19b564a 100644
--- a/drivers/media/video/bttv-if.c
+++ b/drivers/media/video/bttv-if.c
@@ -1,13 +1,13 @@
 /*
 
     bttv-if.c  --  old gpio interface to other kernel modules
-                   don't use in new code, will go away in 2.7
+		   don't use in new code, will go away in 2.7
 		   have a look at bttv-gpio.c instead.
 
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
     This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c
index a5ed99b8..b40e973 100644
--- a/drivers/media/video/bttv-risc.c
+++ b/drivers/media/video/bttv-risc.c
@@ -74,27 +74,27 @@
 		}
 		if (bpl <= sg_dma_len(sg)-offset) {
 			/* fits into current chunk */
-                        *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+			*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
 					    BT848_RISC_EOL|bpl);
-                        *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                        offset+=bpl;
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			offset+=bpl;
 		} else {
 			/* scanline needs to be splitted */
-                        todo = bpl;
-                        *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+			todo = bpl;
+			*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
 					    (sg_dma_len(sg)-offset));
-                        *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                        todo -= (sg_dma_len(sg)-offset);
-                        offset = 0;
-                        sg++;
-                        while (todo > sg_dma_len(sg)) {
-                                *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			todo -= (sg_dma_len(sg)-offset);
+			offset = 0;
+			sg++;
+			while (todo > sg_dma_len(sg)) {
+				*(rp++)=cpu_to_le32(BT848_RISC_WRITE|
 						    sg_dma_len(sg));
-                                *(rp++)=cpu_to_le32(sg_dma_address(sg));
+				*(rp++)=cpu_to_le32(sg_dma_address(sg));
 				todo -= sg_dma_len(sg);
 				sg++;
 			}
-                        *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
+			*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
 					    todo);
 			*(rp++)=cpu_to_le32(sg_dma_address(sg));
 			offset += todo;
@@ -201,8 +201,8 @@
 				ri |= BT848_RISC_EOL;
 
 			/* write risc instruction */
-                        *(rp++)=cpu_to_le32(ri | ylen);
-                        *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
+			*(rp++)=cpu_to_le32(ri | ylen);
+			*(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
 					    (ylen >> hshift));
 			*(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
 			yoffset += ylen;
@@ -319,7 +319,7 @@
 	      int width, int height, int interleaved, int norm)
 {
 	const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
-        u32 xsf, sr;
+	u32 xsf, sr;
 	int vdelay;
 
 	int swidth       = tvnorm->swidth;
@@ -334,52 +334,52 @@
 
 	vdelay = tvnorm->vdelay;
 
-        xsf = (width*scaledtwidth)/swidth;
-        geo->hscale =  ((totalwidth*4096UL)/xsf-4096);
-        geo->hdelay =  tvnorm->hdelayx1;
-        geo->hdelay =  (geo->hdelay*width)/swidth;
-        geo->hdelay &= 0x3fe;
-        sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
-        geo->vscale =  (0x10000UL-sr) & 0x1fff;
-        geo->crop   =  ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
-                ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
-        geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
-        geo->vdelay  =  vdelay;
-        geo->width   =  width;
-        geo->sheight =  tvnorm->sheight;
+	xsf = (width*scaledtwidth)/swidth;
+	geo->hscale =  ((totalwidth*4096UL)/xsf-4096);
+	geo->hdelay =  tvnorm->hdelayx1;
+	geo->hdelay =  (geo->hdelay*width)/swidth;
+	geo->hdelay &= 0x3fe;
+	sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
+	geo->vscale =  (0x10000UL-sr) & 0x1fff;
+	geo->crop   =  ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
+		((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
+	geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
+	geo->vdelay  =  vdelay;
+	geo->width   =  width;
+	geo->sheight =  tvnorm->sheight;
 	geo->vtotal  =  tvnorm->vtotal;
 
-        if (btv->opt_combfilter) {
-                geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
-                geo->comb = (width < 769) ? 1 : 0;
-        } else {
-                geo->vtc  = 0;
-                geo->comb = 0;
-        }
+	if (btv->opt_combfilter) {
+		geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+		geo->comb = (width < 769) ? 1 : 0;
+	} else {
+		geo->vtc  = 0;
+		geo->comb = 0;
+	}
 }
 
 static void
 bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
 {
-        int off = odd ? 0x80 : 0x00;
+	int off = odd ? 0x80 : 0x00;
 
 	if (geo->comb)
 		btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
 	else
 		btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
 
-        btwrite(geo->vtc,             BT848_E_VTC+off);
-        btwrite(geo->hscale >> 8,     BT848_E_HSCALE_HI+off);
-        btwrite(geo->hscale & 0xff,   BT848_E_HSCALE_LO+off);
-        btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
-        btwrite(geo->vscale & 0xff,   BT848_E_VSCALE_LO+off);
-        btwrite(geo->width & 0xff,    BT848_E_HACTIVE_LO+off);
-        btwrite(geo->hdelay & 0xff,   BT848_E_HDELAY_LO+off);
-        btwrite(geo->sheight & 0xff,  BT848_E_VACTIVE_LO+off);
-        btwrite(geo->vdelay & 0xff,   BT848_E_VDELAY_LO+off);
-        btwrite(geo->crop,            BT848_E_CROP+off);
+	btwrite(geo->vtc,             BT848_E_VTC+off);
+	btwrite(geo->hscale >> 8,     BT848_E_HSCALE_HI+off);
+	btwrite(geo->hscale & 0xff,   BT848_E_HSCALE_LO+off);
+	btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
+	btwrite(geo->vscale & 0xff,   BT848_E_VSCALE_LO+off);
+	btwrite(geo->width & 0xff,    BT848_E_HACTIVE_LO+off);
+	btwrite(geo->hdelay & 0xff,   BT848_E_HDELAY_LO+off);
+	btwrite(geo->sheight & 0xff,  BT848_E_VACTIVE_LO+off);
+	btwrite(geo->vdelay & 0xff,   BT848_E_VDELAY_LO+off);
+	btwrite(geo->crop,            BT848_E_CROP+off);
 	btwrite(geo->vtotal>>8,       BT848_VTOTAL_HI);
-        btwrite(geo->vtotal & 0xff,   BT848_VTOTAL_LO);
+	btwrite(geo->vtotal & 0xff,   BT848_VTOTAL_LO);
 }
 
 /* ---------------------------------------------------------- */
@@ -420,7 +420,7 @@
 	} else {
 		del_timer(&btv->timeout);
 	}
-        btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
+	btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
 
 	btaor(capctl, ~0x0f, BT848_CAP_CTL);
 	if (capctl) {
@@ -432,7 +432,7 @@
 	} else {
 		if (!btv->dma_on)
 			return;
-                btand(~3, BT848_GPIO_DMA_CTL);
+		btand(~3, BT848_GPIO_DMA_CTL);
 		btv->dma_on = 0;
 	}
 	return;
@@ -460,19 +460,19 @@
 	btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
 	btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
 
-        btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
+	btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
 				       BT848_FIFO_STATUS_VRO);
-        btv->main.cpu[9] = cpu_to_le32(0);
+	btv->main.cpu[9] = cpu_to_le32(0);
 
 	/* bottom field */
-        btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
+	btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
 	btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
-        btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
+	btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
 	btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
 
 	/* jump back to top field */
 	btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
-        btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
+	btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
 
 	return 0;
 }
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index d254e90..124ea41 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -20,123 +20,148 @@
 /* ---------------------------------------------------------- */
 /* exported by bttv-cards.c                                   */
 
-#define BTTV_UNKNOWN       0x00
-#define BTTV_MIRO          0x01
-#define BTTV_HAUPPAUGE     0x02
-#define BTTV_STB           0x03
-#define BTTV_INTEL         0x04
-#define BTTV_DIAMOND       0x05
-#define BTTV_AVERMEDIA     0x06
-#define BTTV_MATRIX_VISION 0x07
-#define BTTV_FLYVIDEO      0x08
-#define BTTV_TURBOTV       0x09
-#define BTTV_HAUPPAUGE878  0x0a
-#define BTTV_MIROPRO       0x0b
-#define BTTV_ADSTECH_TV    0x0c
-#define BTTV_AVERMEDIA98   0x0d
-#define BTTV_VHX           0x0e
-#define BTTV_ZOLTRIX       0x0f
-#define BTTV_PIXVIEWPLAYTV 0x10
-#define BTTV_WINVIEW_601   0x11
-#define BTTV_AVEC_INTERCAP 0x12
-#define BTTV_LIFE_FLYKIT   0x13
-#define BTTV_CEI_RAFFLES   0x14
-#define BTTV_CONFERENCETV  0x15
-#define BTTV_PHOEBE_TVMAS  0x16
-#define BTTV_MODTEC_205    0x17
-#define BTTV_MAGICTVIEW061 0x18
-#define BTTV_VOBIS_BOOSTAR 0x19
-#define BTTV_HAUPPAUG_WCAM 0x1a
-#define BTTV_MAXI          0x1b
-#define BTTV_TERRATV       0x1c
-#define BTTV_PXC200        0x1d
-#define BTTV_FLYVIDEO_98   0x1e
-#define BTTV_IPROTV        0x1f
-#define BTTV_INTEL_C_S_PCI 0x20
-#define BTTV_TERRATVALUE   0x21
-#define BTTV_WINFAST2000   0x22
-#define BTTV_CHRONOS_VS2   0x23
-#define BTTV_TYPHOON_TVIEW 0x24
-#define BTTV_PXELVWPLTVPRO 0x25
-#define BTTV_MAGICTVIEW063 0x26
-#define BTTV_PINNACLE      0x27
-#define BTTV_STB2          0x28
-#define BTTV_AVPHONE98     0x29
-#define BTTV_PV951         0x2a
-#define BTTV_ONAIR_TV      0x2b
-#define BTTV_SIGMA_TVII_FM 0x2c
-#define BTTV_MATRIX_VISION2 0x2d
-#define BTTV_ZOLTRIX_GENIE 0x2e
-#define BTTV_TERRATVRADIO  0x2f
-#define BTTV_DYNALINK      0x30
-#define BTTV_GVBCTV3PCI    0x31
-#define BTTV_PXELVWPLTVPAK 0x32
-#define BTTV_EAGLE         0x33
-#define BTTV_PINNACLEPRO   0x34
-#define BTTV_TVIEW_RDS_FM  0x35
-#define BTTV_LIFETEC_9415  0x36
-#define BTTV_BESTBUY_EASYTV 0x37
-#define BTTV_FLYVIDEO_98FM 0x38
-#define BTTV_GMV1          0x3d
-#define BTTV_BESTBUY_EASYTV2 0x3e
-#define BTTV_ATI_TVWONDER  0x3f
-#define BTTV_ATI_TVWONDERVE 0x40
-#define BTTV_FLYVIDEO2000   0x41
-#define BTTV_TERRATVALUER   0x42
-#define BTTV_GVBCTV4PCI     0x43
-#define BTTV_VOODOOTV_FM    0x44
-#define BTTV_AIMMS          0x45
-#define BTTV_PV_BT878P_PLUS 0x46
-#define BTTV_FLYVIDEO98EZ   0x47
-#define BTTV_PV_BT878P_9B   0x48
-#define BTTV_SENSORAY311    0x49
-#define BTTV_RV605          0x4a
-#define BTTV_WINDVR         0x4c
-#define BTTV_GRANDTEC       0x4d
-#define BTTV_KWORLD         0x4e
-#define BTTV_HAUPPAUGEPVR   0x50
-#define BTTV_GVBCTV5PCI     0x51
-#define BTTV_OSPREY1x0      0x52
-#define BTTV_OSPREY1x0_848  0x53
-#define BTTV_OSPREY101_848  0x54
-#define BTTV_OSPREY1x1      0x55
-#define BTTV_OSPREY1x1_SVID 0x56
-#define BTTV_OSPREY2xx      0x57
-#define BTTV_OSPREY2x0_SVID 0x58
-#define BTTV_OSPREY2x0      0x59
-#define BTTV_OSPREY500      0x5a
-#define BTTV_OSPREY540      0x5b
-#define BTTV_OSPREY2000     0x5c
-#define BTTV_IDS_EAGLE      0x5d
-#define BTTV_PINNACLESAT    0x5e
-#define BTTV_FORMAC_PROTV   0x5f
-#define BTTV_EURESYS_PICOLO 0x61
-#define BTTV_PV150          0x62
-#define BTTV_AD_TVK503      0x63
-#define BTTV_IVC200         0x66
-#define BTTV_XGUARD         0x67
-#define BTTV_NEBULA_DIGITV  0x68
-#define BTTV_PV143          0x69
-#define BTTV_IVC100         0x6e
-#define BTTV_IVC120         0x6f
-#define BTTV_PC_HDTV        0x70
-#define BTTV_TWINHAN_DST    0x71
-#define BTTV_WINFASTVC100   0x72
-#define BTTV_SIMUS_GVC1100  0x74
-#define BTTV_NGSTV_PLUS     0x75
-#define BTTV_LMLBT4         0x76
-#define BTTV_PICOLO_TETRA_CHIP 0x79
-#define BTTV_AVDVBT_771     0x7b
-#define BTTV_AVDVBT_761     0x7c
-#define BTTV_MATRIX_VISIONSQ  0x7d
-#define BTTV_MATRIX_VISIONSLC 0x7e
-#define BTTV_APAC_VIEWCOMP  0x7f
-#define BTTV_DVICO_DVBT_LITE  0x80
-#define BTTV_TIBET_CS16  0x83
-#define BTTV_KODICOM_4400R  0x84
-#define BTTV_ADLINK_RTV24   0x86
-#define BTTV_DVICO_FUSIONHDTV_5_LITE 0x87
-#define BTTV_ACORP_Y878F   0x88
+#define BTTV_BOARD_UNKNOWN                 0x00
+#define BTTV_BOARD_MIRO                    0x01
+#define BTTV_BOARD_HAUPPAUGE               0x02
+#define BTTV_BOARD_STB                     0x03
+#define BTTV_BOARD_INTEL                   0x04
+#define BTTV_BOARD_DIAMOND                 0x05
+#define BTTV_BOARD_AVERMEDIA               0x06
+#define BTTV_BOARD_MATRIX_VISION           0x07
+#define BTTV_BOARD_FLYVIDEO                0x08
+#define BTTV_BOARD_TURBOTV                 0x09
+#define BTTV_BOARD_HAUPPAUGE878            0x0a
+#define BTTV_BOARD_MIROPRO                 0x0b
+#define BTTV_BOARD_ADSTECH_TV              0x0c
+#define BTTV_BOARD_AVERMEDIA98             0x0d
+#define BTTV_BOARD_VHX                     0x0e
+#define BTTV_BOARD_ZOLTRIX                 0x0f
+#define BTTV_BOARD_PIXVIEWPLAYTV           0x10
+#define BTTV_BOARD_WINVIEW_601             0x11
+#define BTTV_BOARD_AVEC_INTERCAP           0x12
+#define BTTV_BOARD_LIFE_FLYKIT             0x13
+#define BTTV_BOARD_CEI_RAFFLES             0x14
+#define BTTV_BOARD_CONFERENCETV            0x15
+#define BTTV_BOARD_PHOEBE_TVMAS            0x16
+#define BTTV_BOARD_MODTEC_205              0x17
+#define BTTV_BOARD_MAGICTVIEW061           0x18
+#define BTTV_BOARD_VOBIS_BOOSTAR           0x19
+#define BTTV_BOARD_HAUPPAUG_WCAM           0x1a
+#define BTTV_BOARD_MAXI                    0x1b
+#define BTTV_BOARD_TERRATV                 0x1c
+#define BTTV_BOARD_PXC200                  0x1d
+#define BTTV_BOARD_FLYVIDEO_98             0x1e
+#define BTTV_BOARD_IPROTV                  0x1f
+#define BTTV_BOARD_INTEL_C_S_PCI           0x20
+#define BTTV_BOARD_TERRATVALUE             0x21
+#define BTTV_BOARD_WINFAST2000             0x22
+#define BTTV_BOARD_CHRONOS_VS2             0x23
+#define BTTV_BOARD_TYPHOON_TVIEW           0x24
+#define BTTV_BOARD_PXELVWPLTVPRO           0x25
+#define BTTV_BOARD_MAGICTVIEW063           0x26
+#define BTTV_BOARD_PINNACLE                0x27
+#define BTTV_BOARD_STB2                    0x28
+#define BTTV_BOARD_AVPHONE98               0x29
+#define BTTV_BOARD_PV951                   0x2a
+#define BTTV_BOARD_ONAIR_TV                0x2b
+#define BTTV_BOARD_SIGMA_TVII_FM           0x2c
+#define BTTV_BOARD_MATRIX_VISION2          0x2d
+#define BTTV_BOARD_ZOLTRIX_GENIE           0x2e
+#define BTTV_BOARD_TERRATVRADIO            0x2f
+#define BTTV_BOARD_DYNALINK                0x30
+#define BTTV_BOARD_GVBCTV3PCI              0x31
+#define BTTV_BOARD_PXELVWPLTVPAK           0x32
+#define BTTV_BOARD_EAGLE                   0x33
+#define BTTV_BOARD_PINNACLEPRO             0x34
+#define BTTV_BOARD_TVIEW_RDS_FM            0x35
+#define BTTV_BOARD_LIFETEC_9415            0x36
+#define BTTV_BOARD_BESTBUY_EASYTV          0x37
+#define BTTV_BOARD_FLYVIDEO_98FM           0x38
+#define BTTV_BOARD_GRANDTEC                0x39
+#define BTTV_BOARD_ASKEY_CPH060            0x3a
+#define BTTV_BOARD_ASKEY_CPH03X            0x3b
+#define BTTV_BOARD_MM100PCTV               0x3c
+#define BTTV_BOARD_GMV1                    0x3d
+#define BTTV_BOARD_BESTBUY_EASYTV2         0x3e
+#define BTTV_BOARD_ATI_TVWONDER            0x3f
+#define BTTV_BOARD_ATI_TVWONDERVE          0x40
+#define BTTV_BOARD_FLYVIDEO2000            0x41
+#define BTTV_BOARD_TERRATVALUER            0x42
+#define BTTV_BOARD_GVBCTV4PCI              0x43
+#define BTTV_BOARD_VOODOOTV_FM             0x44
+#define BTTV_BOARD_AIMMS                   0x45
+#define BTTV_BOARD_PV_BT878P_PLUS          0x46
+#define BTTV_BOARD_FLYVIDEO98EZ            0x47
+#define BTTV_BOARD_PV_BT878P_9B            0x48
+#define BTTV_BOARD_SENSORAY311             0x49
+#define BTTV_BOARD_RV605                   0x4a
+#define BTTV_BOARD_POWERCLR_MTV878         0x4b
+#define BTTV_BOARD_WINDVR                  0x4c
+#define BTTV_BOARD_GRANDTEC_MULTI          0x4d
+#define BTTV_BOARD_KWORLD                  0x4e
+#define BTTV_BOARD_DSP_TCVIDEO             0x4f
+#define BTTV_BOARD_HAUPPAUGEPVR            0x50
+#define BTTV_BOARD_GVBCTV5PCI              0x51
+#define BTTV_BOARD_OSPREY1x0               0x52
+#define BTTV_BOARD_OSPREY1x0_848           0x53
+#define BTTV_BOARD_OSPREY101_848           0x54
+#define BTTV_BOARD_OSPREY1x1               0x55
+#define BTTV_BOARD_OSPREY1x1_SVID          0x56
+#define BTTV_BOARD_OSPREY2xx               0x57
+#define BTTV_BOARD_OSPREY2x0_SVID          0x58
+#define BTTV_BOARD_OSPREY2x0               0x59
+#define BTTV_BOARD_OSPREY500               0x5a
+#define BTTV_BOARD_OSPREY540               0x5b
+#define BTTV_BOARD_OSPREY2000              0x5c
+#define BTTV_BOARD_IDS_EAGLE               0x5d
+#define BTTV_BOARD_PINNACLESAT             0x5e
+#define BTTV_BOARD_FORMAC_PROTV            0x5f
+#define BTTV_BOARD_MACHTV                  0x60
+#define BTTV_BOARD_EURESYS_PICOLO          0x61
+#define BTTV_BOARD_PV150                   0x62
+#define BTTV_BOARD_AD_TVK503               0x63
+#define BTTV_BOARD_HERCULES_SM_TV          0x64
+#define BTTV_BOARD_PACETV                  0x65
+#define BTTV_BOARD_IVC200                  0x66
+#define BTTV_BOARD_XGUARD                  0x67
+#define BTTV_BOARD_NEBULA_DIGITV           0x68
+#define BTTV_BOARD_PV143                   0x69
+#define BTTV_BOARD_VD009X1_MINIDIN         0x6a
+#define BTTV_BOARD_VD009X1_COMBI           0x6b
+#define BTTV_BOARD_VD009_MINIDIN           0x6c
+#define BTTV_BOARD_VD009_COMBI             0x6d
+#define BTTV_BOARD_IVC100                  0x6e
+#define BTTV_BOARD_IVC120                  0x6f
+#define BTTV_BOARD_PC_HDTV                 0x70
+#define BTTV_BOARD_TWINHAN_DST             0x71
+#define BTTV_BOARD_WINFASTVC100            0x72
+#define BTTV_BOARD_TEV560                  0x73
+#define BTTV_BOARD_SIMUS_GVC1100           0x74
+#define BTTV_BOARD_NGSTV_PLUS              0x75
+#define BTTV_BOARD_LMLBT4                  0x76
+#define BTTV_BOARD_TEKRAM_M205             0x77
+#define BTTV_BOARD_CONTVFMI                0x78
+#define BTTV_BOARD_PICOLO_TETRA_CHIP       0x79
+#define BTTV_BOARD_SPIRIT_TV               0x7a
+#define BTTV_BOARD_AVDVBT_771              0x7b
+#define BTTV_BOARD_AVDVBT_761              0x7c
+#define BTTV_BOARD_MATRIX_VISIONSQ         0x7d
+#define BTTV_BOARD_MATRIX_VISIONSLC        0x7e
+#define BTTV_BOARD_APAC_VIEWCOMP           0x7f
+#define BTTV_BOARD_DVICO_DVBT_LITE         0x80
+#define BTTV_BOARD_VGEAR_MYVCD             0x81
+#define BTTV_BOARD_SUPER_TV                0x82
+#define BTTV_BOARD_TIBET_CS16              0x83
+#define BTTV_BOARD_KODICOM_4400R           0x84
+#define BTTV_BOARD_KODICOM_4400R_SL        0x85
+#define BTTV_BOARD_ADLINK_RTV24            0x86
+#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
+#define BTTV_BOARD_ACORP_Y878F             0x88
+#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2    0x89
+#define BTTV_BOARD_PV_BT878P_2E            0x8a
+#define BTTV_BOARD_PV_M4900                0x8b
+#define BTTV_BOARD_OSPREY440               0x8c
+#define BTTV_BOARD_ASOUND_SKYEYE	   0x8d
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -177,7 +202,7 @@
 	struct list_head     subs;     /* struct bttv_sub_device */
 
 	/* device config */
-        unsigned int         nr;       /* dev nr (for printk("bttv%d: ...");  */
+	unsigned int         nr;       /* dev nr (for printk("bttv%d: ...");  */
 	unsigned int         type;     /* card type (pointer into tvcards[])  */
 	char                 name[8];  /* dev name */
 };
@@ -186,16 +211,16 @@
 
 struct tvcard
 {
-        char *name;
-        unsigned int video_inputs;
-        unsigned int audio_inputs;
-        unsigned int tuner;
-        unsigned int svhs;
+	char *name;
+	unsigned int video_inputs;
+	unsigned int audio_inputs;
+	unsigned int tuner;
+	unsigned int svhs;
 	unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
-        u32 gpiomask;
-        u32 muxsel[16];
-        u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
-        u32 gpiomask2;   /* GPIO MUX mask */
+	u32 gpiomask;
+	u32 muxsel[16];
+	u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
+	u32 gpiomask2;   /* GPIO MUX mask */
 
 	/* i2c audio flags */
 	unsigned int no_msp34xx:1;
@@ -218,6 +243,7 @@
 
 	unsigned int tuner_type;
 	unsigned int tuner_addr;
+	unsigned int radio_addr;
 
 	unsigned int has_radio;
 	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
@@ -246,7 +272,7 @@
    interface below for new code */
 
 /* returns card type + card ID (for bt878-based ones)
-   for possible values see lines below beginning with #define BTTV_UNKNOWN
+   for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN
    returns negative value if error occurred
 */
 extern int bttv_get_cardinfo(unsigned int card, int *type,
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
index e0e7c7a..386f546 100644
--- a/drivers/media/video/bttvp.h
+++ b/drivers/media/video/bttvp.h
@@ -77,14 +77,14 @@
 struct bttv_tvnorm {
 	int   v4l2_id;
 	char  *name;
-        u32   Fsc;
-        u16   swidth, sheight; /* scaled standard width, height */
+	u32   Fsc;
+	u16   swidth, sheight; /* scaled standard width, height */
 	u16   totalwidth;
 	u8    adelay, bdelay, iform;
 	u32   scaledtwidth;
 	u16   hdelayx1, hactivex1;
 	u16   vdelay;
-        u8    vbipack;
+	u8    vbipack;
 	u16   vtotal;
 	int   sram;
 };
@@ -267,8 +267,8 @@
 
 	/* card configuration info */
 	unsigned int cardid;   /* pci subsystem id (bt878 based ones) */
-        unsigned int tuner_type;  /* tuner chip type */
-        unsigned int pinnacle_id;
+	unsigned int tuner_type;  /* tuner chip type */
+	unsigned int pinnacle_id;
 	unsigned int svhs;
 	struct bttv_pll_info pll;
 	int triton1;
@@ -301,9 +301,9 @@
 
 	/* locking */
 	spinlock_t s_lock;
-        struct semaphore lock;
+	struct semaphore lock;
 	int resources;
-        struct semaphore reslock;
+	struct semaphore reslock;
 #ifdef VIDIOC_G_PRIORITY
 	struct v4l2_prio_state prio;
 #endif
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
new file mode 100644
index 0000000..780b352
--- /dev/null
+++ b/drivers/media/video/cs53l32a.c
@@ -0,0 +1,240 @@
+/*
+ * cs53l32a (Adaptec AVC-2010 and AVC-2410) i2c ivtv driver.
+ * Copyright (C) 2005  Martin Vaughan
+ *
+ * Audio source switching for Adaptec AVC-2410 added by Trev Jackson
+ *
+ * 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.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/audiochip.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
+MODULE_AUTHOR("Martin Vaughan");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
+
+#define cs53l32a_dbg(fmt, arg...) \
+	do { \
+		if (debug) \
+			printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
+	} while (0)
+
+#define cs53l32a_err(fmt, arg...) do { \
+	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define cs53l32a_info(fmt, arg...) do { \
+	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int cs53l32a_read(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
+			    void *arg)
+{
+	int *input = arg;
+
+	switch (cmd) {
+	case AUDC_SET_INPUT:
+		switch (*input) {
+		case AUDIO_TUNER:
+			cs53l32a_write(client, 0x01, 0x01);
+			break;
+		case AUDIO_EXTERN:
+			cs53l32a_write(client, 0x01, 0x21);
+			break;
+		case AUDIO_MUTE:
+			cs53l32a_write(client, 0x03, 0xF0);
+			break;
+		case AUDIO_UNMUTE:
+			cs53l32a_write(client, 0x03, 0x30);
+			break;
+		default:
+			cs53l32a_err("Invalid input %d.\n", *input);
+			return -EINVAL;
+		}
+		break;
+
+	case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl = arg;
+
+			if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+				return -EINVAL;
+			if (ctrl->value > 12 || ctrl->value < -90)
+				return -EINVAL;
+			cs53l32a_write(client, 0x04, (u8) ctrl->value);
+			cs53l32a_write(client, 0x05, (u8) ctrl->value);
+			break;
+		}
+
+	case VIDIOC_LOG_STATUS:
+		{
+			u8 v = cs53l32a_read(client, 0x01);
+			u8 m = cs53l32a_read(client, 0x03);
+
+			cs53l32a_info("Input: %s%s\n",
+				      v == 0x21 ? "external line in" : "tuner",
+				      (m & 0xC0) ? " (muted)" : "");
+			break;
+		}
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	int i;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return 0;
+
+	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+
+	memset(client, 0, sizeof(struct i2c_client));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver;
+	client->flags = I2C_CLIENT_ALLOW_USE;
+	snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
+
+	cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+	for (i = 1; i <= 7; i++) {
+		u8 v = cs53l32a_read(client, i);
+
+		cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+	}
+
+	/* Set cs53l32a internal register for Adaptec 2010/2410 setup */
+
+	cs53l32a_write(client, 0x01, (u8) 0x21);
+	cs53l32a_write(client, 0x02, (u8) 0x29);
+	cs53l32a_write(client, 0x03, (u8) 0x30);
+	cs53l32a_write(client, 0x04, (u8) 0x00);
+	cs53l32a_write(client, 0x05, (u8) 0x00);
+	cs53l32a_write(client, 0x06, (u8) 0x00);
+	cs53l32a_write(client, 0x07, (u8) 0x00);
+
+	/* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
+
+	for (i = 1; i <= 7; i++) {
+		u8 v = cs53l32a_read(client, i);
+
+		cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+	}
+
+	i2c_attach_client(client);
+
+	return 0;
+}
+
+static int cs53l32a_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+	if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+	if (adapter->id == I2C_HW_B_BT848)
+#endif
+		return i2c_probe(adapter, &addr_data, cs53l32a_attach);
+	return 0;
+}
+
+static int cs53l32a_detach(struct i2c_client *client)
+{
+	int err;
+
+	err = i2c_detach_client(client);
+	if (err) {
+		return err;
+	}
+	kfree(client);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+	.name = "cs53l32a",
+	.id = I2C_DRIVERID_CS53L32A,
+	.flags = I2C_DF_NOTIFY,
+	.attach_adapter = cs53l32a_probe,
+	.detach_client = cs53l32a_detach,
+	.command = cs53l32a_command,
+	.owner = THIS_MODULE,
+};
+
+
+static int __init cs53l32a_init_module(void)
+{
+	return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit cs53l32a_cleanup_module(void)
+{
+	i2c_del_driver(&i2c_driver);
+}
+
+module_init(cs53l32a_init_module);
+module_exit(cs53l32a_cleanup_module);
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
new file mode 100644
index 0000000..41818b6
--- /dev/null
+++ b/drivers/media/video/cx88/Kconfig
@@ -0,0 +1,91 @@
+config VIDEO_CX88
+	tristate "Conexant 2388x (bt878 successor) support"
+	depends on VIDEO_DEV && PCI && I2C
+	select I2C_ALGOBIT
+	select FW_LOADER
+	select VIDEO_BTCX
+	select VIDEO_BUF
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_IR
+	---help---
+	  This is a video4linux driver for Conexant 2388x based
+	  TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx8800
+
+config VIDEO_CX88_DVB
+	tristate "DVB/ATSC Support for cx2388x based TV cards"
+	depends on VIDEO_CX88 && DVB_CORE
+	select VIDEO_BUF_DVB
+	---help---
+	  This adds support for DVB/ATSC cards based on the
+	  Connexant 2388x chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx88-dvb.
+
+	  You must also select one or more DVB/ATSC demodulators.
+	  If you are unsure which you need, choose all of them.
+
+config VIDEO_CX88_DVB_ALL_FRONTENDS
+	bool "Build all supported frontends for cx2388x based TV cards"
+	default y
+	depends on VIDEO_CX88_DVB
+	select DVB_MT352
+	select DVB_OR51132
+	select DVB_CX22702
+	select DVB_LGDT330X
+	select DVB_NXT200X
+	---help---
+	  This builds cx88-dvb with all currently supported frontend
+	  demodulators.  If you wish to tweak your configuration, and
+	  only include support for the hardware that you need, choose N here.
+
+	  If you are unsure, choose Y.
+
+config VIDEO_CX88_DVB_MT352
+	tristate "Zarlink MT352 DVB-T Support"
+	default m
+	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+	select DVB_MT352
+	---help---
+	  This adds DVB-T support for cards based on the
+	  Connexant 2388x chip and the MT352 demodulator.
+
+config VIDEO_CX88_DVB_OR51132
+	tristate "OR51132 ATSC Support"
+	default m
+	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+	select DVB_OR51132
+	---help---
+	  This adds ATSC 8VSB and QAM64/256 support for cards based on the
+	  Connexant 2388x chip and the OR51132 demodulator.
+
+config VIDEO_CX88_DVB_CX22702
+	tristate "Conexant CX22702 DVB-T Support"
+	default m
+	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+	select DVB_CX22702
+	---help---
+	  This adds DVB-T support for cards based on the
+	  Connexant 2388x chip and the CX22702 demodulator.
+
+config VIDEO_CX88_DVB_LGDT330X
+	tristate "LG Electronics DT3302/DT3303 ATSC Support"
+	default m
+	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+	select DVB_LGDT330X
+	---help---
+	  This adds ATSC 8VSB and QAM64/256 support for cards based on the
+	  Connexant 2388x chip and the LGDT3302/LGDT3303 demodulator.
+
+config VIDEO_CX88_DVB_NXT200X
+	tristate "NXT2002/NXT2004 ATSC Support"
+	default m
+	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+	select DVB_NXT200X
+	---help---
+	  This adds ATSC 8VSB and QAM64/256 support for cards based on the
+	  Connexant 2388x chip and the NXT2002/NXT2004 demodulator.
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 107e486..0df40b7 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -9,6 +9,9 @@
 EXTRA_CFLAGS += -I$(src)/..
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+ifneq ($(CONFIG_VIDEO_BUF_DVB),n)
+ EXTRA_CFLAGS += -DHAVE_VIDEO_BUF_DVB=1
+endif
 ifneq ($(CONFIG_DVB_CX22702),n)
  EXTRA_CFLAGS += -DHAVE_CX22702=1
 endif
@@ -21,3 +24,6 @@
 ifneq ($(CONFIG_DVB_MT352),n)
  EXTRA_CFLAGS += -DHAVE_MT352=1
 endif
+ifneq ($(CONFIG_DVB_NXT200X),n)
+ EXTRA_CFLAGS += -DHAVE_NXT200X=1
+endif
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 0c0c59e..4ae3f78 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -38,7 +38,7 @@
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
-static unsigned int mpegbufs = 8;
+static unsigned int mpegbufs = 32;
 module_param(mpegbufs,int,0644);
 MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
 
@@ -436,7 +436,7 @@
 
 static int memory_read(struct cx88_core *core, u32 address, u32 *value)
 {
-        int retval;
+	int retval;
 	u32 val;
 
 	/* Warning: address is dword address (4 bytes) */
@@ -605,11 +605,11 @@
 	u32 *dataptr;
 
 	retval  = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED);
-        retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
-        retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
-        retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+	retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+	retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
+	retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
 	msleep(1);
-        retval |= register_write(dev->core, IVTV_REG_APU, 0);
+	retval |= register_write(dev->core, IVTV_REG_APU, 0);
 
 	if (retval < 0)
 		dprintk(0, "Error with register_write\n");
@@ -657,13 +657,13 @@
 	release_firmware(firmware);
 	dprintk(0, "Firmware upload successful.\n");
 
-        retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
-        retval |= register_read(dev->core, IVTV_REG_SPU, &value);
-        retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
+	retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+	retval |= register_read(dev->core, IVTV_REG_SPU, &value);
+	retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
 	msleep(1);
 
 	retval |= register_read(dev->core, IVTV_REG_VPU, &value);
-        retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
+	retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
 
 	if (retval < 0)
 		dprintk(0, "Error with register_write\n");
@@ -683,84 +683,560 @@
 =================================================================================================================
 *DB: "DirectBurn"
 */
-static void blackbird_codec_settings(struct cx8802_dev *dev)
+
+static struct blackbird_dnr default_dnr_params = {
+	.mode     = BLACKBIRD_DNR_BITS_MANUAL,
+	.type     = BLACKBIRD_MEDIAN_FILTER_DISABLED,
+	.spatial  = 0,
+	.temporal = 0
+};
+static struct v4l2_mpeg_compression default_mpeg_params = {
+	.st_type          = V4L2_MPEG_PS_2,
+	.st_bitrate       = {
+		.mode     = V4L2_BITRATE_CBR,
+		.min      = 0,
+		.target   = 0,
+		.max      = 0
+	},
+	.ts_pid_pmt       = 16,
+	.ts_pid_audio     = 260,
+	.ts_pid_video     = 256,
+	.ts_pid_pcr       = 259,
+	.ps_size          = 0,
+	.au_type          = V4L2_MPEG_AU_2_II,
+	.au_bitrate       = {
+		.mode     = V4L2_BITRATE_CBR,
+		.min      = 224,
+		.target   = 224,
+		.max      = 224
+	},
+	.au_sample_rate    = 44100,
+	.au_pesid          = 0,
+	.vi_type           = V4L2_MPEG_VI_2,
+	.vi_aspect_ratio   = V4L2_MPEG_ASPECT_4_3,
+	.vi_bitrate        = {
+		.mode      = V4L2_BITRATE_CBR,
+		.min       = 4000,
+		.target    = 4500,
+		.max       = 6000
+	},
+	.vi_frame_rate     = 25,
+	.vi_frames_per_gop = 15,
+	.vi_bframes_count  = 2,
+	.vi_pesid          = 0,
+	.closed_gops       = 0,
+	.pulldown          = 0
+};
+
+static enum blackbird_stream_type mpeg_stream_types[] = {
+	[V4L2_MPEG_SS_1]   = BLACKBIRD_STREAM_MPEG1,
+	[V4L2_MPEG_PS_2]   = BLACKBIRD_STREAM_PROGRAM,
+	[V4L2_MPEG_TS_2]   = BLACKBIRD_STREAM_TRANSPORT,
+	[V4L2_MPEG_PS_DVD] = BLACKBIRD_STREAM_DVD,
+};
+static enum blackbird_aspect_ratio mpeg_stream_ratios[] = {
+	[V4L2_MPEG_ASPECT_SQUARE] = BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
+	[V4L2_MPEG_ASPECT_4_3]    = BLACKBIRD_ASPECT_RATIO_4_3,
+	[V4L2_MPEG_ASPECT_16_9]   = BLACKBIRD_ASPECT_RATIO_16_9,
+	[V4L2_MPEG_ASPECT_1_221]  = BLACKBIRD_ASPECT_RATIO_221_100,
+};
+static enum blackbird_video_bitrate_type mpeg_video_bitrates[] = {
+	[V4L2_BITRATE_NONE] = BLACKBIRD_VIDEO_CBR,
+	[V4L2_BITRATE_CBR]  = BLACKBIRD_VIDEO_CBR,
+	[V4L2_BITRATE_VBR]  = BLACKBIRD_VIDEO_VBR,
+};
+/* find the best layer I/II bitrate to fit a given numeric value */
+struct bitrate_bits {
+	u32 bits; /* layer bits for the best fit */
+	u32 rate; /* actual numeric value for the layer best fit */
+};
+struct bitrate_approximation {
+	u32                 target;   /* numeric value of the rate we want */
+	struct bitrate_bits layer[2];
+};
+static struct bitrate_approximation mpeg_audio_bitrates[] = {
+	/* target  layer[0].bits           layer[0].rate       layer[1].bits           layer[1].rate */
+	{   0, { {                                0,   0, }, {                                0,   0, }, }, },
+	{  32, { { BLACKBIRD_AUDIO_BITS_LAYER_1_32 ,  32, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_32 ,  32, }, }, },
+	{  48, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 ,  64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_48 ,  48, }, }, },
+	{  56, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 ,  64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_56 ,  56, }, }, },
+	{  64, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 ,  64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_64 ,  64, }, }, },
+	{  80, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 ,  96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_80 ,  80, }, }, },
+	{  96, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 ,  96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_96 ,  96, }, }, },
+	{ 112, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_112, 112, }, }, },
+	{ 128, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_128, 128, }, }, },
+	{ 160, { { BLACKBIRD_AUDIO_BITS_LAYER_1_160, 160, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_160, 160, }, }, },
+	{ 192, { { BLACKBIRD_AUDIO_BITS_LAYER_1_192, 192, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_192, 192, }, }, },
+	{ 224, { { BLACKBIRD_AUDIO_BITS_LAYER_1_224, 224, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_224, 224, }, }, },
+	{ 256, { { BLACKBIRD_AUDIO_BITS_LAYER_1_256, 256, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_256, 256, }, }, },
+	{ 288, { { BLACKBIRD_AUDIO_BITS_LAYER_1_288, 288, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
+	{ 320, { { BLACKBIRD_AUDIO_BITS_LAYER_1_320, 320, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
+	{ 352, { { BLACKBIRD_AUDIO_BITS_LAYER_1_352, 352, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+	{ 384, { { BLACKBIRD_AUDIO_BITS_LAYER_1_384, 384, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+	{ 416, { { BLACKBIRD_AUDIO_BITS_LAYER_1_416, 416, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+	{ 448, { { BLACKBIRD_AUDIO_BITS_LAYER_1_448, 448, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+};
+static const int BITRATES_SIZE = ARRAY_SIZE(mpeg_audio_bitrates);
+
+static void blackbird_set_default_params(struct cx8802_dev *dev)
 {
-	int bitrate_mode = 1;
-	int bitrate = 7500000;
-	int bitrate_peak = 7500000;
-	bitrate_mode = BLACKBIRD_VIDEO_CBR;
-	bitrate = 4000*1024;
-	bitrate_peak = 4000*1024;
+	struct v4l2_mpeg_compression *params = &dev->params;
+	u32 au_params;
 
 	/* assign stream type */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM);
-
-	/* assign output port */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
+	if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
+		params->st_type = V4L2_MPEG_PS_2;
+	if( params->st_type == V4L2_MPEG_SS_1 )
+		params->vi_type = V4L2_MPEG_VI_1;
+	else
+		params->vi_type = V4L2_MPEG_VI_2;
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
 
 	/* assign framerate */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
-
-	/* assign frame size */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
-			  dev->height, dev->width);
+	if( params->vi_frame_rate <= 25 )
+	{
+		params->vi_frame_rate = 25;
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
+	}
+	else
+	{
+		params->vi_frame_rate = 30;
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
+	}
 
 	/* assign aspect ratio */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, BLACKBIRD_ASPECT_RATIO_4_3);
-
-	/* assign bitrates */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 5, 0,
-			 bitrate_mode,         /* mode */
-			 bitrate,              /* bps */
-			 bitrate_peak / BLACKBIRD_PEAK_RATE_DIVISOR,   /* peak/400 */
-			 BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/);             /* encoding buffer, ckennedy */
+	if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
+		params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
 
 	/* assign gop properties */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, 15, 3);
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
+
+	/* assign gop closure */
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
 
 	/* assign 3 2 pulldown */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, BLACKBIRD_3_2_PULLDOWN_DISABLED);
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
+
+	/* make sure the params are within bounds */
+	if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+		params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+	if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+		params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+	if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+		params->au_bitrate.mode = V4L2_BITRATE_NONE;
 
 	/* assign audio properties */
 	/* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
-	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4));
-	   blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4)); */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0,
-			BLACKBIRD_AUDIO_BITS_44100HZ |
-			BLACKBIRD_AUDIO_BITS_LAYER_2 |
-			BLACKBIRD_AUDIO_BITS_LAYER_2_224 |
-			BLACKBIRD_AUDIO_BITS_STEREO |
+	au_params = BLACKBIRD_AUDIO_BITS_STEREO |
 			/* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
 			BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
 			BLACKBIRD_AUDIO_BITS_CRC_OFF |
 			BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
-			BLACKBIRD_AUDIO_BITS_COPY
-		);
+			BLACKBIRD_AUDIO_BITS_COPY |
+			0;
+	if( params->au_sample_rate <= 32000 )
+	{
+		params->au_sample_rate = 32000;
+		au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
+	}
+	else if( params->au_sample_rate <= 44100 )
+	{
+		params->au_sample_rate = 44100;
+		au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
+	}
+	else
+	{
+		params->au_sample_rate = 48000;
+		au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
+	}
+	if( params->au_type == V4L2_MPEG_AU_2_I )
+	{
+		au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
+	}
+	else
+	{
+		/* TODO: try to handle the other formats more gracefully */
+		params->au_type = V4L2_MPEG_AU_2_II;
+		au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
+	}
+	if( params->au_bitrate.mode )
+	{
+		int layer;
+
+		if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
+			params->au_bitrate.max = params->vi_bitrate.target;
+		else
+			params->au_bitrate.target = params->vi_bitrate.max;
+
+		layer = params->au_type;
+		if( params->au_bitrate.target == 0 )
+		{
+			/* TODO: use the minimum possible bitrate instead of 0 ? */
+			au_params |= 0;
+		}
+		else if( params->au_bitrate.target >=
+			 mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
+		{
+			/* clamp the bitrate to the max supported by the standard */
+			params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
+			params->au_bitrate.max = params->au_bitrate.target;
+			au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
+		}
+		else
+		{
+			/* round up to the nearest supported bitrate */
+			int i;
+			for(i = 1; i < BITRATES_SIZE; i++)
+			{
+				if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
+				    params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
+				{
+					params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
+					params->au_bitrate.max = params->au_bitrate.target;
+					au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
+					break;
+				}
+			}
+		}
+	}
+	else
+	{
+		/* TODO: ??? */
+		params->au_bitrate.target = params->au_bitrate.max = 0;
+		au_params |= 0;
+	}
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
+
+	/* assign bitrates */
+	if( params->vi_bitrate.mode )
+	{
+		/* bitrate is set, let's figure out the cbr/vbr mess */
+		if( params->vi_bitrate.max < params->vi_bitrate.target )
+		{
+			if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
+				params->vi_bitrate.max = params->vi_bitrate.target;
+			else
+				params->vi_bitrate.target = params->vi_bitrate.max;
+		}
+	}
+	else
+	{
+		if( params->st_bitrate.max < params->st_bitrate.target )
+		{
+			if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
+				params->st_bitrate.target = params->st_bitrate.max;
+			else
+				params->st_bitrate.max = params->st_bitrate.target;
+		}
+		/* calculate vi_bitrate = st_bitrate - au_bitrate */
+		params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
+		params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
+	}
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
+				mpeg_video_bitrates[params->vi_bitrate.mode],
+				params->vi_bitrate.target * 1000, /* kbps -> bps */
+				params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
+				BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+
+	/* TODO: implement the stream ID stuff:
+		ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
+		ps_size, au_pesid, vi_pesid
+	*/
+}
+#define CHECK_PARAM( name ) ( dev->params.name != params->name )
+#define IF_PARAM( name ) if( CHECK_PARAM( name ) )
+#define UPDATE_PARAM( name ) dev->params.name = params->name
+void blackbird_set_params(struct cx8802_dev *dev, struct v4l2_mpeg_compression *params)
+{
+	u32 au_params;
+
+	/* assign stream type */
+	if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
+		params->st_type = V4L2_MPEG_PS_2;
+	if( params->st_type == V4L2_MPEG_SS_1 )
+		params->vi_type = V4L2_MPEG_VI_1;
+	else
+		params->vi_type = V4L2_MPEG_VI_2;
+	if( CHECK_PARAM( st_type ) || CHECK_PARAM( vi_type ) )
+	{
+		UPDATE_PARAM( st_type );
+		UPDATE_PARAM( vi_type );
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
+	}
+
+	/* assign framerate */
+	if( params->vi_frame_rate <= 25 )
+		params->vi_frame_rate = 25;
+	else
+		params->vi_frame_rate = 30;
+	IF_PARAM( vi_frame_rate )
+	{
+		UPDATE_PARAM( vi_frame_rate );
+		if( params->vi_frame_rate == 25 )
+			blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
+		else
+			blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
+	}
+
+	/* assign aspect ratio */
+	if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
+		params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
+	IF_PARAM( vi_aspect_ratio )
+	{
+		UPDATE_PARAM( vi_aspect_ratio );
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
+	}
+
+	/* assign gop properties */
+	if( CHECK_PARAM( vi_frames_per_gop ) || CHECK_PARAM( vi_bframes_count ) )
+	{
+		UPDATE_PARAM( vi_frames_per_gop );
+		UPDATE_PARAM( vi_bframes_count );
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
+	}
 
 	/* assign gop closure */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, BLACKBIRD_GOP_CLOSURE_OFF);
+	IF_PARAM( closed_gops )
+	{
+		UPDATE_PARAM( closed_gops );
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
+	}
 
+	/* assign 3 2 pulldown */
+	IF_PARAM( pulldown )
+	{
+		UPDATE_PARAM( pulldown );
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
+	}
 
+	/* make sure the params are within bounds */
+	if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+		params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+	if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+		params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+	if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+		params->au_bitrate.mode = V4L2_BITRATE_NONE;
+
+	/* assign audio properties */
+	/* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
+	au_params = BLACKBIRD_AUDIO_BITS_STEREO |
+			/* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
+	BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
+		BLACKBIRD_AUDIO_BITS_CRC_OFF |
+		BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
+		BLACKBIRD_AUDIO_BITS_COPY |
+		0;
+	if( params->au_sample_rate < 32000 )
+	{
+		params->au_sample_rate = 32000;
+		au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
+	}
+	else if( params->au_sample_rate < 44100 )
+	{
+		params->au_sample_rate = 44100;
+		au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
+	}
+	else
+	{
+		params->au_sample_rate = 48000;
+		au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
+	}
+	if( params->au_type == V4L2_MPEG_AU_2_I )
+	{
+		au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
+	}
+	else
+	{
+		/* TODO: try to handle the other formats more gracefully */
+		params->au_type = V4L2_MPEG_AU_2_II;
+		au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
+	}
+	if( params->au_bitrate.mode )
+	{
+		int layer;
+
+		if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
+			params->au_bitrate.max = params->vi_bitrate.target;
+		else
+			params->au_bitrate.target = params->vi_bitrate.max;
+
+		layer = params->au_type;
+		if( params->au_bitrate.target == 0 )
+		{
+			/* TODO: use the minimum possible bitrate instead of 0 ? */
+			au_params |= 0;
+		}
+		else if( params->au_bitrate.target >=
+			 mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
+		{
+			/* clamp the bitrate to the max supported by the standard */
+			params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
+			params->au_bitrate.max = params->au_bitrate.target;
+			au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
+		}
+		else
+		{
+			/* round up to the nearest supported bitrate */
+			int i;
+			for(i = 1; i < BITRATES_SIZE; i++)
+			{
+				if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
+				    params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
+				{
+					params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
+					params->au_bitrate.max = params->au_bitrate.target;
+					au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
+					break;
+				}
+			}
+		}
+	}
+	else
+	{
+		/* TODO: ??? */
+		params->au_bitrate.target = params->au_bitrate.max = 0;
+		au_params |= 0;
+	}
+	if( CHECK_PARAM( au_type ) || CHECK_PARAM( au_sample_rate )
+		|| CHECK_PARAM( au_bitrate.mode ) || CHECK_PARAM( au_bitrate.max )
+		|| CHECK_PARAM( au_bitrate.target )
+	)
+	{
+		UPDATE_PARAM( au_type );
+		UPDATE_PARAM( au_sample_rate );
+		UPDATE_PARAM( au_bitrate );
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
+	}
+
+	/* assign bitrates */
+	if( params->vi_bitrate.mode )
+	{
+		/* bitrate is set, let's figure out the cbr/vbr mess */
+		if( params->vi_bitrate.max < params->vi_bitrate.target )
+		{
+			if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
+				params->vi_bitrate.max = params->vi_bitrate.target;
+			else
+				params->vi_bitrate.target = params->vi_bitrate.max;
+		}
+	}
+	else
+	{
+		if( params->st_bitrate.max < params->st_bitrate.target )
+		{
+			if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
+				params->st_bitrate.target = params->st_bitrate.max;
+			else
+				params->st_bitrate.max = params->st_bitrate.target;
+		}
+		/* calculate vi_bitrate = st_bitrate - au_bitrate */
+		params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
+		params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
+	}
+	UPDATE_PARAM( st_bitrate );
+	if( CHECK_PARAM( vi_bitrate.mode ) || CHECK_PARAM( vi_bitrate.max )
+		|| CHECK_PARAM( vi_bitrate.target )
+	)
+	{
+		UPDATE_PARAM( vi_bitrate );
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
+				mpeg_video_bitrates[params->vi_bitrate.mode],
+				params->vi_bitrate.target * 1000, /* kbps -> bps */
+				params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
+				BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+	}
+
+	/* TODO: implement the stream ID stuff:
+		ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
+		ps_size, au_pesid, vi_pesid
+	*/
+	UPDATE_PARAM( ts_pid_pmt );
+	UPDATE_PARAM( ts_pid_audio );
+	UPDATE_PARAM( ts_pid_video );
+	UPDATE_PARAM( ts_pid_pcr );
+	UPDATE_PARAM( ps_size );
+	UPDATE_PARAM( au_pesid );
+	UPDATE_PARAM( vi_pesid );
+}
+
+static void blackbird_set_default_dnr_params(struct cx8802_dev *dev)
+{
 	/* assign dnr filter mode */
+	if( dev->dnr_params.mode > BLACKBIRD_DNR_BITS_AUTO )
+		dev->dnr_params.mode = BLACKBIRD_DNR_BITS_MANUAL;
+	if( dev->dnr_params.type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
+		dev->dnr_params.type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
 	blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0,
-			BLACKBIRD_DNR_BITS_MANUAL,
-			BLACKBIRD_MEDIAN_FILTER_DISABLED
-		);
+				dev->dnr_params.mode,
+				dev->dnr_params.type
+			);
 
 	/* assign dnr filter props*/
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, 0, 0);
+	if( dev->dnr_params.spatial > 15 )
+		dev->dnr_params.spatial = 15;
+	if( dev->dnr_params.temporal > 31 )
+		dev->dnr_params.temporal = 31;
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0,
+				dev->dnr_params.spatial,
+				dev->dnr_params.temporal
+			);
+}
+#define CHECK_DNR_PARAM( name ) ( dev->dnr_params.name != dnr_params->name )
+#define UPDATE_DNR_PARAM( name ) dev->dnr_params.name = dnr_params->name
+void blackbird_set_dnr_params(struct cx8802_dev *dev, struct blackbird_dnr* dnr_params)
+{
+	/* assign dnr filter mode */
+	/* clamp values */
+	if( dnr_params->mode > BLACKBIRD_DNR_BITS_AUTO )
+		dnr_params->mode = BLACKBIRD_DNR_BITS_MANUAL;
+	if( dnr_params->type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
+		dnr_params->type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
+	/* check if the params actually changed */
+	if( CHECK_DNR_PARAM( mode ) || CHECK_DNR_PARAM( type ) )
+	{
+		UPDATE_DNR_PARAM( mode );
+		UPDATE_DNR_PARAM( type );
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0, dnr_params->mode, dnr_params->type);
+	}
+
+	/* assign dnr filter props*/
+	if( dnr_params->spatial > 15 )
+		dnr_params->spatial = 15;
+	if( dnr_params->temporal > 31 )
+		dnr_params->temporal = 31;
+	if( CHECK_DNR_PARAM( spatial ) || CHECK_DNR_PARAM( temporal ) )
+	{
+		UPDATE_DNR_PARAM( spatial );
+		UPDATE_DNR_PARAM( temporal );
+		blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, dnr_params->spatial, dnr_params->temporal);
+	}
+}
+
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+
+	/* assign output port */
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
+
+	/* assign frame size */
+	blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
+				dev->height, dev->width);
 
 	/* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
 	blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MEDIAN, 4, 0, 0, 255, 0, 255);
 
 	/* assign spatial filter type: luma_t: horiz_only, chroma_t: horiz_only */
 	blackbird_api_cmd(dev, BLACKBIRD_API_SET_SPATIAL_FILTER, 2, 0,
-			BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
-			BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
-		);
+				BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
+				BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
+			);
 
 	/* assign frame drop rate */
 	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); */
+
+	blackbird_set_default_params(dev);
+	blackbird_set_default_dnr_params(dev);
 }
 
 static int blackbird_initialize_codec(struct cx8802_dev *dev)
@@ -851,15 +1327,10 @@
 	struct cx8802_fh *fh = q->priv_data;
 
 	fh->dev->ts_packet_size  = 188 * 4; /* was: 512 */
-	fh->dev->ts_packet_count = 32; /* was: 100 */
+	fh->dev->ts_packet_count = mpegbufs; /* was: 100 */
 
 	*size = fh->dev->ts_packet_size * fh->dev->ts_packet_count;
-	if (0 == *count)
-		*count = mpegbufs;
-	if (*count < 2)
-		*count = 2;
-	if (*count > 32)
-		*count = 32;
+	*count = fh->dev->ts_packet_count;
 	return 0;
 }
 
@@ -868,7 +1339,7 @@
 	       enum v4l2_field field)
 {
 	struct cx8802_fh *fh = q->priv_data;
-	return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb);
+	return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb, field);
 }
 
 static void
@@ -920,8 +1391,6 @@
 			V4L2_CAP_VIDEO_CAPTURE |
 			V4L2_CAP_READWRITE     |
 			V4L2_CAP_STREAMING     |
-			V4L2_CAP_VBI_CAPTURE   |
-			V4L2_CAP_VIDEO_OVERLAY |
 			0;
 		if (UNSET != core->tuner_type)
 			cap->capabilities |= V4L2_CAP_TUNER;
@@ -941,27 +1410,52 @@
 
 		memset(f,0,sizeof(*f));
 		f->index = index;
-		strlcpy(f->description, "MPEG TS", sizeof(f->description));
+		strlcpy(f->description, "MPEG", sizeof(f->description));
 		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 		f->pixelformat = V4L2_PIX_FMT_MPEG;
 		return 0;
 	}
 	case VIDIOC_G_FMT:
-	case VIDIOC_S_FMT:
-	case VIDIOC_TRY_FMT:
 	{
-		/* FIXME -- quick'n'dirty for exactly one size ... */
 		struct v4l2_format *f = arg;
 
 		memset(f,0,sizeof(*f));
 		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+		f->fmt.pix.bytesperline = 0;
+		f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
+		f->fmt.pix.colorspace   = 0;
 		f->fmt.pix.width        = dev->width;
 		f->fmt.pix.height       = dev->height;
+		f->fmt.pix.field        = fh->mpegq.field;
+		dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+			dev->width, dev->height, fh->mpegq.field );
+		return 0;
+	}
+	case VIDIOC_TRY_FMT:
+	{
+		struct v4l2_format *f = arg;
+
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-		f->fmt.pix.field        = V4L2_FIELD_NONE;
 		f->fmt.pix.bytesperline = 0;
-		f->fmt.pix.sizeimage    = 188 * 4 * 1024; /* 1024 * 512 */ /* FIXME: BUFFER_SIZE */;
+		f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
 		f->fmt.pix.colorspace   = 0;
+		dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+			dev->width, dev->height, fh->mpegq.field );
+		return 0;
+	}
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *f = arg;
+
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+		f->fmt.pix.bytesperline = 0;
+		f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+		f->fmt.pix.colorspace   = 0;
+		dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+			f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
 		return 0;
 	}
 
@@ -985,6 +1479,22 @@
 	case VIDIOC_STREAMOFF:
 		return videobuf_streamoff(&fh->mpegq);
 
+	/* --- mpeg compression -------------------------------------- */
+	case VIDIOC_G_MPEGCOMP:
+	{
+		struct v4l2_mpeg_compression *f = arg;
+
+		memcpy(f,&dev->params,sizeof(*f));
+		return 0;
+	}
+	case VIDIOC_S_MPEGCOMP:
+	{
+		struct v4l2_mpeg_compression *f = arg;
+
+		blackbird_set_params(dev, f);
+		return 0;
+	}
+
 	default:
 		return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook );
 	}
@@ -1034,16 +1544,17 @@
 	file->private_data = fh;
 	fh->dev      = dev;
 
-	/* FIXME: locking against other video device */
-	cx88_set_scale(dev->core, dev->width, dev->height,
-		       V4L2_FIELD_INTERLACED);
-
 	videobuf_queue_init(&fh->mpegq, &blackbird_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			    V4L2_FIELD_TOP,
+			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct cx88_buffer),
 			    fh);
+
+	/* FIXME: locking against other video device */
+	cx88_set_scale(dev->core, dev->width, dev->height,
+			fh->mpegq.field);
+
 	return 0;
 }
 
@@ -1173,6 +1684,8 @@
 	dev->core = core;
 	dev->width = 720;
 	dev->height = 576;
+	memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
+	memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
 
 	err = cx8802_init_common(dev);
 	if (0 != err)
@@ -1199,7 +1712,7 @@
 
 static void __devexit blackbird_remove(struct pci_dev *pci_dev)
 {
-        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 
 	/* blackbird */
 	blackbird_unregister_video(dev);
@@ -1215,8 +1728,8 @@
 	{
 		.vendor       = 0x14f1,
 		.device       = 0x8802,
-                .subvendor    = PCI_ANY_ID,
-                .subdevice    = PCI_ANY_ID,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
 	},{
 		/* --- end of list --- */
 	}
@@ -1224,10 +1737,10 @@
 MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
 
 static struct pci_driver blackbird_pci_driver = {
-        .name     = "cx88-blackbird",
-        .id_table = cx8802_pci_tbl,
-        .probe    = blackbird_probe,
-        .remove   = __devexit_p(blackbird_remove),
+	.name     = "cx88-blackbird",
+	.id_table = cx8802_pci_tbl,
+	.probe    = blackbird_probe,
+	.remove   = __devexit_p(blackbird_remove),
 	.suspend  = cx8802_suspend_common,
 	.resume   = cx8802_resume_common,
 };
@@ -1257,6 +1770,8 @@
 
 EXPORT_SYMBOL(cx88_ioctl_hook);
 EXPORT_SYMBOL(cx88_ioctl_translator);
+EXPORT_SYMBOL(blackbird_set_params);
+EXPORT_SYMBOL(blackbird_set_dnr_params);
 
 /* ----------------------------------------------------------- */
 /*
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 4da91d5..f226863 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -126,27 +126,27 @@
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-                        .gpio0  = 0x03ff,
+			.gpio0  = 0x03ff,
 		},{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
-                        .gpio0  = 0x03fe,
+			.gpio0  = 0x03fe,
 		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-                        .gpio0  = 0x03fe,
+			.gpio0  = 0x03fe,
 		}},
 	},
-        [CX88_BOARD_WINFAST2000XP_EXPERT] = {
-                .name           = "Leadtek Winfast 2000XP Expert",
-                .tuner_type     = TUNER_PHILIPS_4IN1,
+	[CX88_BOARD_WINFAST2000XP_EXPERT] = {
+		.name           = "Leadtek Winfast 2000XP Expert",
+		.tuner_type     = TUNER_PHILIPS_4IN1,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-                .input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
 			.gpio0	= 0x00F5e700,
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x00F5e700,
@@ -165,16 +165,16 @@
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x00F5c700,
 			.gpio3  = 0x02000000,
-                }},
-                .radio = {
-                        .type   = CX88_RADIO,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
 			.gpio0	= 0x00F5d700,
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x00F5d700,
 			.gpio3  = 0x02000000,
-                },
-        },
-	[CX88_BOARD_AVERTV_303] = {
+		},
+	},
+	[CX88_BOARD_AVERTV_STUDIO_303] = {
 		.name           = "AverTV Studio 303 (M126)",
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
 		.radio_type     = UNSET,
@@ -206,7 +206,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.tda9887_conf	= TDA9887_PRESENT,
+		.tda9887_conf	= TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC,
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
@@ -214,32 +214,32 @@
 			.gpio1  = 0x000080c0,
 			.gpio2  = 0x0000ff40,
 		},{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
 			.gpio0  = 0x000040bf,
 			.gpio1  = 0x000080c0,
 			.gpio2  = 0x0000ff40,
 		},{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
 			.gpio0  = 0x000040bf,
 			.gpio1  = 0x000080c0,
 			.gpio2  = 0x0000ff40,
-                }},
-                .radio = {
+		}},
+		.radio = {
 			 .type   = CX88_RADIO,
-                },
+		},
 	},
 	[CX88_BOARD_WINFAST_DV2000] = {
-                .name           = "Leadtek Winfast DV2000",
-                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.name           = "Leadtek Winfast DV2000",
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-                .input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
 			.gpio0  = 0x0035e700,
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x0035e700,
@@ -260,14 +260,14 @@
 			.gpio2  = 0x02000000,
 			.gpio3  = 0x02000000,
 		}},
-                .radio = {
+		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x0035d700,
 			.gpio1  = 0x00007004,
 			.gpio2  = 0x0035d700,
 			.gpio3  = 0x02000000,
 		 },
-        },
+	},
 	[CX88_BOARD_LEADTEK_PVR2000] = {
 		// gpio values for PAL version from regspy by DScaler
 		.name           = "Leadtek PVR 2000",
@@ -296,25 +296,25 @@
 		.blackbird = 1,
 	},
 	[CX88_BOARD_IODATA_GVVCP3PCI] = {
- 		.name		= "IODATA GV-VCP3/PCI",
+		.name		= "IODATA GV-VCP3/PCI",
 		.tuner_type     = TUNER_ABSENT,
- 		.radio_type     = UNSET,
+		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.input          = {{
- 			.type   = CX88_VMUX_COMPOSITE1,
- 			.vmux   = 0,
- 		},{
- 			.type   = CX88_VMUX_COMPOSITE2,
- 			.vmux   = 1,
- 		},{
- 			.type   = CX88_VMUX_SVIDEO,
- 			.vmux   = 2,
- 		}},
- 	},
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 0,
+		},{
+			.type   = CX88_VMUX_COMPOSITE2,
+			.vmux   = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+		}},
+	},
 	[CX88_BOARD_PROLINK_PLAYTVPVR] = {
-                .name           = "Prolink PlayTV PVR",
-                .tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+		.name           = "Prolink PlayTV PVR",
+		.tuner_type     = TUNER_PHILIPS_FM1236_MK3,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
@@ -348,15 +348,15 @@
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0000fde6,
- 		},{
+		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
 		}},
-                .radio = {
-                        .type   = CX88_RADIO,
+		.radio = {
+			.type   = CX88_RADIO,
 			.gpio0  = 0x0000fde2,
-                },
+		},
 		.blackbird = 1,
 	},
 	[CX88_BOARD_MSI_TVANYWHERE] = {
@@ -372,34 +372,34 @@
 			.gpio0  = 0x00000fbf,
 			.gpio2  = 0x0000fc08,
 		},{
-  			.type   = CX88_VMUX_COMPOSITE1,
-  			.vmux   = 1,
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
 			.gpio0  = 0x00000fbf,
 			.gpio2  = 0x0000fc68,
 		},{
-  			.type   = CX88_VMUX_SVIDEO,
-  			.vmux   = 2,
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
 			.gpio0  = 0x00000fbf,
 			.gpio2  = 0x0000fc68,
-  		}},
+		}},
 	},
-        [CX88_BOARD_KWORLD_DVB_T] = {
-                .name           = "KWorld/VStream XPert DVB-T",
+	[CX88_BOARD_KWORLD_DVB_T] = {
+		.name           = "KWorld/VStream XPert DVB-T",
 		.tuner_type     = TUNER_ABSENT,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-                .input          = {{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-                }},
+		}},
 		.dvb            = 1,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
@@ -425,27 +425,27 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-                .input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
-                        .gpio0  = 0x07f8,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x07f8,
 		},{
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 0,
 			.gpio0  = 0x07f9,  // mono from tuner chip
-                },{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
-                        .gpio0  = 0x000007fa,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
-                        .gpio0  = 0x000007fa,
-                }},
-                .radio = {
-                        .type   = CX88_RADIO,
-                        .gpio0  = 0x000007f8,
-                },
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000007fa,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000007fa,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x000007f8,
+		},
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = {
 		.name		= "DViCO FusionHDTV 3 Gold-Q",
@@ -489,28 +489,28 @@
 		}},
 		.dvb            = 1,
 	},
-        [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
+	[CX88_BOARD_HAUPPAUGE_DVB_T1] = {
 		.name           = "Hauppauge Nova-T DVB-T",
 		.tuner_type     = TUNER_ABSENT,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.input          = {{
-                        .type   = CX88_VMUX_DVB,
-                        .vmux   = 0,
-                }},
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		}},
 		.dvb            = 1,
 	},
-        [CX88_BOARD_CONEXANT_DVB_T1] = {
+	[CX88_BOARD_CONEXANT_DVB_T1] = {
 		.name           = "Conexant DVB-T reference design",
 		.tuner_type     = TUNER_ABSENT,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-                .input          = {{
-                        .type   = CX88_VMUX_DVB,
-                        .vmux   = 0,
-                }},
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		}},
 		.dvb            = 1,
 	},
 	[CX88_BOARD_PROVIDEO_PV259] = {
@@ -543,12 +543,12 @@
 		.dvb            = 1,
 	},
 	[CX88_BOARD_DNTV_LIVE_DVB_T] = {
-		.name	        = "digitalnow DNTV Live! DVB-T",
+		.name		= "digitalnow DNTV Live! DVB-T",
 		.tuner_type     = TUNER_ABSENT,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input	        = {{
+		.input		= {{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00000700,
@@ -705,44 +705,44 @@
 			 .gpio0 = 0xbf60,
 		 },
 	},
-        [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
+	[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
 		.name           = "DViCO FusionHDTV 3 Gold-T",
 		.tuner_type     = TUNER_THOMSON_DTT7611,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
-                        .gpio0  = 0x97ed,
-                },{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
-                        .gpio0  = 0x97e9,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
-                        .gpio0  = 0x97e9,
-                }},
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x97ed,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x97e9,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x97e9,
+		}},
 		.dvb            = 1,
-        },
-        [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
-                .name           = "ADS Tech Instant TV DVB-T PCI",
+	},
+	[CX88_BOARD_ADSTECH_DVB_T_PCI] = {
+		.name           = "ADS Tech Instant TV DVB-T PCI",
 		.tuner_type     = TUNER_ABSENT,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.input          = {{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-                }},
+		}},
 		.dvb            = 1,
 	},
 	[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
@@ -762,20 +762,139 @@
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
 		.input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
-                        .gpio0  = 0x87fd,
-                },{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
-                        .gpio0  = 0x87f9,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
-                        .gpio0  = 0x87f9,
-                }},
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x87fd,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x87f9,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x87f9,
+		}},
 		.dvb            = 1,
 	},
+	[CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
+		.name           = "AverMedia UltraTV Media Center PCI 550",
+		.tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.blackbird      = 1,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 0,
+			.gpio0  = 0x0000cd73,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 1,
+			.gpio0  = 0x0000cd73,
+		},{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 3,
+			.gpio0  = 0x0000cdb3,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.vmux   = 2,
+			.gpio0  = 0x0000cdf3,
+		},
+	},
+	[CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = {
+		 /* Alexander Wold <awold@bigfoot.com> */
+		 .name           = "Kworld V-Stream Xpert DVD",
+		 .tuner_type     = UNSET,
+		 .input          = {{
+			 .type   = CX88_VMUX_COMPOSITE1,
+			 .vmux   = 1,
+			 .gpio0  = 0x03000000,
+			 .gpio1  = 0x01000000,
+			 .gpio2  = 0x02000000,
+			 .gpio3  = 0x00100000,
+		 },{
+			 .type   = CX88_VMUX_SVIDEO,
+			 .vmux   = 2,
+			 .gpio0  = 0x03000000,
+			 .gpio1  = 0x01000000,
+			 .gpio2  = 0x02000000,
+			 .gpio3  = 0x00100000,
+		 }},
+	},
+	[CX88_BOARD_ATI_HDTVWONDER] = {
+		.name           = "ATI HDTV Wonder",
+		.tuner_type     = TUNER_PHILIPS_TUV1236D,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00000ff7,
+			.gpio1  = 0x000000ff,
+			.gpio2  = 0x00000001,
+			.gpio3  = 0x00000000,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00000ffe,
+			.gpio1  = 0x000000ff,
+			.gpio2  = 0x00000001,
+			.gpio3  = 0x00000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00000ffe,
+			.gpio1  = 0x000000ff,
+			.gpio2  = 0x00000001,
+			.gpio3  = 0x00000000,
+		}},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_WINFAST_DTV1000] = {
+		.name           = "WinFast DTV1000-T",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		}},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_AVERTV_303] = {
+		.name           = "AVerTV 303 (M126)",
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00ff,
+			.gpio1  = 0xe09f,
+			.gpio2  = 0x0010,
+			.gpio3  = 0x0000,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00ff,
+			.gpio1  = 0xe05f,
+			.gpio2  = 0x0010,
+			.gpio3  = 0x0000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00ff,
+			.gpio1  = 0xe05f,
+			.gpio2  = 0x0010,
+			.gpio3  = 0x0000,
+		}},
+	},
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -804,41 +923,41 @@
 		.subdevice = 0x00f8,
 		.card      = CX88_BOARD_ATI_WONDER_PRO,
 	},{
-                .subvendor = 0x107d,
-                .subdevice = 0x6611,
-                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
-	},{
-                .subvendor = 0x107d,
-                .subdevice = 0x6613,	/* NTSC */
-                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
+		.subvendor = 0x107d,
+		.subdevice = 0x6611,
+		.card      = CX88_BOARD_WINFAST2000XP_EXPERT,
 	},{
 		.subvendor = 0x107d,
-                .subdevice = 0x6620,
-                .card      = CX88_BOARD_WINFAST_DV2000,
-        },{
-                .subvendor = 0x107d,
-                .subdevice = 0x663b,
-                .card      = CX88_BOARD_LEADTEK_PVR2000,
-        },{
-                .subvendor = 0x107d,
-                .subdevice = 0x663C,
-                .card      = CX88_BOARD_LEADTEK_PVR2000,
-        },{
+		.subdevice = 0x6613,	/* NTSC */
+		.card      = CX88_BOARD_WINFAST2000XP_EXPERT,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x6620,
+		.card      = CX88_BOARD_WINFAST_DV2000,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x663b,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x663C,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
+	},{
 		.subvendor = 0x1461,
 		.subdevice = 0x000b,
-		.card      = CX88_BOARD_AVERTV_303,
+		.card      = CX88_BOARD_AVERTV_STUDIO_303,
 	},{
 		.subvendor = 0x1462,
 		.subdevice = 0x8606,
 		.card      = CX88_BOARD_MSI_TVANYWHERE_MASTER,
 	},{
- 		.subvendor = 0x10fc,
- 		.subdevice = 0xd003,
- 		.card      = CX88_BOARD_IODATA_GVVCP3PCI,
+		.subvendor = 0x10fc,
+		.subdevice = 0xd003,
+		.card      = CX88_BOARD_IODATA_GVVCP3PCI,
 	},{
- 		.subvendor = 0x1043,
- 		.subdevice = 0x4823,  /* with mpeg encoder */
- 		.card      = CX88_BOARD_ASUS_PVR_416,
+		.subvendor = 0x1043,
+		.subdevice = 0x4823,  /* with mpeg encoder */
+		.card      = CX88_BOARD_ASUS_PVR_416,
 	},{
 		.subvendor = 0x17de,
 		.subdevice = 0x08a6,
@@ -852,43 +971,43 @@
 		.subdevice = 0xd820,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
 	},{
-		.subvendor = 0x18AC,
-		.subdevice = 0xDB00,
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb00,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
- 	},{
+	},{
 		.subvendor = 0x0070,
 		.subdevice = 0x9002,
 		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
- 	},{
+	},{
 		.subvendor = 0x14f1,
 		.subdevice = 0x0187,
 		.card      = CX88_BOARD_CONEXANT_DVB_T1,
- 	},{
+	},{
 		.subvendor = 0x1540,
 		.subdevice = 0x2580,
 		.card      = CX88_BOARD_PROVIDEO_PV259,
 	},{
-		.subvendor = 0x18AC,
-		.subdevice = 0xDB10,
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb10,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
 	},{
-                .subvendor = 0x1554,
-                .subdevice = 0x4811,
-                .card      = CX88_BOARD_PIXELVIEW,
+		.subvendor = 0x1554,
+		.subdevice = 0x4811,
+		.card      = CX88_BOARD_PIXELVIEW,
 	},{
 		.subvendor = 0x7063,
 		.subdevice = 0x3000, /* HD-3000 card */
 		.card      = CX88_BOARD_PCHDTV_HD3000,
 	},{
-		.subvendor = 0x17DE,
-		.subdevice = 0xA8A6,
+		.subvendor = 0x17de,
+		.subdevice = 0xa8a6,
 		.card      = CX88_BOARD_DNTV_LIVE_DVB_T,
 	},{
 		.subvendor = 0x0070,
 		.subdevice = 0x2801,
 		.card      = CX88_BOARD_HAUPPAUGE_ROSLYN,
 	},{
-		.subvendor = 0x14F1,
+		.subvendor = 0x14f1,
 		.subdevice = 0x0342,
 		.card      = CX88_BOARD_DIGITALLOGIC_MEC,
 	},{
@@ -899,14 +1018,30 @@
 		.subvendor = 0x1421,
 		.subdevice = 0x0334,
 		.card      = CX88_BOARD_ADSTECH_DVB_T_PCI,
- 	},{
+	},{
 		.subvendor = 0x153b,
 		.subdevice = 0x1166,
 		.card      = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
- 	},{
+	},{
 		.subvendor = 0x18ac,
 		.subdevice = 0xd500,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
+	},{
+		.subvendor = 0x1461,
+		.subdevice = 0x8011,
+		.card      = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
+	},{
+		.subvendor = PCI_VENDOR_ID_ATI,
+		.subdevice = 0xa101,
+		.card      = CX88_BOARD_ATI_HDTVWONDER,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x665f,
+		.card      = CX88_BOARD_WINFAST_DTV1000,
+	},{
+		.subvendor = 0x1461,
+		.subdevice = 0x000a,
+		.card      = CX88_BOARD_AVERTV_303,
 	},
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1108,6 +1243,19 @@
 		cx_clear(MO_GP0_IO, 0x00000007);
 		cx_set(MO_GP2_IO, 0x00000101);
 		break;
+	case CX88_BOARD_ATI_HDTVWONDER:
+		if (0 == core->i2c_rc) {
+			/* enable tuner */
+			int i;
+			u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+			core->i2c_client.addr = 0x0a;
+
+			for (i = 0; i < 5; i++)
+				if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2))
+					printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
+						core->name, i);
+		}
+		break;
 	}
 	if (cx88_boards[core->board].radio.type == CX88_RADIO)
 		core->has_radio = 1;
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index dc5c5c1..eb806af 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -31,7 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 
 #include "cx88.h"
 
@@ -153,26 +153,26 @@
 		}
 		if (bpl <= sg_dma_len(sg)-offset) {
 			/* fits into current chunk */
-                        *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
-                        *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                        offset+=bpl;
+			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			offset+=bpl;
 		} else {
 			/* scanline needs to be splitted */
-                        todo = bpl;
-                        *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+			todo = bpl;
+			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
 					    (sg_dma_len(sg)-offset));
-                        *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                        todo -= (sg_dma_len(sg)-offset);
-                        offset = 0;
-                        sg++;
-                        while (todo > sg_dma_len(sg)) {
-                                *(rp++)=cpu_to_le32(RISC_WRITE|
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			todo -= (sg_dma_len(sg)-offset);
+			offset = 0;
+			sg++;
+			while (todo > sg_dma_len(sg)) {
+				*(rp++)=cpu_to_le32(RISC_WRITE|
 						    sg_dma_len(sg));
-                                *(rp++)=cpu_to_le32(sg_dma_address(sg));
+				*(rp++)=cpu_to_le32(sg_dma_address(sg));
 				todo -= sg_dma_len(sg);
 				sg++;
 			}
-                        *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
 			*(rp++)=cpu_to_le32(sg_dma_address(sg));
 			offset += todo;
 		}
@@ -309,7 +309,7 @@
 		.name       = "video y / packed",
 		.cmds_start = 0x180040,
 		.ctrl_start = 0x180400,
-	        .cdt        = 0x180400 + 64,
+		.cdt        = 0x180400 + 64,
 		.fifo_start = 0x180c00,
 		.fifo_size  = 0x002800,
 		.ptr1_reg   = MO_DMA21_PTR1,
@@ -321,7 +321,7 @@
 		.name       = "video u",
 		.cmds_start = 0x180080,
 		.ctrl_start = 0x1804a0,
-	        .cdt        = 0x1804a0 + 64,
+		.cdt        = 0x1804a0 + 64,
 		.fifo_start = 0x183400,
 		.fifo_size  = 0x000800,
 		.ptr1_reg   = MO_DMA22_PTR1,
@@ -333,7 +333,7 @@
 		.name       = "video v",
 		.cmds_start = 0x1800c0,
 		.ctrl_start = 0x180540,
-	        .cdt        = 0x180540 + 64,
+		.cdt        = 0x180540 + 64,
 		.fifo_start = 0x183c00,
 		.fifo_size  = 0x000800,
 		.ptr1_reg   = MO_DMA23_PTR1,
@@ -345,7 +345,7 @@
 		.name       = "vbi",
 		.cmds_start = 0x180100,
 		.ctrl_start = 0x1805e0,
-	        .cdt        = 0x1805e0 + 64,
+		.cdt        = 0x1805e0 + 64,
 		.fifo_start = 0x184400,
 		.fifo_size  = 0x001000,
 		.ptr1_reg   = MO_DMA24_PTR1,
@@ -357,7 +357,7 @@
 		.name       = "audio from",
 		.cmds_start = 0x180140,
 		.ctrl_start = 0x180680,
-	        .cdt        = 0x180680 + 64,
+		.cdt        = 0x180680 + 64,
 		.fifo_start = 0x185400,
 		.fifo_size  = 0x000200,
 		.ptr1_reg   = MO_DMA25_PTR1,
@@ -369,7 +369,7 @@
 		.name       = "audio to",
 		.cmds_start = 0x180180,
 		.ctrl_start = 0x180720,
-	        .cdt        = 0x180680 + 64,  /* same as audio IN */
+		.cdt        = 0x180680 + 64,  /* same as audio IN */
 		.fifo_start = 0x185400,       /* same as audio IN */
 		.fifo_size  = 0x000200,       /* same as audio IN */
 		.ptr1_reg   = MO_DMA26_PTR1,
@@ -431,7 +431,7 @@
 /* ------------------------------------------------------------------ */
 /* debug helper code                                                  */
 
-int cx88_risc_decode(u32 risc)
+static int cx88_risc_decode(u32 risc)
 {
 	static char *instr[16] = {
 		[ RISC_SYNC    >> 28 ] = "sync",
@@ -845,19 +845,19 @@
 		return 0;
 
 	if (V4L2_STD_PAL_BG & norm->id) {
-		core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
+		core->tvaudio = WW_BG;
 
 	} else if (V4L2_STD_PAL_DK & norm->id) {
-		core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
+		core->tvaudio = WW_DK;
 
 	} else if (V4L2_STD_PAL_I & norm->id) {
-		core->tvaudio = WW_NICAM_I;
+		core->tvaudio = WW_I;
 
 	} else if (V4L2_STD_SECAM_L & norm->id) {
-		core->tvaudio = WW_SYSTEM_L_AM;
+		core->tvaudio = WW_L;
 
 	} else if (V4L2_STD_SECAM_DK & norm->id) {
-		core->tvaudio = WW_A2_DK;
+		core->tvaudio = WW_DK;
 
 	} else if ((V4L2_STD_NTSC_M & norm->id) ||
 		   (V4L2_STD_PAL_M  & norm->id)) {
@@ -1137,7 +1137,7 @@
 	if (!core->radio_addr)
 		core->radio_addr = cx88_boards[core->board].radio_addr;
 
-        printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
+	printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
 		core->tuner_type, core->tuner_addr<<1,
 		core->radio_type, core->radio_addr<<1);
 
@@ -1146,6 +1146,7 @@
 	/* init hardware */
 	cx88_reset(core);
 	cx88_i2c_init(core,pci);
+	cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
 	cx88_card_setup(core);
 	cx88_ir_init(core,pci);
 
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 4334744..9cce91e 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -29,7 +29,6 @@
 #include <linux/file.h>
 #include <linux/suspend.h>
 
-
 #include "cx88.h"
 #include "dvb-pll.h"
 
@@ -46,6 +45,9 @@
 #ifdef HAVE_LGDT330X
 # include "lgdt330x.h"
 #endif
+#ifdef HAVE_NXT200X
+# include "nxt200x.h"
+#endif
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -78,7 +80,7 @@
 			   enum v4l2_field field)
 {
 	struct cx8802_dev *dev = q->priv_data;
-	return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb);
+	return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb,field);
 }
 
 static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -129,7 +131,7 @@
 	static u8 reset []         = { 0x50, 0x80 };
 	static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
 	static u8 agc_cfg []       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
-	                               0x00, 0xFF, 0x00, 0x40, 0x40 };
+				       0x00, 0xFF, 0x00, 0x40, 0x40 };
 	static u8 dntv_extra[]     = { 0xB5, 0x7A };
 	static u8 capt_range_cfg[] = { 0x75, 0x32 };
 
@@ -285,6 +287,33 @@
 };
 #endif
 
+#ifdef HAVE_NXT200X
+static int nxt200x_set_ts_param(struct dvb_frontend* fe,
+				int is_punctured)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+	return 0;
+}
+
+static int nxt200x_set_pll_input(u8* buf, int input)
+{
+	if (input)
+		buf[3] |= 0x08;
+	else
+		buf[3] &= ~0x08;
+	return 0;
+}
+
+static struct nxt200x_config ati_hdtvwonder = {
+	.demod_address    = 0x0a,
+	.pll_address      = 0x61,
+	.pll_desc         = &dvb_pll_tuv1236d,
+	.set_pll_input    = nxt200x_set_pll_input,
+	.set_ts_params    = nxt200x_set_ts_param,
+};
+#endif
+
 static int dvb_register(struct cx8802_dev *dev)
 {
 	/* init struct videobuf_dvb */
@@ -300,6 +329,7 @@
 		break;
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
 	case CX88_BOARD_CONEXANT_DVB_T1:
+	case CX88_BOARD_WINFAST_DTV1000:
 		dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
 						   &dev->core->i2c_adap);
 		break;
@@ -385,6 +415,12 @@
 		}
 		break;
 #endif
+#ifdef HAVE_NXT200X
+	case CX88_BOARD_ATI_HDTVWONDER:
+		dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
+						 &dev->core->i2c_adap);
+		break;
+#endif
 	default:
 		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
@@ -403,6 +439,9 @@
 	/* Put the analog decoder in standby to keep it quiet */
 	cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
 
+	/* Put the analog decoder in standby to keep it quiet */
+	cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
 	/* register everything */
 	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
 }
@@ -461,7 +500,7 @@
 
 static void __devexit dvb_remove(struct pci_dev *pci_dev)
 {
-        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 
 	/* dvb */
 	videobuf_dvb_unregister(&dev->dvb);
@@ -476,8 +515,8 @@
 	{
 		.vendor       = 0x14f1,
 		.device       = 0x8802,
-                .subvendor    = PCI_ANY_ID,
-                .subdevice    = PCI_ANY_ID,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
 	},{
 		/* --- end of list --- */
 	}
@@ -485,10 +524,10 @@
 MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
 
 static struct pci_driver dvb_pci_driver = {
-        .name     = "cx88-dvb",
-        .id_table = cx8802_pci_tbl,
-        .probe    = dvb_probe,
-        .remove   = __devexit_p(dvb_remove),
+	.name     = "cx88-dvb",
+	.id_table = cx8802_pci_tbl,
+	.probe    = dvb_probe,
+	.remove   = __devexit_p(dvb_remove),
 	.suspend  = cx8802_suspend_common,
 	.resume   = cx8802_resume_common,
 };
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 761cebd..9790d41 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -3,7 +3,7 @@
     cx88-i2c.c  --  all the i2c code is here
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
@@ -90,7 +90,7 @@
 
 static int attach_inform(struct i2c_client *client)
 {
-        struct tuner_setup tun_setup;
+	struct tuner_setup tun_setup;
 	struct cx88_core *core = i2c_get_adapdata(client->adapter);
 
 	dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
@@ -98,7 +98,7 @@
 	if (!client->driver->command)
 		return 0;
 
-        if (core->radio_type != UNSET) {
+	if (core->radio_type != UNSET) {
 		if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) {
 			tun_setup.mode_mask = T_RADIO;
 			tun_setup.type = core->radio_type;
@@ -106,8 +106,8 @@
 
 			client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
-        }
-        if (core->tuner_type != UNSET) {
+	}
+	if (core->tuner_type != UNSET) {
 		if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) {
 
 			tun_setup.mode_mask = T_ANALOG_TV;
@@ -116,7 +116,7 @@
 
 			client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
-        }
+	}
 
 	if (core->tda9887_conf)
 		client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
@@ -159,7 +159,7 @@
 };
 
 static struct i2c_client cx8800_i2c_client_template = {
-        .name	= "cx88xx internal",
+	.name	= "cx88xx internal",
 };
 
 static char *i2c_devs[128] = {
@@ -202,10 +202,10 @@
 
 	core->i2c_adap.dev.parent = &pci->dev;
 	strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
-        core->i2c_algo.data = core;
-        i2c_set_adapdata(&core->i2c_adap,core);
-        core->i2c_adap.algo_data = &core->i2c_algo;
-        core->i2c_client.adapter = &core->i2c_adap;
+	core->i2c_algo.data = core;
+	i2c_set_adapdata(&core->i2c_adap,core);
+	core->i2c_adap.algo_data = &core->i2c_algo;
+	core->i2c_client.adapter = &core->i2c_adap;
 
 	cx8800_bit_setscl(core,1);
 	cx8800_bit_setsda(core,1);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index c27fe4c3..38b12eb 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -553,7 +553,7 @@
 
 		if ((ircode & 0xffff) != 0xeb04) { /* wrong address */
 			ir_dprintk("pulse distance decoded wrong address\n");
- 			break;
+			break;
 		}
 
 		if (((~ircode >> 24) & 0xff) != ((ircode >> 16) & 0xff)) { /* wrong checksum */
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index ee2300e..35e6d0c 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -54,7 +54,7 @@
 {
 	struct cx88_core *core = dev->core;
 
-	dprintk(0, "cx8802_start_dma %d\n", buf->vb.width);
+	dprintk(0, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
 
 	/* setup fifo + format */
 	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -158,7 +158,8 @@
 
 /* ------------------------------------------------------------------ */
 
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf)
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
+			enum v4l2_field field)
 {
 	int size = dev->ts_packet_size * dev->ts_packet_count;
 	int rc;
@@ -171,7 +172,7 @@
 		buf->vb.width  = dev->ts_packet_size;
 		buf->vb.height = dev->ts_packet_count;
 		buf->vb.size   = size;
-		buf->vb.field  = V4L2_FIELD_TOP;
+		buf->vb.field  = field /*V4L2_FIELD_TOP*/;
 
 		if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
 			goto fail;
@@ -315,14 +316,14 @@
 		spin_unlock(&dev->slock);
 	}
 
-        /* other general errors */
-        if (status & 0x1f0100) {
+	/* other general errors */
+	if (status & 0x1f0100) {
 		dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 );
-                spin_lock(&dev->slock);
+		spin_lock(&dev->slock);
 		cx8802_stop_dma(dev);
-                cx8802_restart_queue(dev,&dev->mpegq);
-                spin_unlock(&dev->slock);
-        }
+		cx8802_restart_queue(dev,&dev->mpegq);
+		spin_unlock(&dev->slock);
+	}
 }
 
 #define MAX_IRQ_LOOP 10
@@ -378,8 +379,8 @@
 	}
 
 	pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
-        pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER,  &dev->pci_lat);
-        printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
+	pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
 	       "latency: %d, mmio: 0x%lx\n", dev->core->name,
 	       pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
 	       dev->pci_lat,pci_resource_start(dev->pci,0));
@@ -429,7 +430,7 @@
 
 int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
 {
-        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 	struct cx88_core *core = dev->core;
 
 	/* stop mpeg dma */
diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h
index 0a3a62f..d3bf5b1 100644
--- a/drivers/media/video/cx88/cx88-reg.h
+++ b/drivers/media/video/cx88/cx88-reg.h
@@ -3,9 +3,9 @@
     cx88x-hw.h - CX2388x register offsets
 
     Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
-                  2001 Michael Eskin
-                  2002 Yurij Sysoev <yurij@naturesoft.net>
-                  2003 Gerd Knorr <kraxel@bytesex.org>
+		  2001 Michael Eskin
+		  2002 Yurij Sysoev <yurij@naturesoft.net>
+		  2003 Gerd Knorr <kraxel@bytesex.org>
 
     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
@@ -728,13 +728,13 @@
 #define ColorFormatGamma         0x1000
 
 #define Interlaced		 0x1
-#define NonInterlaced	 	 0x0
+#define NonInterlaced		 0x0
 
 #define FieldEven		 0x1
 #define FieldOdd		 0x0
 
-#define TGReadWriteMode	 	 0x0
-#define TGEnableMode	 	 0x1
+#define TGReadWriteMode		 0x0
+#define TGEnableMode		 0x1
 
 #define DV_CbAlign		 0x0
 #define DV_Y0Align		 0x1
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 2765ace..6d9bec1 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -57,39 +57,38 @@
 #include "cx88.h"
 
 static unsigned int audio_debug = 0;
-module_param(audio_debug,int,0644);
-MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
 
 #define dprintk(fmt, arg...)	if (audio_debug) \
 	printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
 
 /* ----------------------------------------------------------- */
 
-static char *aud_ctl_names[64] =
-{
-	[ EN_BTSC_FORCE_MONO       ] = "BTSC_FORCE_MONO",
-	[ EN_BTSC_FORCE_STEREO     ] = "BTSC_FORCE_STEREO",
-	[ EN_BTSC_FORCE_SAP        ] = "BTSC_FORCE_SAP",
-	[ EN_BTSC_AUTO_STEREO      ] = "BTSC_AUTO_STEREO",
-	[ EN_BTSC_AUTO_SAP         ] = "BTSC_AUTO_SAP",
-	[ EN_A2_FORCE_MONO1        ] = "A2_FORCE_MONO1",
-	[ EN_A2_FORCE_MONO2        ] = "A2_FORCE_MONO2",
-	[ EN_A2_FORCE_STEREO       ] = "A2_FORCE_STEREO",
-	[ EN_A2_AUTO_MONO2         ] = "A2_AUTO_MONO2",
-	[ EN_A2_AUTO_STEREO        ] = "A2_AUTO_STEREO",
-	[ EN_EIAJ_FORCE_MONO1      ] = "EIAJ_FORCE_MONO1",
-	[ EN_EIAJ_FORCE_MONO2      ] = "EIAJ_FORCE_MONO2",
-	[ EN_EIAJ_FORCE_STEREO     ] = "EIAJ_FORCE_STEREO",
-	[ EN_EIAJ_AUTO_MONO2       ] = "EIAJ_AUTO_MONO2",
-	[ EN_EIAJ_AUTO_STEREO      ] = "EIAJ_AUTO_STEREO",
-	[ EN_NICAM_FORCE_MONO1     ] = "NICAM_FORCE_MONO1",
-	[ EN_NICAM_FORCE_MONO2     ] = "NICAM_FORCE_MONO2",
-	[ EN_NICAM_FORCE_STEREO    ] = "NICAM_FORCE_STEREO",
-	[ EN_NICAM_AUTO_MONO2      ] = "NICAM_AUTO_MONO2",
-	[ EN_NICAM_AUTO_STEREO     ] = "NICAM_AUTO_STEREO",
-	[ EN_FMRADIO_FORCE_MONO    ] = "FMRADIO_FORCE_MONO",
-	[ EN_FMRADIO_FORCE_STEREO  ] = "FMRADIO_FORCE_STEREO",
-	[ EN_FMRADIO_AUTO_STEREO   ] = "FMRADIO_AUTO_STEREO",
+static char *aud_ctl_names[64] = {
+	[EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO",
+	[EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO",
+	[EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP",
+	[EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO",
+	[EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP",
+	[EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1",
+	[EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2",
+	[EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO",
+	[EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2",
+	[EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO",
+	[EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1",
+	[EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2",
+	[EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO",
+	[EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2",
+	[EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO",
+	[EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1",
+	[EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2",
+	[EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO",
+	[EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2",
+	[EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO",
+	[EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO",
+	[EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO",
+	[EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO",
 };
 
 struct rlist {
@@ -97,8 +96,7 @@
 	u32 val;
 };
 
-static void set_audio_registers(struct cx88_core *core,
-				const struct rlist *l)
+static void set_audio_registers(struct cx88_core *core, const struct rlist *l)
 {
 	int i;
 
@@ -119,17 +117,18 @@
 	}
 }
 
-static void set_audio_start(struct cx88_core *core,
-			u32 mode)
+static void set_audio_start(struct cx88_core *core, u32 mode)
 {
 	// mute
-	cx_write(AUD_VOL_CTL,       (1 << 6));
+	cx_write(AUD_VOL_CTL, (1 << 6));
 
 	// start programming
-	cx_write(AUD_CTL,           0x0000);
-	cx_write(AUD_INIT,          mode);
-	cx_write(AUD_INIT_LD,       0x0001);
-	cx_write(AUD_SOFT_RESET,    0x0001);
+	cx_write(MO_AUD_DMACNTRL, 0x0000);
+	msleep(100);
+	//cx_write(AUD_CTL, 0x0000);
+	cx_write(AUD_INIT, mode);
+	cx_write(AUD_INIT_LD, 0x0001);
+	cx_write(AUD_SOFT_RESET, 0x0001);
 }
 
 static void set_audio_finish(struct cx88_core *core, u32 ctl)
@@ -148,12 +147,13 @@
 		cx_write(AUD_I2SCNTL, 0);
 		//cx_write(AUD_APB_IN_RATE_ADJ, 0);
 	} else {
-	ctl |= EN_DAC_ENABLE;
-	cx_write(AUD_CTL, ctl);
+		ctl |= EN_DAC_ENABLE;
+		cx_write(AUD_CTL, ctl);
 	}
 
 	/* finish programming */
 	cx_write(AUD_SOFT_RESET, 0x0000);
+	cx_write(MO_AUD_DMACNTRL, 0x0003);
 
 	/* unmute */
 	volume = cx_sread(SHADOW_AUD_VOL_CTL);
@@ -162,486 +162,463 @@
 
 /* ----------------------------------------------------------- */
 
-static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap, u32 mode)
+static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap,
+				    u32 mode)
 {
 	static const struct rlist btsc[] = {
-	{ AUD_AFE_12DB_EN,             0x00000001 },
-		{ AUD_OUT1_SEL,                0x00000013 },
-		{ AUD_OUT1_SHIFT,              0x00000000 },
-		{ AUD_POLY0_DDS_CONSTANT,      0x0012010c },
-		{ AUD_DMD_RA_DDS,              0x00c3e7aa },
-		{ AUD_DBX_IN_GAIN,             0x00004734 },
-		{ AUD_DBX_WBE_GAIN,            0x00004640 },
-		{ AUD_DBX_SE_GAIN,             0x00008d31 },
-		{ AUD_DCOC_0_SRC,              0x0000001a },
-		{ AUD_IIR1_4_SEL,              0x00000021 },
-		{ AUD_DCOC_PASS_IN,            0x00000003 },
-		{ AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
-		{ AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
-		{ AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
-		{ AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
-		{ AUD_DN0_FREQ,                0x0000283b },
-		{ AUD_DN2_SRC_SEL,             0x00000008 },
-		{ AUD_DN2_FREQ,                0x00003000 },
-		{ AUD_DN2_AFC,                 0x00000002 },
-		{ AUD_DN2_SHFT,                0x00000000 },
-		{ AUD_IIR2_2_SEL,              0x00000020 },
-		{ AUD_IIR2_2_SHIFT,            0x00000000 },
-		{ AUD_IIR2_3_SEL,              0x0000001f },
-		{ AUD_IIR2_3_SHIFT,            0x00000000 },
-		{ AUD_CRDC1_SRC_SEL,           0x000003ce },
-		{ AUD_CRDC1_SHIFT,             0x00000000 },
-		{ AUD_CORDIC_SHIFT_1,          0x00000007 },
-		{ AUD_DCOC_1_SRC,              0x0000001b },
-		{ AUD_DCOC1_SHIFT,             0x00000000 },
-		{ AUD_RDSI_SEL,                0x00000008 },
-		{ AUD_RDSQ_SEL,                0x00000008 },
-		{ AUD_RDSI_SHIFT,              0x00000000 },
-		{ AUD_RDSQ_SHIFT,              0x00000000 },
-		{ AUD_POLYPH80SCALEFAC,        0x00000003 },
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_OUT1_SEL, 0x00000013},
+		{AUD_OUT1_SHIFT, 0x00000000},
+		{AUD_POLY0_DDS_CONSTANT, 0x0012010c},
+		{AUD_DMD_RA_DDS, 0x00c3e7aa},
+		{AUD_DBX_IN_GAIN, 0x00004734},
+		{AUD_DBX_WBE_GAIN, 0x00004640},
+		{AUD_DBX_SE_GAIN, 0x00008d31},
+		{AUD_DCOC_0_SRC, 0x0000001a},
+		{AUD_IIR1_4_SEL, 0x00000021},
+		{AUD_DCOC_PASS_IN, 0x00000003},
+		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+		{AUD_DN0_FREQ, 0x0000283b},
+		{AUD_DN2_SRC_SEL, 0x00000008},
+		{AUD_DN2_FREQ, 0x00003000},
+		{AUD_DN2_AFC, 0x00000002},
+		{AUD_DN2_SHFT, 0x00000000},
+		{AUD_IIR2_2_SEL, 0x00000020},
+		{AUD_IIR2_2_SHIFT, 0x00000000},
+		{AUD_IIR2_3_SEL, 0x0000001f},
+		{AUD_IIR2_3_SHIFT, 0x00000000},
+		{AUD_CRDC1_SRC_SEL, 0x000003ce},
+		{AUD_CRDC1_SHIFT, 0x00000000},
+		{AUD_CORDIC_SHIFT_1, 0x00000007},
+		{AUD_DCOC_1_SRC, 0x0000001b},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_RDSI_SEL, 0x00000008},
+		{AUD_RDSQ_SEL, 0x00000008},
+		{AUD_RDSI_SHIFT, 0x00000000},
+		{AUD_RDSQ_SHIFT, 0x00000000},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
 		{ /* end of list */ },
 	};
 	static const struct rlist btsc_sap[] = {
-	{ AUD_AFE_12DB_EN,             0x00000001 },
-		{ AUD_DBX_IN_GAIN,             0x00007200 },
-		{ AUD_DBX_WBE_GAIN,            0x00006200 },
-		{ AUD_DBX_SE_GAIN,             0x00006200 },
-		{ AUD_IIR1_1_SEL,              0x00000000 },
-		{ AUD_IIR1_3_SEL,              0x00000001 },
-		{ AUD_DN1_SRC_SEL,             0x00000007 },
-		{ AUD_IIR1_4_SHIFT,            0x00000006 },
-		{ AUD_IIR2_1_SHIFT,            0x00000000 },
-		{ AUD_IIR2_2_SHIFT,            0x00000000 },
-		{ AUD_IIR3_0_SHIFT,            0x00000000 },
-		{ AUD_IIR3_1_SHIFT,            0x00000000 },
-		{ AUD_IIR3_0_SEL,              0x0000000d },
-		{ AUD_IIR3_1_SEL,              0x0000000e },
-		{ AUD_DEEMPH1_SRC_SEL,         0x00000014 },
-		{ AUD_DEEMPH1_SHIFT,           0x00000000 },
-		{ AUD_DEEMPH1_G0,              0x00004000 },
-		{ AUD_DEEMPH1_A0,              0x00000000 },
-		{ AUD_DEEMPH1_B0,              0x00000000 },
-		{ AUD_DEEMPH1_A1,              0x00000000 },
-		{ AUD_DEEMPH1_B1,              0x00000000 },
-		{ AUD_OUT0_SEL,                0x0000003f },
-		{ AUD_OUT1_SEL,                0x0000003f },
-		{ AUD_DN1_AFC,                 0x00000002 },
-		{ AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
-		{ AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
-		{ AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
-		{ AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
-		{ AUD_IIR1_0_SEL,              0x0000001d },
-		{ AUD_IIR1_2_SEL,              0x0000001e },
-		{ AUD_IIR2_1_SEL,              0x00000002 },
-		{ AUD_IIR2_2_SEL,              0x00000004 },
-		{ AUD_IIR3_2_SEL,              0x0000000f },
-		{ AUD_DCOC2_SHIFT,             0x00000001 },
-		{ AUD_IIR3_2_SHIFT,            0x00000001 },
-		{ AUD_DEEMPH0_SRC_SEL,         0x00000014 },
-		{ AUD_CORDIC_SHIFT_1,          0x00000006 },
-		{ AUD_POLY0_DDS_CONSTANT,      0x000e4db2 },
-		{ AUD_DMD_RA_DDS,              0x00f696e6 },
-		{ AUD_IIR2_3_SEL,              0x00000025 },
-		{ AUD_IIR1_4_SEL,              0x00000021 },
-		{ AUD_DN1_FREQ,                0x0000c965 },
-		{ AUD_DCOC_PASS_IN,            0x00000003 },
-		{ AUD_DCOC_0_SRC,              0x0000001a },
-		{ AUD_DCOC_1_SRC,              0x0000001b },
-		{ AUD_DCOC1_SHIFT,             0x00000000 },
-		{ AUD_RDSI_SEL,                0x00000009 },
-		{ AUD_RDSQ_SEL,                0x00000009 },
-		{ AUD_RDSI_SHIFT,              0x00000000 },
-		{ AUD_RDSQ_SHIFT,              0x00000000 },
-		{ AUD_POLYPH80SCALEFAC,        0x00000003 },
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_DBX_IN_GAIN, 0x00007200},
+		{AUD_DBX_WBE_GAIN, 0x00006200},
+		{AUD_DBX_SE_GAIN, 0x00006200},
+		{AUD_IIR1_1_SEL, 0x00000000},
+		{AUD_IIR1_3_SEL, 0x00000001},
+		{AUD_DN1_SRC_SEL, 0x00000007},
+		{AUD_IIR1_4_SHIFT, 0x00000006},
+		{AUD_IIR2_1_SHIFT, 0x00000000},
+		{AUD_IIR2_2_SHIFT, 0x00000000},
+		{AUD_IIR3_0_SHIFT, 0x00000000},
+		{AUD_IIR3_1_SHIFT, 0x00000000},
+		{AUD_IIR3_0_SEL, 0x0000000d},
+		{AUD_IIR3_1_SEL, 0x0000000e},
+		{AUD_DEEMPH1_SRC_SEL, 0x00000014},
+		{AUD_DEEMPH1_SHIFT, 0x00000000},
+		{AUD_DEEMPH1_G0, 0x00004000},
+		{AUD_DEEMPH1_A0, 0x00000000},
+		{AUD_DEEMPH1_B0, 0x00000000},
+		{AUD_DEEMPH1_A1, 0x00000000},
+		{AUD_DEEMPH1_B1, 0x00000000},
+		{AUD_OUT0_SEL, 0x0000003f},
+		{AUD_OUT1_SEL, 0x0000003f},
+		{AUD_DN1_AFC, 0x00000002},
+		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+		{AUD_IIR1_0_SEL, 0x0000001d},
+		{AUD_IIR1_2_SEL, 0x0000001e},
+		{AUD_IIR2_1_SEL, 0x00000002},
+		{AUD_IIR2_2_SEL, 0x00000004},
+		{AUD_IIR3_2_SEL, 0x0000000f},
+		{AUD_DCOC2_SHIFT, 0x00000001},
+		{AUD_IIR3_2_SHIFT, 0x00000001},
+		{AUD_DEEMPH0_SRC_SEL, 0x00000014},
+		{AUD_CORDIC_SHIFT_1, 0x00000006},
+		{AUD_POLY0_DDS_CONSTANT, 0x000e4db2},
+		{AUD_DMD_RA_DDS, 0x00f696e6},
+		{AUD_IIR2_3_SEL, 0x00000025},
+		{AUD_IIR1_4_SEL, 0x00000021},
+		{AUD_DN1_FREQ, 0x0000c965},
+		{AUD_DCOC_PASS_IN, 0x00000003},
+		{AUD_DCOC_0_SRC, 0x0000001a},
+		{AUD_DCOC_1_SRC, 0x0000001b},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_RDSI_SEL, 0x00000009},
+		{AUD_RDSQ_SEL, 0x00000009},
+		{AUD_RDSI_SHIFT, 0x00000000},
+		{AUD_RDSQ_SHIFT, 0x00000000},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
 		{ /* end of list */ },
 	};
 
 	mode |= EN_FMRADIO_EN_RDS;
 
 	if (sap) {
-		dprintk("%s SAP (status: unknown)\n",__FUNCTION__);
-	set_audio_start(core, SEL_SAP);
+		dprintk("%s SAP (status: unknown)\n", __FUNCTION__);
+		set_audio_start(core, SEL_SAP);
 		set_audio_registers(core, btsc_sap);
 		set_audio_finish(core, mode);
 	} else {
-		dprintk("%s (status: known-good)\n",__FUNCTION__);
-	set_audio_start(core, SEL_BTSC);
+		dprintk("%s (status: known-good)\n", __FUNCTION__);
+		set_audio_start(core, SEL_BTSC);
 		set_audio_registers(core, btsc);
 		set_audio_finish(core, mode);
 	}
 }
 
-
-static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo)
+static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
 {
-	/* This is probably weird..
-	* Let's operate and find out. */
-
-	static const struct rlist nicam_l_mono[] = {
-		{ AUD_ERRLOGPERIOD_R,     0x00000064 },
-		{ AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
-		{ AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
-		{ AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
-
-		{ AUD_PDF_DDS_CNST_BYTE2, 0x48 },
-		{ AUD_PDF_DDS_CNST_BYTE1, 0x3D },
-		{ AUD_QAM_MODE,           0x00 },
-		{ AUD_PDF_DDS_CNST_BYTE0, 0xf5 },
-		{ AUD_PHACC_FREQ_8MSB,    0x3a },
-		{ AUD_PHACC_FREQ_8LSB,    0x4a },
-
-		{ AUD_DEEMPHGAIN_R, 0x6680 },
-		{ AUD_DEEMPHNUMER1_R, 0x353DE },
-		{ AUD_DEEMPHNUMER2_R, 0x1B1 },
-		{ AUD_DEEMPHDENOM1_R, 0x0F3D0 },
-		{ AUD_DEEMPHDENOM2_R, 0x0 },
-		{ AUD_FM_MODE_ENABLE, 0x7 },
-		{ AUD_POLYPH80SCALEFAC, 0x3 },
-		{ AUD_AFE_12DB_EN, 0x1 },
-		{ AAGC_GAIN, 0x0 },
-		{ AAGC_HYST, 0x18 },
-		{ AAGC_DEF, 0x20 },
-		{ AUD_DN0_FREQ, 0x0 },
-		{ AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 },
-		{ AUD_DCOC_0_SRC, 0x21 },
-		{ AUD_IIR1_0_SEL, 0x0 },
-		{ AUD_IIR1_0_SHIFT, 0x7 },
-		{ AUD_IIR1_1_SEL, 0x2 },
-		{ AUD_IIR1_1_SHIFT, 0x0 },
-		{ AUD_DCOC_1_SRC, 0x3 },
-		{ AUD_DCOC1_SHIFT, 0x0 },
-		{ AUD_DCOC_PASS_IN, 0x0 },
-		{ AUD_IIR1_2_SEL, 0x23 },
-		{ AUD_IIR1_2_SHIFT, 0x0 },
-		{ AUD_IIR1_3_SEL, 0x4 },
-		{ AUD_IIR1_3_SHIFT, 0x7 },
-		{ AUD_IIR1_4_SEL, 0x5 },
-		{ AUD_IIR1_4_SHIFT, 0x7 },
-		{ AUD_IIR3_0_SEL, 0x7 },
-		{ AUD_IIR3_0_SHIFT, 0x0 },
-		{ AUD_DEEMPH0_SRC_SEL, 0x11 },
-		{ AUD_DEEMPH0_SHIFT, 0x0 },
-		{ AUD_DEEMPH0_G0, 0x7000 },
-		{ AUD_DEEMPH0_A0, 0x0 },
-		{ AUD_DEEMPH0_B0, 0x0 },
-		{ AUD_DEEMPH0_A1, 0x0 },
-		{ AUD_DEEMPH0_B1, 0x0 },
-		{ AUD_DEEMPH1_SRC_SEL, 0x11 },
-		{ AUD_DEEMPH1_SHIFT, 0x0 },
-		{ AUD_DEEMPH1_G0, 0x7000 },
-		{ AUD_DEEMPH1_A0, 0x0 },
-		{ AUD_DEEMPH1_B0, 0x0 },
-		{ AUD_DEEMPH1_A1, 0x0 },
-		{ AUD_DEEMPH1_B1, 0x0 },
-		{ AUD_OUT0_SEL, 0x3F },
-		{ AUD_OUT1_SEL, 0x3F },
-		{ AUD_DMD_RA_DDS, 0x0F5C285 },
-		{ AUD_PLL_INT, 0x1E },
-		{ AUD_PLL_DDS, 0x0 },
-		{ AUD_PLL_FRAC, 0x0E542 },
-
-		// setup QAM registers
-		{ AUD_RATE_ADJ1,      0x00000100 },
-		{ AUD_RATE_ADJ2,      0x00000200 },
-		{ AUD_RATE_ADJ3,      0x00000300 },
-		{ AUD_RATE_ADJ4,      0x00000400 },
-		{ AUD_RATE_ADJ5,      0x00000500 },
-		{ AUD_RATE_THRES_DMD, 0x000000C0 },
-		{ /* end of list */ },
-	};
-
 	static const struct rlist nicam_l[] = {
-		// setup QAM registers
-		{ AUD_RATE_ADJ1, 0x00000060 },
-		{ AUD_RATE_ADJ2, 0x000000F9 },
-		{ AUD_RATE_ADJ3, 0x000001CC },
-		{ AUD_RATE_ADJ4, 0x000002B3 },
-		{ AUD_RATE_ADJ5, 0x00000726 },
-		{ AUD_DEEMPHDENOM1_R, 0x0000F3D0 },
-		{ AUD_DEEMPHDENOM2_R, 0x00000000 },
-		{ AUD_ERRLOGPERIOD_R, 0x00000064 },
-		{ AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
-		{ AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
-		{ AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
-		{ AUD_POLYPH80SCALEFAC, 0x00000003 },
-		{ AUD_DMD_RA_DDS, 0x00C00000 },
-		{ AUD_PLL_INT, 0x0000001E },
-		{ AUD_PLL_DDS, 0x00000000 },
-		{ AUD_PLL_FRAC, 0x0000E542 },
-		{ AUD_START_TIMER, 0x00000000 },
-		{ AUD_DEEMPHNUMER1_R, 0x000353DE },
-		{ AUD_DEEMPHNUMER2_R, 0x000001B1 },
-		{ AUD_PDF_DDS_CNST_BYTE2, 0x06 },
-		{ AUD_PDF_DDS_CNST_BYTE1, 0x82 },
-		{ AUD_QAM_MODE, 0x05 },
-		{ AUD_PDF_DDS_CNST_BYTE0, 0x12 },
-		{ AUD_PHACC_FREQ_8MSB, 0x34 },
-		{ AUD_PHACC_FREQ_8LSB, 0x4C },
-		{ AUD_DEEMPHGAIN_R, 0x00006680 },
-		{ AUD_RATE_THRES_DMD, 0x000000C0  },
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_RATE_ADJ1, 0x00000060},
+		{AUD_RATE_ADJ2, 0x000000F9},
+		{AUD_RATE_ADJ3, 0x000001CC},
+		{AUD_RATE_ADJ4, 0x000002B3},
+		{AUD_RATE_ADJ5, 0x00000726},
+		{AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+		{AUD_DEEMPHDENOM2_R, 0x00000000},
+		{AUD_ERRLOGPERIOD_R, 0x00000064},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
+		{AUD_DMD_RA_DDS, 0x00C00000},
+		{AUD_PLL_INT, 0x0000001E},
+		{AUD_PLL_DDS, 0x00000000},
+		{AUD_PLL_FRAC, 0x0000E542},
+		{AUD_START_TIMER, 0x00000000},
+		{AUD_DEEMPHNUMER1_R, 0x000353DE},
+		{AUD_DEEMPHNUMER2_R, 0x000001B1},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
+		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
+		{AUD_QAM_MODE, 0x05},
+		{AUD_PHACC_FREQ_8MSB, 0x34},
+		{AUD_PHACC_FREQ_8LSB, 0x4C},
+		{AUD_DEEMPHGAIN_R, 0x00006680},
+		{AUD_RATE_THRES_DMD, 0x000000C0},
 		{ /* end of list */ },
-	} ;
-	dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
-
-	if (!stereo) {
-	/* AM Mono */
-		set_audio_start(core, SEL_A2);
-		set_audio_registers(core, nicam_l_mono);
-	set_audio_finish(core, EN_A2_FORCE_MONO1);
-	} else {
-	/* Nicam Stereo */
-		set_audio_start(core, SEL_NICAM);
-		set_audio_registers(core, nicam_l);
-	set_audio_finish(core, 0x1924); /* FIXME */
-	}
-}
-
-static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo)
-{
-       static const struct rlist pal_i_fm_mono[] = {
-	{AUD_ERRLOGPERIOD_R,       0x00000064},
-	{AUD_ERRINTRPTTHSHLD1_R,   0x00000fff},
-	{AUD_ERRINTRPTTHSHLD2_R,   0x0000001f},
-	{AUD_ERRINTRPTTHSHLD3_R,   0x0000000f},
-	{AUD_PDF_DDS_CNST_BYTE2,   0x06},
-	{AUD_PDF_DDS_CNST_BYTE1,   0x82},
-	{AUD_PDF_DDS_CNST_BYTE0,   0x12},
-	{AUD_QAM_MODE,             0x05},
-	{AUD_PHACC_FREQ_8MSB,      0x3a},
-	{AUD_PHACC_FREQ_8LSB,      0x93},
-	{AUD_DMD_RA_DDS,           0x002a4f2f},
-	{AUD_PLL_INT,              0x0000001e},
-	{AUD_PLL_DDS,              0x00000004},
-	{AUD_PLL_FRAC,             0x0000e542},
-	{AUD_RATE_ADJ1,            0x00000100},
-	{AUD_RATE_ADJ2,            0x00000200},
-	{AUD_RATE_ADJ3,            0x00000300},
-	{AUD_RATE_ADJ4,            0x00000400},
-	{AUD_RATE_ADJ5,            0x00000500},
-	{AUD_THR_FR,               0x00000000},
-	{AUD_PILOT_BQD_1_K0,       0x0000755b},
-	{AUD_PILOT_BQD_1_K1,       0x00551340},
-	{AUD_PILOT_BQD_1_K2,       0x006d30be},
-	{AUD_PILOT_BQD_1_K3,       0xffd394af},
-	{AUD_PILOT_BQD_1_K4,       0x00400000},
-	{AUD_PILOT_BQD_2_K0,       0x00040000},
-	{AUD_PILOT_BQD_2_K1,       0x002a4841},
-	{AUD_PILOT_BQD_2_K2,       0x00400000},
-	{AUD_PILOT_BQD_2_K3,       0x00000000},
-	{AUD_PILOT_BQD_2_K4,       0x00000000},
-	{AUD_MODE_CHG_TIMER,       0x00000060},
-	{AUD_AFE_12DB_EN,          0x00000001},
-	{AAGC_HYST,                0x0000000a},
-	{AUD_CORDIC_SHIFT_0,       0x00000007},
-	{AUD_CORDIC_SHIFT_1,       0x00000007},
-	{AUD_C1_UP_THR,            0x00007000},
-	{AUD_C1_LO_THR,            0x00005400},
-	{AUD_C2_UP_THR,            0x00005400},
-	{AUD_C2_LO_THR,            0x00003000},
-	{AUD_DCOC_0_SRC,           0x0000001a},
-	{AUD_DCOC0_SHIFT,          0x00000000},
-	{AUD_DCOC_0_SHIFT_IN0,     0x0000000a},
-	{AUD_DCOC_0_SHIFT_IN1,     0x00000008},
-	{AUD_DCOC_PASS_IN,         0x00000003},
-	{AUD_IIR3_0_SEL,           0x00000021},
-	{AUD_DN2_AFC,              0x00000002},
-	{AUD_DCOC_1_SRC,           0x0000001b},
-	{AUD_DCOC1_SHIFT,          0x00000000},
-	{AUD_DCOC_1_SHIFT_IN0,     0x0000000a},
-	{AUD_DCOC_1_SHIFT_IN1,     0x00000008},
-	{AUD_IIR3_1_SEL,           0x00000023},
-	{AUD_DN0_FREQ,             0x000035a3},
-	{AUD_DN2_FREQ,             0x000029c7},
-	{AUD_CRDC0_SRC_SEL,        0x00000511},
-	{AUD_IIR1_0_SEL,           0x00000001},
-	{AUD_IIR1_1_SEL,           0x00000000},
-	{AUD_IIR3_2_SEL,           0x00000003},
-	{AUD_IIR3_2_SHIFT,         0x00000000},
-	{AUD_IIR3_0_SEL,           0x00000002},
-	{AUD_IIR2_0_SEL,           0x00000021},
-	{AUD_IIR2_0_SHIFT,         0x00000002},
-	{AUD_DEEMPH0_SRC_SEL,      0x0000000b},
-	{AUD_DEEMPH1_SRC_SEL,      0x0000000b},
-	{AUD_POLYPH80SCALEFAC,     0x00000001},
-	{AUD_START_TIMER,          0x00000000},
-	{ /* end of list */ },
-       };
-
-       static const struct rlist pal_i_nicam[] = {
-	{ AUD_RATE_ADJ1,           0x00000010 },
-	{ AUD_RATE_ADJ2,           0x00000040 },
-	{ AUD_RATE_ADJ3,           0x00000100 },
-	{ AUD_RATE_ADJ4,           0x00000400 },
-	{ AUD_RATE_ADJ5,           0x00001000 },
-	//     { AUD_DMD_RA_DDS,          0x00c0d5ce },
-	{ AUD_DEEMPHGAIN_R,        0x000023c2 },
-	{ AUD_DEEMPHNUMER1_R,      0x0002a7bc },
-	{ AUD_DEEMPHNUMER2_R,      0x0003023e },
-	{ AUD_DEEMPHDENOM1_R,      0x0000f3d0 },
-	{ AUD_DEEMPHDENOM2_R,      0x00000000 },
-	{ AUD_DEEMPHDENOM2_R,      0x00000000 },
-	{ AUD_ERRLOGPERIOD_R,      0x00000fff },
-	{ AUD_ERRINTRPTTHSHLD1_R,  0x000003ff },
-	{ AUD_ERRINTRPTTHSHLD2_R,  0x000000ff },
-	{ AUD_ERRINTRPTTHSHLD3_R,  0x0000003f },
-	{ AUD_POLYPH80SCALEFAC,    0x00000003 },
-	{ AUD_PDF_DDS_CNST_BYTE2,  0x06 },
-	{ AUD_PDF_DDS_CNST_BYTE1,  0x82 },
-	{ AUD_PDF_DDS_CNST_BYTE0,  0x16 },
-	{ AUD_QAM_MODE,            0x05 },
-	{ AUD_PDF_DDS_CNST_BYTE0,  0x12 },
-	{ AUD_PHACC_FREQ_8MSB,     0x3a },
-	{ AUD_PHACC_FREQ_8LSB,     0x93 },
-	{ /* end of list */ },
 	};
 
-	dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
+	static const struct rlist nicam_bgdki_common[] = {
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_RATE_ADJ1, 0x00000010},
+		{AUD_RATE_ADJ2, 0x00000040},
+		{AUD_RATE_ADJ3, 0x00000100},
+		{AUD_RATE_ADJ4, 0x00000400},
+		{AUD_RATE_ADJ5, 0x00001000},
+		//{ AUD_DMD_RA_DDS,        0x00c0d5ce },
+		{AUD_ERRLOGPERIOD_R, 0x00000fff},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x000003ff},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x000000ff},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000003f},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
+		{AUD_DEEMPHGAIN_R, 0x000023c2},
+		{AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+		{AUD_DEEMPHNUMER2_R, 0x0003023e},
+		{AUD_DEEMPHDENOM1_R, 0x0000f3d0},
+		{AUD_DEEMPHDENOM2_R, 0x00000000},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
+		{AUD_QAM_MODE, 0x05},
+		{ /* end of list */ },
+	};
 
-	if (!stereo) {
-	/* FM Mono */
-	set_audio_start(core, SEL_A2);
-		set_audio_registers(core, pal_i_fm_mono);
-		set_audio_finish(core, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1);
-	} else {
-	/* Nicam Stereo */
-	set_audio_start(core, SEL_NICAM);
-		set_audio_registers(core, pal_i_nicam);
-		set_audio_finish(core, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
-	}
+	static const struct rlist nicam_i[] = {
+		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
+		{AUD_PHACC_FREQ_8MSB, 0x3a},
+		{AUD_PHACC_FREQ_8LSB, 0x93},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist nicam_default[] = {
+		{AUD_PDF_DDS_CNST_BYTE0, 0x16},
+		{AUD_PHACC_FREQ_8MSB, 0x34},
+		{AUD_PHACC_FREQ_8LSB, 0x4c},
+		{ /* end of list */ },
+	};
+
+	set_audio_start(core,SEL_NICAM);
+	switch (core->tvaudio) {
+	case WW_L:
+		dprintk("%s SECAM-L NICAM (status: devel)\n", __FUNCTION__);
+		set_audio_registers(core, nicam_l);
+		break;
+	case WW_I:
+		dprintk("%s PAL-I NICAM (status: devel)\n", __FUNCTION__);
+		set_audio_registers(core, nicam_bgdki_common);
+		set_audio_registers(core, nicam_i);
+		break;
+	default:
+		dprintk("%s PAL-BGDK NICAM (status: unknown)\n", __FUNCTION__);
+		set_audio_registers(core, nicam_bgdki_common);
+		set_audio_registers(core, nicam_default);
+		break;
+	};
+
+	mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS;
+	set_audio_finish(core, mode);
 }
 
 static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
 {
-	static const struct rlist a2_common[] = {
-	{AUD_ERRLOGPERIOD_R,            0x00000064},
-	{AUD_ERRINTRPTTHSHLD1_R,        0x00000fff},
-	{AUD_ERRINTRPTTHSHLD2_R,        0x0000001f},
-	{AUD_ERRINTRPTTHSHLD3_R,        0x0000000f},
-	{AUD_PDF_DDS_CNST_BYTE2,        0x06},
-	{AUD_PDF_DDS_CNST_BYTE1,        0x82},
-	{AUD_PDF_DDS_CNST_BYTE0,        0x12},
-	{AUD_QAM_MODE,                  0x05},
-	{AUD_PHACC_FREQ_8MSB,           0x34},
-	{AUD_PHACC_FREQ_8LSB,           0x4c},
-	{AUD_RATE_ADJ1,                 0x00000100},
-	{AUD_RATE_ADJ2,                 0x00000200},
-	{AUD_RATE_ADJ3,                 0x00000300},
-	{AUD_RATE_ADJ4,                 0x00000400},
-	{AUD_RATE_ADJ5,                 0x00000500},
-	{AUD_THR_FR,                    0x00000000},
-	{AAGC_HYST,                     0x0000001a},
-	{AUD_PILOT_BQD_1_K0,            0x0000755b},
-	{AUD_PILOT_BQD_1_K1,            0x00551340},
-	{AUD_PILOT_BQD_1_K2,            0x006d30be},
-	{AUD_PILOT_BQD_1_K3,            0xffd394af},
-	{AUD_PILOT_BQD_1_K4,            0x00400000},
-	{AUD_PILOT_BQD_2_K0,            0x00040000},
-	{AUD_PILOT_BQD_2_K1,            0x002a4841},
-	{AUD_PILOT_BQD_2_K2,            0x00400000},
-	{AUD_PILOT_BQD_2_K3,            0x00000000},
-	{AUD_PILOT_BQD_2_K4,            0x00000000},
-	{AUD_MODE_CHG_TIMER,            0x00000040},
-	{AUD_AFE_12DB_EN,               0x00000001},
-	{AUD_CORDIC_SHIFT_0,            0x00000007},
-	{AUD_CORDIC_SHIFT_1,            0x00000007},
-	{AUD_DEEMPH0_G0,                0x00000380},
-	{AUD_DEEMPH1_G0,                0x00000380},
-	{AUD_DCOC_0_SRC,                0x0000001a},
-	{AUD_DCOC0_SHIFT,               0x00000000},
-	{AUD_DCOC_0_SHIFT_IN0,          0x0000000a},
-	{AUD_DCOC_0_SHIFT_IN1,          0x00000008},
-	{AUD_DCOC_PASS_IN,              0x00000003},
-	{AUD_IIR3_0_SEL,                0x00000021},
-	{AUD_DN2_AFC,                   0x00000002},
-	{AUD_DCOC_1_SRC,                0x0000001b},
-	{AUD_DCOC1_SHIFT,               0x00000000},
-	{AUD_DCOC_1_SHIFT_IN0,          0x0000000a},
-	{AUD_DCOC_1_SHIFT_IN1,          0x00000008},
-	{AUD_IIR3_1_SEL,                0x00000023},
-	{AUD_RDSI_SEL,                  0x00000017},
-	{AUD_RDSI_SHIFT,                0x00000000},
-	{AUD_RDSQ_SEL,                  0x00000017},
-	{AUD_RDSQ_SHIFT,                0x00000000},
-	{AUD_PLL_INT,                   0x0000001e},
-	{AUD_PLL_DDS,                   0x00000000},
-	{AUD_PLL_FRAC,                  0x0000e542},
-	{AUD_POLYPH80SCALEFAC,          0x00000001},
-	{AUD_START_TIMER,               0x00000000},
-	{ /* end of list */ },
+	static const struct rlist a2_bgdk_common[] = {
+		{AUD_ERRLOGPERIOD_R, 0x00000064},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
+		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
+		{AUD_QAM_MODE, 0x05},
+		{AUD_PHACC_FREQ_8MSB, 0x34},
+		{AUD_PHACC_FREQ_8LSB, 0x4c},
+		{AUD_RATE_ADJ1, 0x00000100},
+		{AUD_RATE_ADJ2, 0x00000200},
+		{AUD_RATE_ADJ3, 0x00000300},
+		{AUD_RATE_ADJ4, 0x00000400},
+		{AUD_RATE_ADJ5, 0x00000500},
+		{AUD_THR_FR, 0x00000000},
+		{AAGC_HYST, 0x0000001a},
+		{AUD_PILOT_BQD_1_K0, 0x0000755b},
+		{AUD_PILOT_BQD_1_K1, 0x00551340},
+		{AUD_PILOT_BQD_1_K2, 0x006d30be},
+		{AUD_PILOT_BQD_1_K3, 0xffd394af},
+		{AUD_PILOT_BQD_1_K4, 0x00400000},
+		{AUD_PILOT_BQD_2_K0, 0x00040000},
+		{AUD_PILOT_BQD_2_K1, 0x002a4841},
+		{AUD_PILOT_BQD_2_K2, 0x00400000},
+		{AUD_PILOT_BQD_2_K3, 0x00000000},
+		{AUD_PILOT_BQD_2_K4, 0x00000000},
+		{AUD_MODE_CHG_TIMER, 0x00000040},
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AUD_CORDIC_SHIFT_0, 0x00000007},
+		{AUD_CORDIC_SHIFT_1, 0x00000007},
+		{AUD_DEEMPH0_G0, 0x00000380},
+		{AUD_DEEMPH1_G0, 0x00000380},
+		{AUD_DCOC_0_SRC, 0x0000001a},
+		{AUD_DCOC0_SHIFT, 0x00000000},
+		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+		{AUD_DCOC_PASS_IN, 0x00000003},
+		{AUD_IIR3_0_SEL, 0x00000021},
+		{AUD_DN2_AFC, 0x00000002},
+		{AUD_DCOC_1_SRC, 0x0000001b},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+		{AUD_IIR3_1_SEL, 0x00000023},
+		{AUD_RDSI_SEL, 0x00000017},
+		{AUD_RDSI_SHIFT, 0x00000000},
+		{AUD_RDSQ_SEL, 0x00000017},
+		{AUD_RDSQ_SHIFT, 0x00000000},
+		{AUD_PLL_INT, 0x0000001e},
+		{AUD_PLL_DDS, 0x00000000},
+		{AUD_PLL_FRAC, 0x0000e542},
+		{AUD_POLYPH80SCALEFAC, 0x00000001},
+		{AUD_START_TIMER, 0x00000000},
+		{ /* end of list */ },
 	};
 
 	static const struct rlist a2_bg[] = {
-	{AUD_DMD_RA_DDS,                0x002a4f2f},
-	{AUD_C1_UP_THR,                 0x00007000},
-	{AUD_C1_LO_THR,                 0x00005400},
-	{AUD_C2_UP_THR,                 0x00005400},
-	{AUD_C2_LO_THR,                 0x00003000},
+		{AUD_DMD_RA_DDS, 0x002a4f2f},
+		{AUD_C1_UP_THR, 0x00007000},
+		{AUD_C1_LO_THR, 0x00005400},
+		{AUD_C2_UP_THR, 0x00005400},
+		{AUD_C2_LO_THR, 0x00003000},
 		{ /* end of list */ },
 	};
 
 	static const struct rlist a2_dk[] = {
-	{AUD_DMD_RA_DDS,                0x002a4f2f},
-	{AUD_C1_UP_THR,                 0x00007000},
-	{AUD_C1_LO_THR,                 0x00005400},
-	{AUD_C2_UP_THR,                 0x00005400},
-	{AUD_C2_LO_THR,                 0x00003000},
-	{AUD_DN0_FREQ,                  0x00003a1c},
-	{AUD_DN2_FREQ,                  0x0000d2e0},
+		{AUD_DMD_RA_DDS, 0x002a4f2f},
+		{AUD_C1_UP_THR, 0x00007000},
+		{AUD_C1_LO_THR, 0x00005400},
+		{AUD_C2_UP_THR, 0x00005400},
+		{AUD_C2_LO_THR, 0x00003000},
+		{AUD_DN0_FREQ, 0x00003a1c},
+		{AUD_DN2_FREQ, 0x0000d2e0},
 		{ /* end of list */ },
 	};
-/* unknown, probably NTSC-M */
-	static const struct rlist a2_m[] = {
-	{AUD_DMD_RA_DDS,                0x002a0425},
-	{AUD_C1_UP_THR,                 0x00003c00},
-	{AUD_C1_LO_THR,                 0x00003000},
-	{AUD_C2_UP_THR,                 0x00006000},
-	{AUD_C2_LO_THR,                 0x00003c00},
-	{AUD_DEEMPH0_A0,                0x00007a80},
-	{AUD_DEEMPH1_A0,                0x00007a80},
-	{AUD_DEEMPH0_G0,                0x00001200},
-	{AUD_DEEMPH1_G0,                0x00001200},
-	{AUD_DN0_FREQ,                  0x0000283b},
-	{AUD_DN1_FREQ,                  0x00003418},
-	{AUD_DN2_FREQ,                  0x000029c7},
-	{AUD_POLY0_DDS_CONSTANT,        0x000a7540},
+
+	static const struct rlist a1_i[] = {
+		{AUD_ERRLOGPERIOD_R, 0x00000064},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
+		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
+		{AUD_QAM_MODE, 0x05},
+		{AUD_PHACC_FREQ_8MSB, 0x3a},
+		{AUD_PHACC_FREQ_8LSB, 0x93},
+		{AUD_DMD_RA_DDS, 0x002a4f2f},
+		{AUD_PLL_INT, 0x0000001e},
+		{AUD_PLL_DDS, 0x00000004},
+		{AUD_PLL_FRAC, 0x0000e542},
+		{AUD_RATE_ADJ1, 0x00000100},
+		{AUD_RATE_ADJ2, 0x00000200},
+		{AUD_RATE_ADJ3, 0x00000300},
+		{AUD_RATE_ADJ4, 0x00000400},
+		{AUD_RATE_ADJ5, 0x00000500},
+		{AUD_THR_FR, 0x00000000},
+		{AUD_PILOT_BQD_1_K0, 0x0000755b},
+		{AUD_PILOT_BQD_1_K1, 0x00551340},
+		{AUD_PILOT_BQD_1_K2, 0x006d30be},
+		{AUD_PILOT_BQD_1_K3, 0xffd394af},
+		{AUD_PILOT_BQD_1_K4, 0x00400000},
+		{AUD_PILOT_BQD_2_K0, 0x00040000},
+		{AUD_PILOT_BQD_2_K1, 0x002a4841},
+		{AUD_PILOT_BQD_2_K2, 0x00400000},
+		{AUD_PILOT_BQD_2_K3, 0x00000000},
+		{AUD_PILOT_BQD_2_K4, 0x00000000},
+		{AUD_MODE_CHG_TIMER, 0x00000060},
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AAGC_HYST, 0x0000000a},
+		{AUD_CORDIC_SHIFT_0, 0x00000007},
+		{AUD_CORDIC_SHIFT_1, 0x00000007},
+		{AUD_C1_UP_THR, 0x00007000},
+		{AUD_C1_LO_THR, 0x00005400},
+		{AUD_C2_UP_THR, 0x00005400},
+		{AUD_C2_LO_THR, 0x00003000},
+		{AUD_DCOC_0_SRC, 0x0000001a},
+		{AUD_DCOC0_SHIFT, 0x00000000},
+		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+		{AUD_DCOC_PASS_IN, 0x00000003},
+		{AUD_IIR3_0_SEL, 0x00000021},
+		{AUD_DN2_AFC, 0x00000002},
+		{AUD_DCOC_1_SRC, 0x0000001b},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+		{AUD_IIR3_1_SEL, 0x00000023},
+		{AUD_DN0_FREQ, 0x000035a3},
+		{AUD_DN2_FREQ, 0x000029c7},
+		{AUD_CRDC0_SRC_SEL, 0x00000511},
+		{AUD_IIR1_0_SEL, 0x00000001},
+		{AUD_IIR1_1_SEL, 0x00000000},
+		{AUD_IIR3_2_SEL, 0x00000003},
+		{AUD_IIR3_2_SHIFT, 0x00000000},
+		{AUD_IIR3_0_SEL, 0x00000002},
+		{AUD_IIR2_0_SEL, 0x00000021},
+		{AUD_IIR2_0_SHIFT, 0x00000002},
+		{AUD_DEEMPH0_SRC_SEL, 0x0000000b},
+		{AUD_DEEMPH1_SRC_SEL, 0x0000000b},
+		{AUD_POLYPH80SCALEFAC, 0x00000001},
+		{AUD_START_TIMER, 0x00000000},
+		{ /* end of list */ },
+	};
+
+	static const struct rlist am_l[] = {
+		{AUD_ERRLOGPERIOD_R, 0x00000064},
+		{AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+		{AUD_PDF_DDS_CNST_BYTE2, 0x48},
+		{AUD_PDF_DDS_CNST_BYTE1, 0x3D},
+		{AUD_QAM_MODE, 0x00},
+		{AUD_PDF_DDS_CNST_BYTE0, 0xf5},
+		{AUD_PHACC_FREQ_8MSB, 0x3a},
+		{AUD_PHACC_FREQ_8LSB, 0x4a},
+		{AUD_DEEMPHGAIN_R, 0x00006680},
+		{AUD_DEEMPHNUMER1_R, 0x000353DE},
+		{AUD_DEEMPHNUMER2_R, 0x000001B1},
+		{AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+		{AUD_DEEMPHDENOM2_R, 0x00000000},
+		{AUD_FM_MODE_ENABLE, 0x00000007},
+		{AUD_POLYPH80SCALEFAC, 0x00000003},
+		{AUD_AFE_12DB_EN, 0x00000001},
+		{AAGC_GAIN, 0x00000000},
+		{AAGC_HYST, 0x00000018},
+		{AAGC_DEF, 0x00000020},
+		{AUD_DN0_FREQ, 0x00000000},
+		{AUD_POLY0_DDS_CONSTANT, 0x000E4DB2},
+		{AUD_DCOC_0_SRC, 0x00000021},
+		{AUD_IIR1_0_SEL, 0x00000000},
+		{AUD_IIR1_0_SHIFT, 0x00000007},
+		{AUD_IIR1_1_SEL, 0x00000002},
+		{AUD_IIR1_1_SHIFT, 0x00000000},
+		{AUD_DCOC_1_SRC, 0x00000003},
+		{AUD_DCOC1_SHIFT, 0x00000000},
+		{AUD_DCOC_PASS_IN, 0x00000000},
+		{AUD_IIR1_2_SEL, 0x00000023},
+		{AUD_IIR1_2_SHIFT, 0x00000000},
+		{AUD_IIR1_3_SEL, 0x00000004},
+		{AUD_IIR1_3_SHIFT, 0x00000007},
+		{AUD_IIR1_4_SEL, 0x00000005},
+		{AUD_IIR1_4_SHIFT, 0x00000007},
+		{AUD_IIR3_0_SEL, 0x00000007},
+		{AUD_IIR3_0_SHIFT, 0x00000000},
+		{AUD_DEEMPH0_SRC_SEL, 0x00000011},
+		{AUD_DEEMPH0_SHIFT, 0x00000000},
+		{AUD_DEEMPH0_G0, 0x00007000},
+		{AUD_DEEMPH0_A0, 0x00000000},
+		{AUD_DEEMPH0_B0, 0x00000000},
+		{AUD_DEEMPH0_A1, 0x00000000},
+		{AUD_DEEMPH0_B1, 0x00000000},
+		{AUD_DEEMPH1_SRC_SEL, 0x00000011},
+		{AUD_DEEMPH1_SHIFT, 0x00000000},
+		{AUD_DEEMPH1_G0, 0x00007000},
+		{AUD_DEEMPH1_A0, 0x00000000},
+		{AUD_DEEMPH1_B0, 0x00000000},
+		{AUD_DEEMPH1_A1, 0x00000000},
+		{AUD_DEEMPH1_B1, 0x00000000},
+		{AUD_OUT0_SEL, 0x0000003F},
+		{AUD_OUT1_SEL, 0x0000003F},
+		{AUD_DMD_RA_DDS, 0x00F5C285},
+		{AUD_PLL_INT, 0x0000001E},
+		{AUD_PLL_DDS, 0x00000000},
+		{AUD_PLL_FRAC, 0x0000E542},
+		{AUD_RATE_ADJ1, 0x00000100},
+		{AUD_RATE_ADJ2, 0x00000200},
+		{AUD_RATE_ADJ3, 0x00000300},
+		{AUD_RATE_ADJ4, 0x00000400},
+		{AUD_RATE_ADJ5, 0x00000500},
+		{AUD_RATE_THRES_DMD, 0x000000C0},
 		{ /* end of list */ },
 	};
 
 	static const struct rlist a2_deemph50[] = {
-	{AUD_DEEMPH0_G0,                0x00000380},
-	{AUD_DEEMPH1_G0,                0x00000380},
-	{AUD_DEEMPHGAIN_R,              0x000011e1},
-	{AUD_DEEMPHNUMER1_R,            0x0002a7bc},
-	{AUD_DEEMPHNUMER2_R,            0x0003023c},
-	{ /* end of list */ },
-	};
-
-	static const struct rlist a2_deemph75[] = {
-	{AUD_DEEMPH0_G0,                0x00000480},
-	{AUD_DEEMPH1_G0,                0x00000480},
-	{AUD_DEEMPHGAIN_R,              0x00009000},
-	{AUD_DEEMPHNUMER1_R,            0x000353de},
-	{AUD_DEEMPHNUMER2_R,            0x000001b1},
+		{AUD_DEEMPH0_G0, 0x00000380},
+		{AUD_DEEMPH1_G0, 0x00000380},
+		{AUD_DEEMPHGAIN_R, 0x000011e1},
+		{AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+		{AUD_DEEMPHNUMER2_R, 0x0003023c},
 		{ /* end of list */ },
 	};
 
 	set_audio_start(core, SEL_A2);
-	set_audio_registers(core, a2_common);
 	switch (core->tvaudio) {
-	case WW_A2_BG:
-		dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
-	set_audio_registers(core, a2_bg);
-	set_audio_registers(core, a2_deemph50);
+	case WW_BG:
+		dprintk("%s PAL-BG A1/2 (status: known-good)\n", __FUNCTION__);
+		set_audio_registers(core, a2_bgdk_common);
+		set_audio_registers(core, a2_bg);
+		set_audio_registers(core, a2_deemph50);
 		break;
-	case WW_A2_DK:
-		dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
-	set_audio_registers(core, a2_dk);
-	set_audio_registers(core, a2_deemph50);
+	case WW_DK:
+		dprintk("%s PAL-DK A1/2 (status: known-good)\n", __FUNCTION__);
+		set_audio_registers(core, a2_bgdk_common);
+		set_audio_registers(core, a2_dk);
+		set_audio_registers(core, a2_deemph50);
 		break;
-	case WW_A2_M:
-		dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
-	set_audio_registers(core, a2_m);
-	set_audio_registers(core, a2_deemph75);
+	case WW_I:
+		dprintk("%s PAL-I A1 (status: known-good)\n", __FUNCTION__);
+		set_audio_registers(core, a1_i);
+		set_audio_registers(core, a2_deemph50);
+		break;
+	case WW_L:
+		dprintk("%s AM-L (status: devel)\n", __FUNCTION__);
+		set_audio_registers(core, am_l);
+		break;
+	default:
+		dprintk("%s Warning: wrong value\n", __FUNCTION__);
+		return;
 		break;
 	};
 
@@ -656,71 +633,71 @@
 
 		{ /* end of list */ },
 	};
-	dprintk("%s (status: unknown)\n",__FUNCTION__);
+	dprintk("%s (status: unknown)\n", __FUNCTION__);
 
 	set_audio_start(core, SEL_EIAJ);
 	set_audio_registers(core, eiaj);
 	set_audio_finish(core, EN_EIAJ_AUTO_STEREO);
 }
 
-static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph)
+static void set_audio_standard_FM(struct cx88_core *core,
+				  enum cx88_deemph_type deemph)
 {
 	static const struct rlist fm_deemph_50[] = {
-		{ AUD_DEEMPH0_G0,	0x0C45 },
-		{ AUD_DEEMPH0_A0,	0x6262 },
-		{ AUD_DEEMPH0_B0,	0x1C29 },
-		{ AUD_DEEMPH0_A1,	0x3FC66},
-		{ AUD_DEEMPH0_B1,	0x399A },
+		{AUD_DEEMPH0_G0, 0x0C45},
+		{AUD_DEEMPH0_A0, 0x6262},
+		{AUD_DEEMPH0_B0, 0x1C29},
+		{AUD_DEEMPH0_A1, 0x3FC66},
+		{AUD_DEEMPH0_B1, 0x399A},
 
-		{ AUD_DEEMPH1_G0,	0x0D80 },
-		{ AUD_DEEMPH1_A0,	0x6262 },
-		{ AUD_DEEMPH1_B0,	0x1C29 },
-		{ AUD_DEEMPH1_A1,	0x3FC66},
-		{ AUD_DEEMPH1_B1,	0x399A},
+		{AUD_DEEMPH1_G0, 0x0D80},
+		{AUD_DEEMPH1_A0, 0x6262},
+		{AUD_DEEMPH1_B0, 0x1C29},
+		{AUD_DEEMPH1_A1, 0x3FC66},
+		{AUD_DEEMPH1_B1, 0x399A},
 
-		{ AUD_POLYPH80SCALEFAC,	0x0003},
+		{AUD_POLYPH80SCALEFAC, 0x0003},
 		{ /* end of list */ },
 	};
 	static const struct rlist fm_deemph_75[] = {
-		{ AUD_DEEMPH0_G0,	0x091B },
-		{ AUD_DEEMPH0_A0,	0x6B68 },
-		{ AUD_DEEMPH0_B0,	0x11EC },
-		{ AUD_DEEMPH0_A1,	0x3FC66},
-		{ AUD_DEEMPH0_B1,	0x399A },
+		{AUD_DEEMPH0_G0, 0x091B},
+		{AUD_DEEMPH0_A0, 0x6B68},
+		{AUD_DEEMPH0_B0, 0x11EC},
+		{AUD_DEEMPH0_A1, 0x3FC66},
+		{AUD_DEEMPH0_B1, 0x399A},
 
-		{ AUD_DEEMPH1_G0,	0x0AA0 },
-		{ AUD_DEEMPH1_A0,	0x6B68 },
-		{ AUD_DEEMPH1_B0,	0x11EC },
-		{ AUD_DEEMPH1_A1,	0x3FC66},
-		{ AUD_DEEMPH1_B1,	0x399A},
+		{AUD_DEEMPH1_G0, 0x0AA0},
+		{AUD_DEEMPH1_A0, 0x6B68},
+		{AUD_DEEMPH1_B0, 0x11EC},
+		{AUD_DEEMPH1_A1, 0x3FC66},
+		{AUD_DEEMPH1_B1, 0x399A},
 
-		{ AUD_POLYPH80SCALEFAC,	0x0003},
+		{AUD_POLYPH80SCALEFAC, 0x0003},
 		{ /* end of list */ },
 	};
 
 	/* It is enough to leave default values? */
 	static const struct rlist fm_no_deemph[] = {
 
-		{ AUD_POLYPH80SCALEFAC,	0x0003},
+		{AUD_POLYPH80SCALEFAC, 0x0003},
 		{ /* end of list */ },
 	};
 
-	dprintk("%s (status: unknown)\n",__FUNCTION__);
+	dprintk("%s (status: unknown)\n", __FUNCTION__);
 	set_audio_start(core, SEL_FMRADIO);
 
-	switch (deemph)
-	{
-		case FM_NO_DEEMPH:
-			set_audio_registers(core, fm_no_deemph);
-			break;
+	switch (deemph) {
+	case FM_NO_DEEMPH:
+		set_audio_registers(core, fm_no_deemph);
+		break;
 
-		case FM_DEEMPH_50:
-			set_audio_registers(core, fm_deemph_50);
-			break;
+	case FM_DEEMPH_50:
+		set_audio_registers(core, fm_deemph_50);
+		break;
 
-		case FM_DEEMPH_75:
-			set_audio_registers(core, fm_deemph_75);
-			break;
+	case FM_DEEMPH_75:
+		set_audio_registers(core, fm_deemph_75);
+		break;
 	}
 
 	set_audio_finish(core, EN_FMRADIO_AUTO_STEREO);
@@ -728,36 +705,64 @@
 
 /* ----------------------------------------------------------- */
 
+int cx88_detect_nicam(struct cx88_core *core)
+{
+	int i, j = 0;
+
+	dprintk("start nicam autodetect.\n");
+
+	for (i = 0; i < 6; i++) {
+		/* if bit1=1 then nicam is detected */
+		j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1);
+
+		/* 3x detected: absolutly sure now */
+		if (j == 3) {
+			dprintk("nicam is detected.\n");
+			return 1;
+		}
+
+		/* wait a little bit for next reading status */
+		msleep(10);
+	}
+
+	dprintk("nicam is not detected.\n");
+	return 0;
+}
+
 void cx88_set_tvaudio(struct cx88_core *core)
 {
 	switch (core->tvaudio) {
 	case WW_BTSC:
 		set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
 		break;
-	case WW_NICAM_BGDKL:
-		set_audio_standard_NICAM_L(core,0);
-		break;
-	case WW_NICAM_I:
-		set_audio_standard_PAL_I(core,0);
-		break;
-	case WW_A2_BG:
-	case WW_A2_DK:
-	case WW_A2_M:
-	set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+	case WW_BG:
+	case WW_DK:
+	case WW_I:
+	case WW_L:
+		/* prepare all dsp registers */
+		set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+
+		/* set nicam mode - otherwise
+		   AUD_NICAM_STATUS2 contains wrong values */
+		set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO);
+		if (0 == cx88_detect_nicam(core)) {
+			/* fall back to fm / am mono */
+			set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+			core->use_nicam = 0;
+		} else {
+			core->use_nicam = 1;
+		}
 		break;
 	case WW_EIAJ:
 		set_audio_standard_EIAJ(core);
 		break;
 	case WW_FM:
-		set_audio_standard_FM(core,FM_NO_DEEMPH);
-		break;
-	case WW_SYSTEM_L_AM:
-		set_audio_standard_NICAM_L(core, 1);
+		set_audio_standard_FM(core, FM_NO_DEEMPH);
 		break;
 	case WW_NONE:
 	default:
 		printk("%s/0: unknown tv audio mode [%d]\n",
-		core->name, core->tvaudio);
+		       core->name, core->tvaudio);
 		break;
 	}
 	return;
@@ -766,24 +771,16 @@
 void cx88_newstation(struct cx88_core *core)
 {
 	core->audiomode_manual = UNSET;
-
-	switch (core->tvaudio) {
-	case WW_SYSTEM_L_AM:
-		/* try nicam ... */
-		core->audiomode_current = V4L2_TUNER_MODE_STEREO;
-		set_audio_standard_NICAM_L(core, 1);
-		break;
-	}
 }
 
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
 {
-	static char *m[] = {"stereo", "dual mono", "mono", "sap"};
-	static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
-	u32 reg,mode,pilot;
+	static char *m[] = { "stereo", "dual mono", "mono", "sap" };
+	static char *p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
+	u32 reg, mode, pilot;
 
-	reg   = cx_read(AUD_STATUS);
-	mode  = reg & 0x03;
+	reg = cx_read(AUD_STATUS);
+	mode = reg & 0x03;
 	pilot = (reg >> 2) & 0x03;
 
 	if (core->astat != reg)
@@ -800,14 +797,13 @@
 
 # if 0
 	t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
-		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+	    V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
 	t->rxsubchans = V4L2_TUNER_SUB_MONO;
-	t->audmode    = V4L2_TUNER_MODE_MONO;
+	t->audmode = V4L2_TUNER_MODE_MONO;
 
 	switch (core->tvaudio) {
 	case WW_BTSC:
-		t->capability = V4L2_TUNER_CAP_STEREO |
-			V4L2_TUNER_CAP_SAP;
+		t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP;
 		t->rxsubchans = V4L2_TUNER_SUB_STEREO;
 		if (1 == pilot) {
 			/* SAP */
@@ -819,13 +815,15 @@
 	case WW_A2_M:
 		if (1 == pilot) {
 			/* stereo */
-			t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+			t->rxsubchans =
+			    V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
 			if (0 == mode)
 				t->audmode = V4L2_TUNER_MODE_STEREO;
 		}
 		if (2 == pilot) {
 			/* dual language -- FIXME */
-			t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+			t->rxsubchans =
+			    V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 			t->audmode = V4L2_TUNER_MODE_LANG1;
 		}
 		break;
@@ -840,7 +838,7 @@
 			t->audmode = V4L2_TUNER_MODE_STEREO;
 			t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
 		}
-		break ;
+		break;
 	default:
 		/* nothing */
 		break;
@@ -851,7 +849,7 @@
 
 void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
 {
-	u32 ctl  = UNSET;
+	u32 ctl = UNSET;
 	u32 mask = UNSET;
 
 	if (manual) {
@@ -879,68 +877,58 @@
 			break;
 		}
 		break;
-	case WW_A2_BG:
-	case WW_A2_DK:
-	case WW_A2_M:
-		switch (mode) {
-		case V4L2_TUNER_MODE_MONO:
-		case V4L2_TUNER_MODE_LANG1:
-		set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
-			break;
-		case V4L2_TUNER_MODE_LANG2:
-		set_audio_standard_A2(core, EN_A2_FORCE_MONO2);
-			break;
-		case V4L2_TUNER_MODE_STEREO:
-		set_audio_standard_A2(core, EN_A2_FORCE_STEREO);
-			break;
-		}
-		break;
-	case WW_NICAM_BGDKL:
-		switch (mode) {
-		case V4L2_TUNER_MODE_MONO:
-			ctl  = EN_NICAM_FORCE_MONO1;
-			mask = 0x3f;
-			break;
-		case V4L2_TUNER_MODE_LANG1:
-			ctl  = EN_NICAM_AUTO_MONO2;
-			mask = 0x3f;
-			break;
-		case V4L2_TUNER_MODE_STEREO:
-			ctl  = EN_NICAM_FORCE_STEREO | EN_DMTRX_LR;
-			mask = 0x93f;
-			break;
-		}
-		break;
-	case WW_SYSTEM_L_AM:
-		switch (mode) {
-		case V4L2_TUNER_MODE_MONO:
-		case V4L2_TUNER_MODE_LANG1:  /* FIXME */
-			set_audio_standard_NICAM_L(core, 0);
-			break;
-		case V4L2_TUNER_MODE_STEREO:
-			set_audio_standard_NICAM_L(core, 1);
-			break;
-		}
-		break;
-	case WW_NICAM_I:
-		switch (mode) {
-		case V4L2_TUNER_MODE_MONO:
-		case V4L2_TUNER_MODE_LANG1:
-			set_audio_standard_PAL_I(core, 0);
-			break;
-		case V4L2_TUNER_MODE_STEREO:
-			set_audio_standard_PAL_I(core, 1);
-			break;
+	case WW_BG:
+	case WW_DK:
+	case WW_I:
+	case WW_L:
+		if (1 == core->use_nicam) {
+			switch (mode) {
+			case V4L2_TUNER_MODE_MONO:
+			case V4L2_TUNER_MODE_LANG1:
+				set_audio_standard_NICAM(core,
+							 EN_NICAM_FORCE_MONO1);
+				break;
+			case V4L2_TUNER_MODE_LANG2:
+				set_audio_standard_NICAM(core,
+							 EN_NICAM_FORCE_MONO2);
+				break;
+			case V4L2_TUNER_MODE_STEREO:
+				set_audio_standard_NICAM(core,
+							 EN_NICAM_FORCE_STEREO);
+				break;
+			}
+		} else {
+			if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) {
+				/* fall back to fm / am mono */
+				set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+			} else {
+				/* TODO: Add A2 autodection */
+				switch (mode) {
+				case V4L2_TUNER_MODE_MONO:
+				case V4L2_TUNER_MODE_LANG1:
+					set_audio_standard_A2(core,
+							      EN_A2_FORCE_MONO1);
+					break;
+				case V4L2_TUNER_MODE_LANG2:
+					set_audio_standard_A2(core,
+							      EN_A2_FORCE_MONO2);
+					break;
+				case V4L2_TUNER_MODE_STEREO:
+					set_audio_standard_A2(core,
+							      EN_A2_FORCE_STEREO);
+					break;
+				}
+			}
 		}
 		break;
 	case WW_FM:
 		switch (mode) {
 		case V4L2_TUNER_MODE_MONO:
-			ctl  = EN_FMRADIO_FORCE_MONO;
+			ctl = EN_FMRADIO_FORCE_MONO;
 			mask = 0x3f;
 			break;
 		case V4L2_TUNER_MODE_STEREO:
-			ctl  = EN_FMRADIO_AUTO_STEREO;
+			ctl = EN_FMRADIO_AUTO_STEREO;
 			mask = 0x3f;
 			break;
 		}
@@ -970,8 +958,8 @@
 			break;
 
 		/* just monitor the audio status for now ... */
-		memset(&t,0,sizeof(t));
-		cx88_get_stereo(core,&t);
+		memset(&t, 0, sizeof(t));
+		cx88_get_stereo(core, &t);
 
 		if (UNSET != core->audiomode_manual)
 			/* manually set, don't do anything. */
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 3dbc074..24a48f8 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -34,6 +34,9 @@
 
 #include "cx88.h"
 
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
@@ -100,7 +103,7 @@
 		.id        = V4L2_STD_PAL_I,
 		.cxiformat = VideoFormatPAL,
 		.cxoformat = 0x181f0008,
-        },{
+	},{
 		.name      = "PAL-M",
 		.id        = V4L2_STD_PAL_M,
 		.cxiformat = VideoFormatPALM,
@@ -470,7 +473,7 @@
 	struct list_head *item;
 
 	if (!list_empty(&q->active)) {
-	        buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
 		dprintk(2,"restart_queue [%p/%d]: restart dma\n",
 			buf, buf->vb.i);
 		start_video_dma(dev, q, buf);
@@ -486,7 +489,7 @@
 	for (;;) {
 		if (list_empty(&q->queued))
 			return 0;
-	        buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+		buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
 		if (NULL == prev) {
 			list_del(&buf->vb.queue);
 			list_add_tail(&buf->vb.queue,&q->active);
@@ -783,11 +786,11 @@
 		cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
 	}
 
-        return 0;
+	return 0;
 }
 
 static ssize_t
-video_read(struct file *file, char *data, size_t count, loff_t *ppos)
+video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
 	struct cx8800_fh *fh = file->private_data;
 
@@ -922,7 +925,7 @@
 {
 	/* struct cx88_core *core = dev->core; */
 	struct cx88_ctrl *c = NULL;
-        u32 v_sat_value;
+	u32 v_sat_value;
 	u32 value;
 	int i;
 
@@ -1187,7 +1190,7 @@
 		struct v4l2_format *f = arg;
 		return cx8800_try_fmt(dev,fh,f);
 	}
-
+#ifdef HAVE_V4L1
 	/* --- streaming capture ------------------------------------- */
 	case VIDIOCGMBUF:
 	{
@@ -1213,6 +1216,7 @@
 		}
 		return 0;
 	}
+#endif
 	case VIDIOC_REQBUFS:
 		return videobuf_reqbufs(get_queue(fh), arg);
 
@@ -1244,7 +1248,6 @@
 		res_free(dev,fh,res);
 		return 0;
 	}
-
 	default:
 		return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl );
 	}
@@ -1252,15 +1255,13 @@
 }
 
 int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
-                  struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
+		  struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
 {
 	int err;
 
+	dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
 	if (video_debug > 1)
 		cx88_print_ioctl(core->name,cmd);
-	printk( KERN_INFO "CORE IOCTL: 0x%x\n", cmd );
-	cx88_print_ioctl(core->name,cmd);
-	dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
 
 	switch (cmd) {
 	/* ---------- tv norms ---------- */
@@ -1401,7 +1402,7 @@
 
 		cx88_get_stereo(core ,t);
 		reg = cx_read(MO_DEVICE_STATUS);
-                t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+		t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
 		return 0;
 	}
 	case VIDIOC_S_TUNER:
@@ -1488,7 +1489,7 @@
 		struct v4l2_capability *cap = arg;
 
 		memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "cx8800");
+		strcpy(cap->driver, "cx8800");
 		strlcpy(cap->card, cx88_boards[core->board].name,
 			sizeof(cap->card));
 		sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
@@ -1505,6 +1506,7 @@
 
 		memset(t,0,sizeof(*t));
 		strcpy(t->name, "Radio");
+		t->type = V4L2_TUNER_RADIO;
 
 		cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
 		return 0;
@@ -1539,6 +1541,7 @@
 		*id = 0;
 		return 0;
 	}
+#ifdef HAVE_V4L1
 	case VIDIOCSTUNER:
 	{
 		struct video_tuner *v = arg;
@@ -1549,6 +1552,7 @@
 		cx88_call_i2c_clients(core,VIDIOCSTUNER,v);
 		return 0;
 	}
+#endif
 	case VIDIOC_S_TUNER:
 	{
 		struct v4l2_tuner *t = arg;
@@ -1829,8 +1833,8 @@
 
 	/* print pci info */
 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
-        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
-        printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
 	       "latency: %d, mmio: 0x%lx\n", core->name,
 	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
 	       dev->pci_lat,pci_resource_start(pci_dev,0));
@@ -1946,7 +1950,7 @@
 
 static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
 {
-        struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+	struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
 	struct cx88_core *core = dev->core;
 
 	/* stop thread */
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index f48dd43..b19d3a9e 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -22,7 +22,7 @@
 #include <linux/pci.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/kdev_t.h>
 
 #include <media/tuner.h>
@@ -148,7 +148,7 @@
 #define CX88_BOARD_PIXELVIEW                3
 #define CX88_BOARD_ATI_WONDER_PRO           4
 #define CX88_BOARD_WINFAST2000XP_EXPERT     5
-#define CX88_BOARD_AVERTV_303               6
+#define CX88_BOARD_AVERTV_STUDIO_303        6
 #define CX88_BOARD_MSI_TVANYWHERE_MASTER    7
 #define CX88_BOARD_WINFAST_DV2000           8
 #define CX88_BOARD_LEADTEK_PVR2000          9
@@ -174,6 +174,11 @@
 #define CX88_BOARD_ADSTECH_DVB_T_PCI          29
 #define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1  30
 #define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31
+#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32
+#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33
+#define CX88_BOARD_ATI_HDTVWONDER          34
+#define CX88_BOARD_WINFAST_DTV1000         35
+#define CX88_BOARD_AVERTV_303              36
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -203,8 +208,8 @@
 	int                     tda9887_conf;
 	struct cx88_input       input[MAX_CX88_INPUT];
 	struct cx88_input       radio;
-	int                     blackbird:1;
-	int                     dvb:1;
+	unsigned int            blackbird:1;
+	unsigned int            dvb:1;
 };
 
 struct cx88_subid {
@@ -255,8 +260,8 @@
 	/* pci stuff */
 	int                        pci_bus;
 	int                        pci_slot;
-        u32                        __iomem *lmmio;
-        u8                         __iomem *bmmio;
+	u32                        __iomem *lmmio;
+	u8                         __iomem *bmmio;
 	u32                        shadow[SHADOW_MAX];
 	int                        pci_irqmask;
 
@@ -287,6 +292,7 @@
 	u32                        audiomode_current;
 	u32                        input;
 	u32                        astat;
+	u32			   use_nicam;
 
 	/* IR remote control state */
 	struct cx88_IR             *ir;
@@ -370,6 +376,14 @@
 	int                        disabled;
 };
 
+/* TODO: move this to struct v4l2_mpeg_compression ? */
+struct blackbird_dnr {
+	u32                       mode;
+	u32                       type;
+	u32                       spatial;
+	u32                       temporal;
+};
+
 struct cx8802_dev {
 	struct cx88_core           *core;
 	spinlock_t                 slock;
@@ -400,6 +414,10 @@
 
 	/* for switching modulation types */
 	unsigned char              ts_gen_cntrl;
+
+	/* mpeg params */
+	struct v4l2_mpeg_compression params;
+	struct blackbird_dnr       dnr_params;
 };
 
 /* ----------------------------------------------------------- */
@@ -514,22 +532,20 @@
 
 #define WW_NONE		 1
 #define WW_BTSC		 2
-#define WW_NICAM_I	 3
-#define WW_NICAM_BGDKL	 4
-#define WW_A1		 5
-#define WW_A2_BG	 6
-#define WW_A2_DK	 7
-#define WW_A2_M		 8
-#define WW_EIAJ		 9
-#define WW_SYSTEM_L_AM	10
-#define WW_I2SPT	11
-#define WW_FM		12
+#define WW_BG		 3
+#define WW_DK		 4
+#define WW_I		 5
+#define WW_L		 6
+#define WW_EIAJ		 7
+#define WW_I2SPT	 8
+#define WW_FM		 9
 
 void cx88_set_tvaudio(struct cx88_core *core);
 void cx88_newstation(struct cx88_core *core);
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
 void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
 int cx88_audio_thread(void *data);
+int cx88_detect_nicam(struct cx88_core *core);
 
 /* ----------------------------------------------------------- */
 /* cx88-input.c                                                */
@@ -541,7 +557,8 @@
 /* ----------------------------------------------------------- */
 /* cx88-mpeg.c                                                 */
 
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf);
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
+			enum v4l2_field field);
 void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
 void cx8802_cancel_buffers(struct cx8802_dev *dev);
 
@@ -562,6 +579,10 @@
 extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
 				unsigned int cmd, void *arg);
 extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+void blackbird_set_params(struct cx8802_dev *dev,
+				struct v4l2_mpeg_compression *params);
+void blackbird_set_dnr_params(struct cx8802_dev *dev,
+				struct blackbird_dnr* dnr_params);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
new file mode 100644
index 0000000..885fd01
--- /dev/null
+++ b/drivers/media/video/em28xx/Kconfig
@@ -0,0 +1,12 @@
+config VIDEO_EM28XX
+	tristate "Empia EM2800/2820/2840 USB video capture support"
+	depends on VIDEO_DEV && USB && I2C
+	select VIDEO_BUF
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_IR
+	---help---
+	  This is a video4linux driver for Empia 28xx based TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called em28xx
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
new file mode 100644
index 0000000..da457a0
--- /dev/null
+++ b/drivers/media/video/em28xx/Makefile
@@ -0,0 +1,6 @@
+em28xx-objs     := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
+		   em28xx-input.o
+
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+
+EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
new file mode 100644
index 0000000..57779e6
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -0,0 +1,292 @@
+/*
+   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Sascha Sommer <saschasommer@freenet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <media/tuner.h>
+#include <media/audiochip.h>
+#include <media/tveeprom.h>
+#include "msp3400.h"
+
+#include "em28xx.h"
+
+struct em28xx_board em28xx_boards[] = {
+	[EM2800_BOARD_UNKNOWN] = {
+		.name         = "Unknown EM2800 video grabber",
+		.is_em2800    = 1,
+		.vchannels    = 2,
+		.norm         = VIDEO_MODE_PAL,
+		.tda9887_conf = TDA9887_PRESENT,
+		.has_tuner    = 1,
+		.decoder      = EM28XX_SAA7113,
+		.input           = {{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
+	[EM2820_BOARD_UNKNOWN] = {
+		.name         = "Unknown EM2820/2840 video grabber",
+		.is_em2800    = 0,
+		.vchannels    = 2,
+		.norm         = VIDEO_MODE_PAL,
+		.tda9887_conf = TDA9887_PRESENT,
+		.has_tuner    = 1,
+		.decoder      = EM28XX_SAA7113,
+		.input           = {{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
+	[EM2820_BOARD_TERRATEC_CINERGY_250] = {
+		.name         = "Terratec Cinergy 250 USB",
+		.vchannels    = 3,
+		.norm         = VIDEO_MODE_PAL,
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.has_tuner    = 1,
+		.decoder      = EM28XX_SAA7113,
+		.input          = {{
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = 2,
+			.amux     = 0,
+		},{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
+	[EM2820_BOARD_PINNACLE_USB_2] = {
+		.name         = "Pinnacle PCTV USB 2",
+		.vchannels    = 3,
+		.norm         = VIDEO_MODE_PAL,
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.has_tuner    = 1,
+		.decoder      = EM28XX_SAA7113,
+		.input          = {{
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = 2,
+			.amux     = 0,
+		},{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
+	[EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
+		.name         = "Hauppauge WinTV USB 2",
+		.vchannels    = 3,
+		.norm         = VIDEO_MODE_NTSC,
+		.tuner_type   = TUNER_PHILIPS_FM1236_MK3,
+		.tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+		.has_tuner    = 1,
+		.decoder      = EM28XX_TVP5150,
+		.has_msp34xx  = 1,
+		/*FIXME: S-Video not tested */
+		.input          = {{
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = 0,
+			.amux     = 6,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 2,
+			.amux     = 1,
+		}},
+	},
+	[EM2820_BOARD_MSI_VOX_USB_2] = {
+		.name		= "MSI VOX USB 2.0",
+		.vchannels	= 3,
+		.norm		= VIDEO_MODE_PAL,
+		.tuner_type	= TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf	= TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+		.has_tuner	= 1,
+		.decoder        = EM28XX_SAA7114,
+		.input          = {{
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = 4,
+			.amux     = 0,
+		},{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
+	[EM2800_BOARD_TERRATEC_CINERGY_200] = {
+		.name         = "Terratec Cinergy 200 USB",
+		.is_em2800    = 1,
+		.vchannels    = 3,
+		.norm         = VIDEO_MODE_PAL,
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.has_tuner    = 1,
+		.decoder      = EM28XX_SAA7113,
+		.input          = {{
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = 2,
+			.amux     = 0,
+		},{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
+	[EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
+		.name         = "Leadtek Winfast USB II",
+		.is_em2800    = 1,
+		.vchannels    = 3,
+		.norm         = VIDEO_MODE_PAL,
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.has_tuner    = 1,
+		.decoder      = EM28XX_SAA7113,
+		.input          = {{
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = 2,
+			.amux     = 0,
+		},{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
+	[EM2800_BOARD_KWORLD_USB2800] = {
+		.name         = "Kworld USB2800",
+		.is_em2800    = 1,
+		.vchannels    = 3,
+		.norm         = VIDEO_MODE_PAL,
+		.tuner_type   = TUNER_PHILIPS_ATSC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.has_tuner    = 1,
+		.decoder      = EM28XX_SAA7113,
+		.input          = {{
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = 2,
+			.amux     = 0,
+		},{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
+	[EM2820_BOARD_PINNACLE_DVC_90] = {
+		.name         = "Pinnacle Dazzle DVC 90",
+		.vchannels    = 3,
+		.norm         = VIDEO_MODE_PAL,
+		.has_tuner    = 0,
+		.decoder      = EM28XX_SAA7113,
+		.input          = {{
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = 0,
+			.amux     = 1,
+		},{
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = 9,
+			.amux     = 1,
+		}},
+	},
+};
+const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+
+/* table of devices that work with this driver */
+struct usb_device_id em28xx_id_table [] = {
+	{ USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
+	{ USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+	{ USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
+	{ USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+	{ USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+	{ },
+};
+
+void em28xx_card_setup(struct em28xx *dev)
+{
+	/* request some modules */
+	if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
+		struct tveeprom tv;
+		struct v4l2_audioout ao;
+#ifdef CONFIG_MODULES
+		request_module("tveeprom");
+		request_module("ir-kbd-i2c");
+		request_module("msp3400");
+#endif
+		/* Call first TVeeprom */
+
+		dev->i2c_client.addr = 0xa0 >> 1;
+		tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+
+		dev->tuner_type= tv.tuner_type;
+		if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+			dev->has_msp34xx=1;
+			memset (&ao,0,sizeof(ao));
+
+			ao.index=2;
+			ao.mode=V4L2_AUDMODE_32BITS;
+			em28xx_i2c_call_clients(dev, VIDIOC_S_AUDOUT, &ao);
+		} else
+			dev->has_msp34xx=0;
+	}
+}
+
+EXPORT_SYMBOL(em28xx_boards);
+EXPORT_SYMBOL(em28xx_bcount);
+EXPORT_SYMBOL(em28xx_id_table);
+
+MODULE_DEVICE_TABLE (usb, em28xx_id_table);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
new file mode 100644
index 0000000..d54bc0127
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -0,0 +1,817 @@
+/*
+   em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Sascha Sommer <saschasommer@freenet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+
+#include "em28xx.h"
+
+/* #define ENABLE_DEBUG_ISOC_FRAMES */
+
+unsigned int core_debug;
+module_param(core_debug,int,0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+#define em28xx_coredbg(fmt, arg...) do {\
+	if (core_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __FUNCTION__ , ##arg); } while (0)
+
+unsigned int reg_debug;
+module_param(reg_debug,int,0644);
+MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
+
+#define em28xx_regdbg(fmt, arg...) do {\
+	if (reg_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __FUNCTION__ , ##arg); } while (0)
+
+unsigned int isoc_debug;
+module_param(isoc_debug,int,0644);
+MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
+
+#define em28xx_isocdbg(fmt, arg...) do {\
+	if (isoc_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __FUNCTION__ , ##arg); } while (0)
+
+static int alt = EM28XX_PINOUT;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+
+/* ------------------------------------------------------------------ */
+/* debug help functions                                               */
+
+static const char *v4l1_ioctls[] = {
+	"0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
+	"CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
+	"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
+	"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
+	"SMICROCODE", "GVBIFMT", "SVBIFMT" };
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
+
+static const char *v4l2_ioctls[] = {
+	"QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
+	"G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
+	"G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
+	"STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
+	"ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
+	"G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
+	"QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
+	"44", "45",  "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
+	"S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
+	"S_MODULATOR"
+};
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+void em28xx_print_ioctl(char *name, unsigned int cmd)
+{
+	char *dir;
+
+	switch (_IOC_DIR(cmd)) {
+	case _IOC_NONE:              dir = "--"; break;
+	case _IOC_READ:              dir = "r-"; break;
+	case _IOC_WRITE:             dir = "-w"; break;
+	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+	default:                     dir = "??"; break;
+	}
+	switch (_IOC_TYPE(cmd)) {
+	case 'v':
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
+		       name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
+		       v4l1_ioctls[_IOC_NR(cmd)] : "???");
+		break;
+	case 'V':
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
+		       name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
+		       v4l2_ioctls[_IOC_NR(cmd)] : "???");
+		break;
+	default:
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
+		       name, cmd, dir, _IOC_NR(cmd));
+	}
+}
+
+static void *rvmalloc(size_t size)
+{
+	void *mem;
+	unsigned long adr;
+
+	size = PAGE_ALIGN(size);
+
+	mem = vmalloc_32((unsigned long)size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size);
+
+	adr = (unsigned long)mem;
+	while (size > 0) {
+		SetPageReserved(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	return mem;
+}
+
+static void rvfree(void *mem, size_t size)
+{
+	unsigned long adr;
+
+	if (!mem)
+		return;
+
+	size = PAGE_ALIGN(size);
+
+	adr = (unsigned long)mem;
+	while (size > 0) {
+		ClearPageReserved(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	vfree(mem);
+}
+
+/*
+ * em28xx_request_buffers()
+ * allocate a number of buffers
+ */
+u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
+{
+	const size_t imagesize = PAGE_ALIGN(dev->frame_size);	/*needs to be page aligned cause the buffers can be mapped individually! */
+	void *buff = NULL;
+	u32 i;
+	em28xx_coredbg("requested %i buffers with size %i", count, imagesize);
+	if (count > EM28XX_NUM_FRAMES)
+		count = EM28XX_NUM_FRAMES;
+
+	dev->num_frames = count;
+	while (dev->num_frames > 0) {
+		if ((buff = rvmalloc(dev->num_frames * imagesize)))
+			break;
+		dev->num_frames--;
+	}
+
+	for (i = 0; i < dev->num_frames; i++) {
+		dev->frame[i].bufmem = buff + i * imagesize;
+		dev->frame[i].buf.index = i;
+		dev->frame[i].buf.m.offset = i * imagesize;
+		dev->frame[i].buf.length = dev->frame_size;
+		dev->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		dev->frame[i].buf.sequence = 0;
+		dev->frame[i].buf.field = V4L2_FIELD_NONE;
+		dev->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+		dev->frame[i].buf.flags = 0;
+	}
+	return dev->num_frames;
+}
+
+/*
+ * em28xx_queue_unusedframes()
+ * add all frames that are not currently in use to the inbuffer queue
+ */
+void em28xx_queue_unusedframes(struct em28xx *dev)
+{
+	unsigned long lock_flags;
+	u32 i;
+
+	for (i = 0; i < dev->num_frames; i++)
+		if (dev->frame[i].state == F_UNUSED) {
+			dev->frame[i].state = F_QUEUED;
+			spin_lock_irqsave(&dev->queue_lock, lock_flags);
+			list_add_tail(&dev->frame[i].frame, &dev->inqueue);
+			spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+		}
+}
+
+/*
+ * em28xx_release_buffers()
+ * free frame buffers
+ */
+void em28xx_release_buffers(struct em28xx *dev)
+{
+	if (dev->num_frames) {
+		rvfree(dev->frame[0].bufmem,
+		       dev->num_frames * PAGE_ALIGN(dev->frame[0].buf.length));
+		dev->num_frames = 0;
+	}
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+				   char *buf, int len)
+{
+	int ret, byte;
+
+	em28xx_regdbg("req=%02x, reg=%02x ", req, reg);
+
+	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0x0000, reg, buf, len, HZ);
+
+	if (reg_debug){
+		printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
+		for (byte = 0; byte < len; byte++) {
+			printk(" %02x", buf[byte]);
+		}
+		printk("\n");
+	}
+
+	return ret;
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
+{
+	u8 val;
+	int ret;
+
+	em28xx_regdbg("req=%02x, reg=%02x:", req, reg);
+
+	ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0x0000, reg, &val, 1, HZ);
+
+	if (reg_debug)
+		printk(ret < 0 ? " failed!\n" : "%02x\n", val);
+
+	if (ret < 0)
+		return ret;
+
+	return val;
+}
+
+int em28xx_read_reg(struct em28xx *dev, u16 reg)
+{
+	return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);
+}
+
+/*
+ * em28xx_write_regs_req()
+ * sends data to the usb device, specifying bRequest
+ */
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+				 int len)
+{
+	int ret;
+
+	/*usb_control_msg seems to expect a kmalloced buffer */
+	unsigned char *bufs = kmalloc(len, GFP_KERNEL);
+
+	em28xx_regdbg("req=%02x reg=%02x:", req, reg);
+
+	if (reg_debug) {
+		int i;
+		for (i = 0; i < len; ++i)
+			printk (" %02x", (unsigned char)buf[i]);
+		printk ("\n");
+	}
+
+	if (!bufs)
+		return -ENOMEM;
+	memcpy(bufs, buf, len);
+	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0x0000, reg, bufs, len, HZ);
+	mdelay(5);		/* FIXME: magic number */
+	kfree(bufs);
+	return ret;
+}
+
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
+{
+	return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+}
+
+/*
+ * em28xx_write_reg_bits()
+ * sets only some bits (specified by bitmask) of a register, by first reading
+ * the actual value
+ */
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+				 u8 bitmask)
+{
+	int oldval;
+	u8 newval;
+	if ((oldval = em28xx_read_reg(dev, reg)) < 0)
+		return oldval;
+	newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+	return em28xx_write_regs(dev, reg, &newval, 1);
+}
+
+/*
+ * em28xx_write_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
+{
+	int ret;
+	u8 addr = reg & 0x7f;
+	if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
+		return ret;
+	if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
+		return ret;
+	if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+		return ret;
+	else if (((u8) ret) & 0x01) {
+		em28xx_warn ("AC97 command still being exectuted: not handled properly!\n");
+	}
+	return 0;
+}
+
+int em28xx_audio_analog_set(struct em28xx *dev)
+{
+	char s[2] = { 0x00, 0x00 };
+	s[0] |= 0x1f - dev->volume;
+	s[1] |= 0x1f - dev->volume;
+	if (dev->mute)
+		s[1] |= 0x80;
+	return em28xx_write_ac97(dev, MASTER_AC97, s);
+}
+
+
+int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+	em28xx_write_regs(dev, YGAIN_REG, "\x10", 1);	/* contrast */
+	em28xx_write_regs(dev, YOFFSET_REG, "\x00", 1);	/* brightness */
+	em28xx_write_regs(dev, UVGAIN_REG, "\x10", 1);	/* saturation */
+	em28xx_write_regs(dev, UOFFSET_REG, "\x00", 1);
+	em28xx_write_regs(dev, VOFFSET_REG, "\x00", 1);
+	em28xx_write_regs(dev, SHARPNESS_REG, "\x00", 1);
+
+	em28xx_write_regs(dev, GAMMA_REG, "\x20", 1);
+	em28xx_write_regs(dev, RGAIN_REG, "\x20", 1);
+	em28xx_write_regs(dev, GGAIN_REG, "\x20", 1);
+	em28xx_write_regs(dev, BGAIN_REG, "\x20", 1);
+	em28xx_write_regs(dev, ROFFSET_REG, "\x00", 1);
+	em28xx_write_regs(dev, GOFFSET_REG, "\x00", 1);
+	return em28xx_write_regs(dev, BOFFSET_REG, "\x00", 1);
+}
+
+int em28xx_capture_start(struct em28xx *dev, int start)
+{
+	int ret;
+	/* FIXME: which is the best order? */
+	/* video registers are sampled by VREF */
+	if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00,
+					  0x10)) < 0)
+		return ret;
+	/* enable video capture */
+	return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1);
+}
+
+int em28xx_outfmt_set_yuv422(struct em28xx *dev)
+{
+	em28xx_write_regs(dev, OUTFMT_REG, "\x34", 1);
+	em28xx_write_regs(dev, VINMODE_REG, "\x10", 1);
+	return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
+}
+
+int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
+				  u8 ymax)
+{
+	em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
+
+	em28xx_write_regs(dev, XMIN_REG, &xmin, 1);
+	em28xx_write_regs(dev, XMAX_REG, &xmax, 1);
+	em28xx_write_regs(dev, YMIN_REG, &ymin, 1);
+	return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
+}
+
+int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+				   u16 width, u16 height)
+{
+	u8 cwidth = width;
+	u8 cheight = height;
+	u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
+
+	em28xx_coredbg("em28xx Area Set: (%d,%d)\n", (width | (overflow & 2) << 7),
+			(height | (overflow & 1) << 8));
+
+	em28xx_write_regs(dev, HSTART_REG, &hstart, 1);
+	em28xx_write_regs(dev, VSTART_REG, &vstart, 1);
+	em28xx_write_regs(dev, CWIDTH_REG, &cwidth, 1);
+	em28xx_write_regs(dev, CHEIGHT_REG, &cheight, 1);
+	return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
+}
+
+int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+	u8 mode;
+	/* the em2800 scaler only supports scaling down to 50% */
+	if(dev->is_em2800)
+		mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+	else {
+		u8 buf[2];
+		buf[0] = h;
+		buf[1] = h >> 8;
+		em28xx_write_regs(dev, HSCALELOW_REG, (char *)buf, 2);
+		buf[0] = v;
+		buf[1] = v >> 8;
+		em28xx_write_regs(dev, VSCALELOW_REG, (char *)buf, 2);
+		/* it seems that both H and V scalers must be active to work correctly */
+		mode = (h || v)? 0x30: 0x00;
+	}
+	return em28xx_write_reg_bits(dev, COMPR_REG, mode, 0x30);
+}
+
+/* FIXME: this only function read values from dev */
+int em28xx_resolution_set(struct em28xx *dev)
+{
+	int width, height;
+	width = norm_maxw(dev);
+	height = norm_maxh(dev) >> 1;
+
+	em28xx_outfmt_set_yuv422(dev);
+	em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+	em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+}
+
+
+/******************* isoc transfer handling ****************************/
+
+#ifdef ENABLE_DEBUG_ISOC_FRAMES
+static void em28xx_isoc_dump(struct urb *urb, struct pt_regs *regs)
+{
+	int len = 0;
+	int ntrans = 0;
+	int i;
+
+	printk(KERN_DEBUG "isocIrq: sf=%d np=%d ec=%x\n",
+	       urb->start_frame, urb->number_of_packets,
+	       urb->error_count);
+	for (i = 0; i < urb->number_of_packets; i++) {
+		unsigned char *buf =
+				urb->transfer_buffer +
+				urb->iso_frame_desc[i].offset;
+		int alen = urb->iso_frame_desc[i].actual_length;
+		if (alen > 0) {
+			if (buf[0] == 0x88) {
+				ntrans++;
+				len += alen;
+			} else if (buf[0] == 0x22) {
+				printk(KERN_DEBUG
+						"= l=%d nt=%d bpp=%d\n",
+				len - 4 * ntrans, ntrans,
+				ntrans == 0 ? 0 : len / ntrans);
+				ntrans = 1;
+				len = alen;
+			} else
+				printk(KERN_DEBUG "!\n");
+		}
+		printk(KERN_DEBUG "   n=%d s=%d al=%d %x\n", i,
+		       urb->iso_frame_desc[i].status,
+		       urb->iso_frame_desc[i].actual_length,
+		       (unsigned int)
+				       *((unsigned char *)(urb->transfer_buffer +
+				       urb->iso_frame_desc[i].
+				       offset)));
+	}
+}
+#endif
+
+static inline int em28xx_isoc_video(struct em28xx *dev,struct em28xx_frame_t **f,
+				    unsigned long *lock_flags, unsigned char buf)
+{
+	if (!(buf & 0x01)) {
+		if ((*f)->state == F_GRABBING) {
+			/*previous frame is incomplete */
+			if ((*f)->fieldbytesused < dev->field_size) {
+				(*f)->state = F_ERROR;
+				em28xx_isocdbg ("dropping incomplete bottom field (%i missing bytes)",
+					 dev->field_size-(*f)->fieldbytesused);
+			} else {
+				(*f)->state = F_DONE;
+				(*f)->buf.bytesused = dev->frame_size;
+			}
+		}
+		if ((*f)->state == F_DONE || (*f)->state == F_ERROR) {
+			/* move current frame to outqueue and get next free buffer from inqueue */
+			spin_lock_irqsave(&dev-> queue_lock, *lock_flags);
+			list_move_tail(&(*f)->frame, &dev->outqueue);
+			if (!list_empty(&dev->inqueue))
+				(*f) = list_entry(dev-> inqueue.next,
+			struct em28xx_frame_t,frame);
+			else
+				(*f) = NULL;
+			spin_unlock_irqrestore(&dev->queue_lock,*lock_flags);
+		}
+		if (!(*f)) {
+			em28xx_isocdbg ("new frame but no buffer is free");
+			return -1;
+		}
+		do_gettimeofday(&(*f)->buf.timestamp);
+		(*f)->buf.sequence = ++dev->frame_count;
+		(*f)->buf.field = V4L2_FIELD_INTERLACED;
+		(*f)->state = F_GRABBING;
+		(*f)->buf.bytesused = 0;
+		(*f)->top_field = 1;
+		(*f)->fieldbytesused = 0;
+	} else {
+					/* acquiring bottom field */
+		if ((*f)->state == F_GRABBING) {
+			if (!(*f)->top_field) {
+				(*f)->state = F_ERROR;
+				em28xx_isocdbg ("unexpected begin of bottom field; discarding it");
+			} else if ((*f)-> fieldbytesused < dev->field_size - 172) {
+				(*f)->state = F_ERROR;
+				em28xx_isocdbg ("dropping incomplete top field (%i missing bytes)",
+					 dev->field_size-(*f)->fieldbytesused);
+			} else {
+				(*f)->top_field = 0;
+				(*f)->fieldbytesused = 0;
+			}
+		}
+	}
+	return (0);
+}
+
+static inline void em28xx_isoc_video_copy(struct em28xx *dev,
+					  struct em28xx_frame_t **f, unsigned char *buf, int len)
+{
+	void *fieldstart, *startwrite, *startread;
+	int linesdone, currlinedone, offset, lencopy,remain;
+
+	if(dev->frame_size != (*f)->buf.length){
+		em28xx_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
+		return;
+	}
+
+	if ((*f)->fieldbytesused + len > dev->field_size)
+		len =dev->field_size - (*f)->fieldbytesused;
+
+	if (buf[0] != 0x88 && buf[0] != 0x22) {
+		em28xx_isocdbg("frame is not complete\n");
+		startread = buf;
+		len+=4;
+	} else
+		startread = buf + 4;
+
+	remain = len;
+
+	if ((*f)->top_field)
+		fieldstart = (*f)->bufmem;
+	else
+		fieldstart = (*f)->bufmem + dev->bytesperline;
+
+	linesdone = (*f)->fieldbytesused / dev->bytesperline;
+	currlinedone = (*f)->fieldbytesused % dev->bytesperline;
+	offset = linesdone * dev->bytesperline * 2 + currlinedone;
+	startwrite = fieldstart + offset;
+	lencopy = dev->bytesperline - currlinedone;
+	lencopy = lencopy > remain ? remain : lencopy;
+
+	memcpy(startwrite, startread, lencopy);
+	remain -= lencopy;
+
+	while (remain > 0) {
+		startwrite += lencopy + dev->bytesperline;
+		startread += lencopy;
+		if (dev->bytesperline > remain)
+			lencopy = remain;
+		else
+			lencopy = dev->bytesperline;
+
+		memcpy(startwrite, startread, lencopy);
+		remain -= lencopy;
+	}
+
+	(*f)->fieldbytesused += len;
+}
+
+/*
+ * em28xx_isoIrq()
+ * handles the incoming isoc urbs and fills the frames from our inqueue
+ */
+void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+{
+	struct em28xx *dev = urb->context;
+	int i, status;
+	struct em28xx_frame_t **f;
+	unsigned long lock_flags;
+
+	if (!dev)
+		return;
+#ifdef ENABLE_DEBUG_ISOC_FRAMES
+	if (isoc_debug>1)
+		em28xx_isoc_dump(urb, regs);
+#endif
+
+	if (urb->status == -ENOENT)
+		return;
+
+	f = &dev->frame_current;
+
+	if (dev->stream == STREAM_INTERRUPT) {
+		dev->stream = STREAM_OFF;
+		if ((*f))
+			(*f)->state = F_QUEUED;
+		em28xx_isocdbg("stream interrupted");
+		wake_up_interruptible(&dev->wait_stream);
+	}
+
+	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+		return;
+
+	if (dev->stream == STREAM_ON && !list_empty(&dev->inqueue)) {
+		if (!(*f))
+			(*f) = list_entry(dev->inqueue.next,
+		struct em28xx_frame_t, frame);
+
+		for (i = 0; i < urb->number_of_packets; i++) {
+			unsigned char *buf = urb->transfer_buffer +
+					urb->iso_frame_desc[i].offset;
+			int len = urb->iso_frame_desc[i].actual_length - 4;
+
+			if (urb->iso_frame_desc[i].status) {
+				em28xx_isocdbg("data error: [%d] len=%d, status=%d", i,
+					urb->iso_frame_desc[i].actual_length,
+					urb->iso_frame_desc[i].status);
+				if (urb->iso_frame_desc[i].status != -EPROTO)
+					continue;
+			}
+			if (urb->iso_frame_desc[i].actual_length <= 0) {
+				em28xx_isocdbg("packet %d is empty",i);
+				continue;
+			}
+			if (urb->iso_frame_desc[i].actual_length >
+						 dev->max_pkt_size) {
+				em28xx_isocdbg("packet bigger than packet size");
+				continue;
+			}
+			/*new frame */
+			if (buf[0] == 0x22 && buf[1] == 0x5a) {
+				em28xx_isocdbg("Video frame, length=%i!",len);
+
+				if (em28xx_isoc_video(dev,f,&lock_flags,buf[2]))
+				break;
+			} else if (buf[0]==0x33 && buf[1]==0x95 && buf[2]==0x00) {
+				em28xx_isocdbg("VBI HEADER!!!");
+			}
+
+			/* actual copying */
+			if ((*f)->state == F_GRABBING) {
+				em28xx_isoc_video_copy(dev,f,buf, len);
+			}
+		}
+	}
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		urb->iso_frame_desc[i].status = 0;
+		urb->iso_frame_desc[i].actual_length = 0;
+	}
+
+	urb->status = 0;
+	if ((status = usb_submit_urb(urb, GFP_ATOMIC))) {
+		em28xx_errdev("resubmit of urb failed (error=%i)\n", status);
+		dev->state |= DEV_MISCONFIGURED;
+	}
+	wake_up_interruptible(&dev->wait_frame);
+	return;
+}
+
+/*
+ * em28xx_uninit_isoc()
+ * deallocates the buffers and urbs allocated during em28xx_init_iosc()
+ */
+void em28xx_uninit_isoc(struct em28xx *dev)
+{
+	int i;
+
+	for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+		if (dev->urb[i]) {
+			usb_kill_urb(dev->urb[i]);
+			if (dev->transfer_buffer[i]){
+				usb_buffer_free(dev->udev,(EM28XX_NUM_PACKETS*dev->max_pkt_size),dev->transfer_buffer[i],dev->urb[i]->transfer_dma);
+			}
+			usb_free_urb(dev->urb[i]);
+		}
+		dev->urb[i] = NULL;
+		dev->transfer_buffer[i] = NULL;
+	}
+	em28xx_capture_start(dev, 0);
+}
+
+/*
+ * em28xx_init_isoc()
+ * allocates transfer buffers and submits the urbs for isoc transfer
+ */
+int em28xx_init_isoc(struct em28xx *dev)
+{
+	/* change interface to 3 which allowes the biggest packet sizes */
+	int i, errCode;
+	const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
+
+	/* reset streaming vars */
+	dev->frame_current = NULL;
+	dev->frame_count = 0;
+
+	/* allocate urbs */
+	for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+		struct urb *urb;
+		int j, k;
+		/* allocate transfer buffer */
+		urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
+		if (!urb){
+			em28xx_errdev("cannot alloc urb %i\n", i);
+			em28xx_uninit_isoc(dev);
+			return -ENOMEM;
+		}
+		dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,&urb->transfer_dma);
+		if (!dev->transfer_buffer[i]) {
+			em28xx_errdev
+					("unable to allocate %i bytes for transfer buffer %i\n",
+					 sb_size, i);
+			em28xx_uninit_isoc(dev);
+			return -ENOMEM;
+		}
+		memset(dev->transfer_buffer[i], 0, sb_size);
+		urb->dev = dev->udev;
+		urb->context = dev;
+		urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->interval = 1;
+		urb->transfer_buffer = dev->transfer_buffer[i];
+		urb->complete = em28xx_isocIrq;
+		urb->number_of_packets = EM28XX_NUM_PACKETS;
+		urb->transfer_buffer_length = sb_size;
+		for (j = k = 0; j < EM28XX_NUM_PACKETS;
+				j++, k += dev->max_pkt_size) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length =
+				dev->max_pkt_size;
+		}
+		dev->urb[i] = urb;
+	}
+
+	/* submit urbs */
+	for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+		errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
+		if (errCode) {
+			em28xx_errdev("submit of urb %i failed (error=%i)\n", i,
+				      errCode);
+			em28xx_uninit_isoc(dev);
+			return errCode;
+		}
+	}
+
+	return 0;
+}
+
+int em28xx_set_alternate(struct em28xx *dev)
+{
+	int errCode, prev_alt = dev->alt;
+	dev->alt = alt;
+	if (dev->alt == 0) {
+		int i;
+		for(i=0;i< dev->num_alt; i++)
+			if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
+				dev->alt=i;
+	}
+
+	if (dev->alt != prev_alt) {
+		dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+		em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt,
+		       dev->max_pkt_size);
+		errCode = usb_set_interface(dev->udev, 0, dev->alt);
+		if (errCode < 0) {
+			em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
+							dev->alt, errCode);
+			return errCode;
+		}
+	}
+	return 0;
+}
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
new file mode 100644
index 0000000..b32d985
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -0,0 +1,586 @@
+/*
+   em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Sascha Sommer <saschasommer@freenet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#include "em28xx.h"
+#include <media/tuner.h>
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\
+			printk(fmt , ##args); } while (0)
+#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
+			printk(KERN_DEBUG "%s at %s: " fmt, \
+			dev->name, __FUNCTION__ , ##args); } while (0)
+
+/*
+ * em2800_i2c_send_max4()
+ * send up to 4 bytes to the i2c device
+ */
+static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
+				char *buf, int len)
+{
+	int ret;
+	int write_timeout;
+	unsigned char b2[6];
+	BUG_ON(len < 1 || len > 4);
+	b2[5] = 0x80 + len - 1;
+	b2[4] = addr;
+	b2[3] = buf[0];
+	if (len > 1)
+		b2[2] = buf[1];
+	if (len > 2)
+		b2[1] = buf[2];
+	if (len > 3)
+		b2[0] = buf[3];
+
+	ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
+	if (ret != 2 + len) {
+		em28xx_warn("writting to i2c device failed (error=%i)\n", ret);
+		return -EIO;
+	}
+	for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+	     write_timeout -= 5) {
+		ret = dev->em28xx_read_reg(dev, 0x05);
+		if (ret == 0x80 + len - 1)
+			return len;
+		mdelay(5);
+	}
+	em28xx_warn("i2c write timed out\n");
+	return -EIO;
+}
+
+/*
+ * em2800_i2c_send_bytes()
+ */
+static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+				 short len)
+{
+	char *bufPtr = buf;
+	int ret;
+	int wrcount = 0;
+	int count;
+	int maxLen = 4;
+	struct em28xx *dev = (struct em28xx *)data;
+	while (len > 0) {
+		count = (len > maxLen) ? maxLen : len;
+		ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
+		if (ret > 0) {
+			len -= count;
+			bufPtr += count;
+			wrcount += count;
+		} else
+			return (ret < 0) ? ret : -EFAULT;
+	}
+	return wrcount;
+}
+
+/*
+ * em2800_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+	char msg;
+	int ret;
+	int write_timeout;
+	msg = addr;
+	ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
+	if (ret < 0) {
+		em28xx_warn("setting i2c device address failed (error=%i)\n",
+			    ret);
+		return ret;
+	}
+	msg = 0x84;
+	ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
+	if (ret < 0) {
+		em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
+		return ret;
+	}
+	for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+	     write_timeout -= 5) {
+		unsigned msg = dev->em28xx_read_reg(dev, 0x5);
+		if (msg == 0x94)
+			return -ENODEV;
+		else if (msg == 0x84)
+			return 0;
+		mdelay(5);
+	}
+	return -ENODEV;
+}
+
+/*
+ * em2800_i2c_recv_bytes()
+ * read from the i2c device
+ */
+static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+				 char *buf, int len)
+{
+	int ret;
+	/* check for the device and set i2c read address */
+	ret = em2800_i2c_check_for_device(dev, addr);
+	if (ret) {
+		em28xx_warn
+		    ("preparing read at i2c address 0x%x failed (error=%i)\n",
+		     addr, ret);
+		return ret;
+	}
+	ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
+	if (ret < 0) {
+		em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
+			    addr, ret);
+		return ret;
+	}
+	return ret;
+}
+
+/*
+ * em28xx_i2c_send_bytes()
+ * untested for more than 4 bytes
+ */
+static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+				 short len, int stop)
+{
+	int wrcount = 0;
+	struct em28xx *dev = (struct em28xx *)data;
+
+	wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
+
+	return wrcount;
+}
+
+/*
+ * em28xx_i2c_recv_bytes()
+ * read a byte from the i2c device
+ */
+static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+				 char *buf, int len)
+{
+	int ret;
+	ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
+	if (ret < 0) {
+		em28xx_warn("reading i2c device failed (error=%i)\n", ret);
+		return ret;
+	}
+	if (dev->em28xx_read_reg(dev, 0x5) != 0)
+		return -ENODEV;
+	return ret;
+}
+
+/*
+ * em28xx_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+	char msg;
+	int ret;
+	msg = addr;
+
+	ret = dev->em28xx_read_reg_req(dev, 2, addr);
+	if (ret < 0) {
+		em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
+		return ret;
+	}
+	if (dev->em28xx_read_reg(dev, 0x5) != 0)
+		return -ENODEV;
+	return 0;
+}
+
+/*
+ * em28xx_i2c_xfer()
+ * the main i2c transfer function
+ */
+static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
+			   struct i2c_msg msgs[], int num)
+{
+	struct em28xx *dev = i2c_adap->algo_data;
+	int addr, rc, i, byte;
+
+	if (num <= 0)
+		return 0;
+	for (i = 0; i < num; i++) {
+		addr = msgs[i].addr << 1;
+		dprintk2(2,"%s %s addr=%x len=%d:",
+			 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+			 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+		if (!msgs[i].len) {	/* no len: check only for device presence */
+			if (dev->is_em2800)
+				rc = em2800_i2c_check_for_device(dev, addr);
+			else
+				rc = em28xx_i2c_check_for_device(dev, addr);
+			if (rc < 0) {
+				dprintk2(2," no device\n");
+				return rc;
+			}
+
+		} else if (msgs[i].flags & I2C_M_RD) {
+			/* read bytes */
+			if (dev->is_em2800)
+				rc = em2800_i2c_recv_bytes(dev, addr,
+							   msgs[i].buf,
+							   msgs[i].len);
+			else
+				rc = em28xx_i2c_recv_bytes(dev, addr,
+							   msgs[i].buf,
+							   msgs[i].len);
+			if (i2c_debug>=2) {
+				for (byte = 0; byte < msgs[i].len; byte++) {
+					printk(" %02x", msgs[i].buf[byte]);
+				}
+			}
+		} else {
+			/* write bytes */
+			if (i2c_debug>=2) {
+				for (byte = 0; byte < msgs[i].len; byte++)
+					printk(" %02x", msgs[i].buf[byte]);
+			}
+			if (dev->is_em2800)
+				rc = em2800_i2c_send_bytes(dev, addr,
+							   msgs[i].buf,
+							   msgs[i].len);
+			else
+				rc = em28xx_i2c_send_bytes(dev, addr,
+							   msgs[i].buf,
+							   msgs[i].len,
+							   i == num - 1);
+			if (rc < 0)
+				goto err;
+		}
+		if (i2c_debug>=2)
+			printk("\n");
+	}
+
+	return num;
+      err:
+	dprintk2(2," ERROR: %i\n", rc);
+	return rc;
+}
+
+static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+{
+	unsigned char buf, *p = eedata;
+	struct em28xx_eeprom *em_eeprom = (void *)eedata;
+	int i, err, size = len, block;
+
+	dev->i2c_client.addr = 0xa0 >> 1;
+
+	/* Check if board has eeprom */
+	err = i2c_master_recv(&dev->i2c_client, &buf, 0);
+	if (err < 0)
+		return -1;
+
+	buf = 0;
+	if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
+		printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+		       dev->name, err);
+		return -1;
+	}
+	while (size > 0) {
+		if (size > 16)
+			block = 16;
+		else
+			block = size;
+
+		if (block !=
+		    (err = i2c_master_recv(&dev->i2c_client, p, block))) {
+			printk(KERN_WARNING
+			       "%s: i2c eeprom read error (err=%d)\n",
+			       dev->name, err);
+			return -1;
+		}
+		size -= block;
+		p += block;
+	}
+	for (i = 0; i < len; i++) {
+		if (0 == (i % 16))
+			printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
+		printk(" %02x", eedata[i]);
+		if (15 == (i % 16))
+			printk("\n");
+	}
+
+	printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id);
+	printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
+	       em_eeprom->product_ID);
+
+	switch (em_eeprom->chip_conf >> 4 & 0x3) {
+	case 0:
+		printk(KERN_INFO "No audio on board.\n");
+		break;
+	case 1:
+		printk(KERN_INFO "AC97 audio (5 sample rates)\n");
+		break;
+	case 2:
+		printk(KERN_INFO "I2S audio, sample rate=32k\n");
+		break;
+	case 3:
+		printk(KERN_INFO "I2S audio, 3 sample rates\n");
+		break;
+	}
+
+	if (em_eeprom->chip_conf & 1 << 3)
+		printk(KERN_INFO "USB Remote wakeup capable\n");
+
+	if (em_eeprom->chip_conf & 1 << 2)
+		printk(KERN_INFO "USB Self power capable\n");
+
+	switch (em_eeprom->chip_conf & 0x3) {
+	case 0:
+		printk(KERN_INFO "500mA max power\n");
+		break;
+	case 1:
+		printk(KERN_INFO "400mA max power\n");
+		break;
+	case 2:
+		printk(KERN_INFO "300mA max power\n");
+		break;
+	case 3:
+		printk(KERN_INFO "200mA max power\n");
+		break;
+	}
+	printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+				em_eeprom->string_idx_table,em_eeprom->string1,
+				em_eeprom->string2,em_eeprom->string3);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * algo_control()
+ */
+static int algo_control(struct i2c_adapter *adapter,
+			unsigned int cmd, unsigned long arg)
+{
+	return 0;
+}
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+#ifndef I2C_PEC
+static void inc_use(struct i2c_adapter *adap)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use(struct i2c_adapter *adap)
+{
+	MOD_DEC_USE_COUNT;
+}
+#endif
+
+static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
+{
+	struct em28xx *dev = client->adapter->algo_data;
+	struct tuner_setup tun_setup;
+
+	if (dev->has_tuner) {
+		tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+		tun_setup.type = dev->tuner_type;
+		tun_setup.addr = dev->tuner_addr;
+
+		em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+	}
+
+	return (0);
+}
+
+/*
+ * attach_inform()
+ * gets called when a device attaches to the i2c bus
+ * does some basic configuration
+ */
+static int attach_inform(struct i2c_client *client)
+{
+	struct em28xx *dev = client->adapter->algo_data;
+
+	switch (client->addr << 1) {
+		case 0x86:
+			em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
+			break;
+		case 0x42:
+			dprintk1(1,"attach_inform: saa7114 detected.\n");
+			break;
+		case 0x4a:
+			dprintk1(1,"attach_inform: saa7113 detected.\n");
+			break;
+		case 0xa0:
+			dprintk1(1,"attach_inform: eeprom detected.\n");
+			break;
+		case 0x60:
+		case 0x8e:
+		{
+			struct IR_i2c *ir = i2c_get_clientdata(client);
+			dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
+			em28xx_set_ir(dev,ir);
+			break;
+		}
+		case 0x80:
+		case 0x88:
+			dprintk1(1,"attach_inform: msp34xx detected.\n");
+			break;
+		case 0xb8:
+		case 0xba:
+			dprintk1(1,"attach_inform: tvp5150 detected.\n");
+			break;
+		default:
+			dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+			dev->tuner_addr = client->addr;
+			em28xx_set_tuner(-1, client);
+	}
+
+	return 0;
+}
+
+static struct i2c_algorithm em28xx_algo = {
+	.master_xfer   = em28xx_i2c_xfer,
+	.algo_control  = algo_control,
+	.functionality = functionality,
+};
+
+static struct i2c_adapter em28xx_adap_template = {
+#ifdef I2C_PEC
+	.owner = THIS_MODULE,
+#else
+	.inc_use = inc_use,
+	.dec_use = dec_use,
+#endif
+#ifdef I2C_CLASS_TV_ANALOG
+	.class = I2C_CLASS_TV_ANALOG,
+#endif
+	.name = "em28xx",
+	.id = I2C_HW_B_EM28XX,
+	.algo = &em28xx_algo,
+	.client_register = attach_inform,
+};
+
+static struct i2c_client em28xx_client_template = {
+	.name = "em28xx internal",
+	.flags = I2C_CLIENT_ALLOW_USE,
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * i2c_devs
+ * incomplete list of known devices
+ */
+static char *i2c_devs[128] = {
+	[0x4a >> 1] = "saa7113h",
+	[0x60 >> 1] = "remote IR sensor",
+	[0x8e >> 1] = "remote IR sensor",
+	[0x86 >> 1] = "tda9887",
+	[0x80 >> 1] = "msp34xx",
+	[0x88 >> 1] = "msp34xx",
+	[0xa0 >> 1] = "eeprom",
+	[0xb8 >> 1] = "tvp5150a",
+	[0xba >> 1] = "tvp5150a",
+	[0xc0 >> 1] = "tuner (analog)",
+	[0xc2 >> 1] = "tuner (analog)",
+	[0xc4 >> 1] = "tuner (analog)",
+	[0xc6 >> 1] = "tuner (analog)",
+};
+
+/*
+ * do_i2c_scan()
+ * check i2c address range for devices
+ */
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i, rc;
+
+	for (i = 0; i < 128; i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c, &buf, 0);
+		if (rc < 0)
+			continue;
+		printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
+		       i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+/*
+ * em28xx_i2c_call_clients()
+ * send commands to all attached i2c devices
+ */
+void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg)
+{
+	BUG_ON(NULL == dev->i2c_adap.algo_data);
+	i2c_clients_command(&dev->i2c_adap, cmd, arg);
+}
+
+/*
+ * em28xx_i2c_register()
+ * register i2c bus
+ */
+int em28xx_i2c_register(struct em28xx *dev)
+{
+	BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
+	BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
+	dev->i2c_adap = em28xx_adap_template;
+	dev->i2c_adap.dev.parent = &dev->udev->dev;
+	strcpy(dev->i2c_adap.name, dev->name);
+	dev->i2c_adap.algo_data = dev;
+	i2c_add_adapter(&dev->i2c_adap);
+
+	dev->i2c_client = em28xx_client_template;
+	dev->i2c_client.adapter = &dev->i2c_adap;
+
+	em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+
+	if (i2c_scan)
+		do_i2c_scan(dev->name, &dev->i2c_client);
+	return 0;
+}
+
+/*
+ * em28xx_i2c_unregister()
+ * unregister i2c_bus
+ */
+int em28xx_i2c_unregister(struct em28xx *dev)
+{
+	i2c_del_adapter(&dev->i2c_adap);
+	return 0;
+}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
new file mode 100644
index 0000000..32c49df
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -0,0 +1,184 @@
+/*
+  handle em28xx IR remotes via linux kernel input layer.
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Sascha Sommer <saschasommer@freenet.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "em28xx.h"
+
+static unsigned int disable_ir = 0;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+
+static unsigned int ir_debug = 0;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+
+#define dprintk(fmt, arg...)	if (ir_debug) \
+	printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+
+/* ---------------------------------------------------------------------- */
+
+static IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
+	[ 0x01 ] = KEY_CHANNEL,
+	[ 0x02 ] = KEY_SELECT,
+	[ 0x03 ] = KEY_MUTE,
+	[ 0x04 ] = KEY_POWER,
+	[ 0x05 ] = KEY_KP1,
+	[ 0x06 ] = KEY_KP2,
+	[ 0x07 ] = KEY_KP3,
+	[ 0x08 ] = KEY_CHANNELUP,
+	[ 0x09 ] = KEY_KP4,
+	[ 0x0a ] = KEY_KP5,
+	[ 0x0b ] = KEY_KP6,
+	[ 0x0c ] = KEY_CHANNELDOWN,
+	[ 0x0d ] = KEY_KP7,
+	[ 0x0e ] = KEY_KP8,
+	[ 0x0f ] = KEY_KP9,
+	[ 0x10 ] = KEY_VOLUMEUP,
+	[ 0x11 ] = KEY_KP0,
+	[ 0x12 ] = KEY_MENU,
+	[ 0x13 ] = KEY_PRINT,
+	[ 0x14 ] = KEY_VOLUMEDOWN,
+	[ 0x16 ] = KEY_PAUSE,
+	[ 0x18 ] = KEY_RECORD,
+	[ 0x19 ] = KEY_REWIND,
+	[ 0x1a ] = KEY_PLAY,
+	[ 0x1b ] = KEY_FORWARD,
+	[ 0x1c ] = KEY_BACKSPACE,
+	[ 0x1e ] = KEY_STOP,
+	[ 0x40 ] = KEY_ZOOM,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char b;
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(&ir->c,&b,1)) {
+		dprintk("read error\n");
+		return -EIO;
+	}
+
+	/* it seems that 0xFE indicates that a button is still hold
+	   down, while 0xff indicates that no button is hold
+	   down. 0xfe sequences are sometimes interrupted by 0xFF */
+
+	dprintk("key %02x\n", b);
+
+	if (b == 0xff)
+		return 0;
+
+	if (b == 0xfe)
+		/* keep old data */
+		return 1;
+
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+
+static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char buf[2];
+	unsigned char code;
+
+	/* poll IR chip */
+	if (2 != i2c_master_recv(&ir->c,buf,2))
+		return -EIO;
+
+	/* Does eliminate repeated parity code */
+	if (buf[1]==0xff)
+		return 0;
+
+	/* avoid fast reapeating */
+	if (buf[1]==ir->old)
+		return 0;
+	ir->old=buf[1];
+
+	/* Rearranges bits to the right order */
+	code=    ((buf[0]&0x01)<<5) | /* 0010 0000 */
+		 ((buf[0]&0x02)<<3) | /* 0001 0000 */
+		 ((buf[0]&0x04)<<1) | /* 0000 1000 */
+		 ((buf[0]&0x08)>>1) | /* 0000 0100 */
+		 ((buf[0]&0x10)>>3) | /* 0000 0010 */
+		 ((buf[0]&0x20)>>5);  /* 0000 0001 */
+
+	dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",code,buf[0]);
+
+	/* return key */
+	*ir_key = code;
+	*ir_raw = code;
+	return 1;
+}
+
+/* ----------------------------------------------------------------------- */
+void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
+{
+	if (disable_ir) {
+		ir->get_key=NULL;
+		return ;
+	}
+
+	/* detect & configure */
+	switch (dev->model) {
+	case (EM2800_BOARD_UNKNOWN):
+		break;
+	case (EM2820_BOARD_UNKNOWN):
+		break;
+	case (EM2800_BOARD_TERRATEC_CINERGY_200):
+	case (EM2820_BOARD_TERRATEC_CINERGY_250):
+		ir->ir_codes = ir_codes_em_terratec;
+		ir->get_key = get_key_terratec;
+		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
+		break;
+	case (EM2820_BOARD_PINNACLE_USB_2):
+		break;
+	case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+		ir->ir_codes = ir_codes_hauppauge_new;
+		ir->get_key = get_key_em_haup;
+		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)");
+		break;
+	case (EM2820_BOARD_MSI_VOX_USB_2):
+		break;
+	case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
+		break;
+	case (EM2800_BOARD_KWORLD_USB2800):
+		break;
+	}
+}
+
+/* ----------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
new file mode 100644
index 0000000..57c1826b92
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -0,0 +1,1933 @@
+/*
+   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+		      Markus Rechberger <mrechberger@gmail.com>
+		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Sascha Sommer <saschasommer@freenet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <linux/video_decoder.h>
+
+#include "em28xx.h"
+#include <media/tuner.h>
+
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+		      "Markus Rechberger <mrechberger@gmail.com>, " \
+		      "Mauro Carvalho Chehab <mchehab@brturbo.com.br>, " \
+		      "Sascha Sommer <saschasommer@freenet.de>"
+
+#define DRIVER_NAME         "em28xx"
+#define DRIVER_DESC         "Empia em28xx based USB video device driver"
+#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 0, 1)
+
+#define em28xx_videodbg(fmt, arg...) do {\
+	if (video_debug) \
+		printk(KERN_INFO "%s %s :"fmt, \
+			 dev->name, __FUNCTION__ , ##arg); } while (0)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static LIST_HEAD(em28xx_devlist);
+
+static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card,"card type");
+
+static int tuner = -1;
+module_param(tuner, int, 0444);
+MODULE_PARM_DESC(tuner, "tuner type");
+
+static unsigned int video_debug = 0;
+module_param(video_debug,int,0644);
+MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+
+/* supported tv norms */
+static struct em28xx_tvnorm tvnorms[] = {
+	{
+		.name = "PAL",
+		.id = V4L2_STD_PAL,
+		.mode = VIDEO_MODE_PAL,
+	 }, {
+		.name = "NTSC",
+		.id = V4L2_STD_NTSC,
+		.mode = VIDEO_MODE_NTSC,
+	}, {
+		 .name = "SECAM",
+		 .id = V4L2_STD_SECAM,
+		 .mode = VIDEO_MODE_SECAM,
+	}, {
+		.name = "PAL-M",
+		.id = V4L2_STD_PAL_M,
+		.mode = VIDEO_MODE_PAL,
+	}
+};
+
+static const unsigned char saa7114_i2c_init[] = {
+	0x00,0x00,0x01,0x08,0x02,0xc4,0x03,0x30,0x04,0x90,0x05,0x90,0x06,0xeb,0x07,0xe0,
+	0x08,0x88,0x09,0x40,0x0a,0x80,0x0b,0x44,0x0c,0x40,0x0d,0x00,0x0e,0x81,0x0f,0x2a,
+	0x10,0x06,0x11,0x00,0x12,0xc8,0x13,0x80,0x14,0x00,0x15,0x11,0x16,0x01,0x17,0x42,
+	0x18,0x40,0x19,0x80,0x40,0x00,0x41,0xff,0x42,0xff,0x43,0xff,0x44,0xff,0x45,0xff,
+	0x46,0xff,0x47,0xff,0x48,0xff,0x49,0xff,0x4a,0xff,0x4b,0xff,0x4c,0xff,0x4d,0xff,
+	0x4e,0xff,0x4f,0xff,0x50,0xff,0x51,0xff,0x52,0xff,0x53,0xff,0x54,0x5f,0x55,0xff,
+	0x56,0xff,0x57,0xff,0x58,0x00,0x59,0x47,0x5a,0x03,0x5b,0x03,0x5d,0x3e,0x5e,0x00,
+	0x80,0x1c,0x83,0x01,0x84,0xa5,0x85,0x10,0x86,0x45,0x87,0x41,0x88,0xf0,0x88,0x00,
+	0x88,0xf0,0x90,0x00,0x91,0x08,0x92,0x00,0x93,0x80,0x94,0x08,0x95,0x00,0x96,0xc0,
+	0x97,0x02,0x98,0x13,0x99,0x00,0x9a,0x38,0x9b,0x01,0x9c,0x80,0x9d,0x02,0x9e,0x06,
+	0x9f,0x01,0xa0,0x01,0xa1,0x00,0xa2,0x00,0xa4,0x80,0xa5,0x36,0xa6,0x36,0xa8,0x67,
+	0xa9,0x04,0xaa,0x00,0xac,0x33,0xad,0x02,0xae,0x00,0xb0,0xcd,0xb1,0x04,0xb2,0xcd,
+	0xb3,0x04,0xb4,0x01,0xb8,0x00,0xb9,0x00,0xba,0x00,0xbb,0x00,0xbc,0x00,0xbd,0x00,
+	0xbe,0x00,0xbf,0x00
+};
+
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+/* supported controls */
+static struct v4l2_queryctrl em28xx_qctrl[] = {
+	{
+		.id = V4L2_CID_BRIGHTNESS,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Brightness",
+		.minimum = -128,
+		.maximum = 127,
+		.step = 1,
+		.default_value = 0,
+		.flags = 0,
+	},{
+		.id = V4L2_CID_CONTRAST,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Contrast",
+		.minimum = 0x0,
+		.maximum = 0x1f,
+		.step = 0x1,
+		.default_value = 0x10,
+		.flags = 0,
+	},{
+		.id = V4L2_CID_SATURATION,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Saturation",
+		.minimum = 0x0,
+		.maximum = 0x1f,
+		.step = 0x1,
+		.default_value = 0x10,
+		.flags = 0,
+	},{
+		.id = V4L2_CID_AUDIO_VOLUME,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Volume",
+		.minimum = 0x0,
+		.maximum = 0x1f,
+		.step = 0x1,
+		.default_value = 0x1f,
+		.flags = 0,
+	},{
+		.id = V4L2_CID_AUDIO_MUTE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Mute",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 1,
+		.flags = 0,
+	},{
+		.id = V4L2_CID_RED_BALANCE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Red chroma balance",
+		.minimum = -128,
+		.maximum = 127,
+		.step = 1,
+		.default_value = 0,
+		.flags = 0,
+	},{
+		.id = V4L2_CID_BLUE_BALANCE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Blue chroma balance",
+		.minimum = -128,
+		.maximum = 127,
+		.step = 1,
+		.default_value = 0,
+		.flags = 0,
+	},{
+		.id = V4L2_CID_GAMMA,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Gamma",
+		.minimum = 0x0,
+		.maximum = 0x3f,
+		.step = 0x1,
+		.default_value = 0x20,
+		.flags = 0,
+	 }
+};
+
+static struct usb_driver em28xx_usb_driver;
+
+static DECLARE_MUTEX(em28xx_sysfs_lock);
+static DECLARE_RWSEM(em28xx_disconnect);
+
+/*********************  v4l2 interface  ******************************************/
+
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long kva, ret;
+
+	kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE - 1);
+	ret = __pa(kva);
+	return ret;
+}
+
+/*
+ * em28xx_config()
+ * inits registers with sane defaults
+ */
+static int em28xx_config(struct em28xx *dev)
+{
+
+	/* Sets I2C speed to 100 KHz */
+	em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
+
+	/* enable vbi capturing */
+	em28xx_audio_usb_mute(dev, 1);
+	dev->mute = 1;		/* maybe not the right place... */
+	dev->volume = 0x1f;
+	em28xx_audio_analog_set(dev);
+	em28xx_audio_analog_setup(dev);
+	em28xx_outfmt_set_yuv422(dev);
+	em28xx_colorlevels_set_default(dev);
+	em28xx_compression_disable(dev);
+
+	return 0;
+}
+
+/*
+ * em28xx_config_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_config_i2c(struct em28xx *dev)
+{
+	struct v4l2_frequency f;
+	struct video_decoder_init em28xx_vdi = {.data = NULL };
+
+
+	/* configure decoder */
+	if(dev->model == EM2820_BOARD_MSI_VOX_USB_2){
+		em28xx_vdi.data=saa7114_i2c_init;
+		em28xx_vdi.len=sizeof(saa7114_i2c_init);
+	}
+
+
+	em28xx_i2c_call_clients(dev, DECODER_INIT, &em28xx_vdi);
+	em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &dev->ctl_input);
+/*	em28xx_i2c_call_clients(dev,DECODER_SET_PICTURE, &dev->vpic); */
+/*	em28xx_i2c_call_clients(dev,DECODER_SET_NORM,&dev->tvnorm->id); */
+/*	em28xx_i2c_call_clients(dev,DECODER_ENABLE_OUTPUT,&output); */
+/*	em28xx_i2c_call_clients(dev,DECODER_DUMP, NULL); */
+
+	/* configure tuner */
+	f.tuner = 0;
+	f.type = V4L2_TUNER_ANALOG_TV;
+	f.frequency = 9076;	/* FIXME:remove magic number */
+	dev->ctl_freq = f.frequency;
+	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+
+	/* configure tda9887 */
+
+
+/*	em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */
+}
+
+/*
+ * em28xx_empty_framequeues()
+ * prepare queues for incoming and outgoing frames
+ */
+static void em28xx_empty_framequeues(struct em28xx *dev)
+{
+	u32 i;
+
+	INIT_LIST_HEAD(&dev->inqueue);
+	INIT_LIST_HEAD(&dev->outqueue);
+
+	for (i = 0; i < EM28XX_NUM_FRAMES; i++) {
+		dev->frame[i].state = F_UNUSED;
+		dev->frame[i].buf.bytesused = 0;
+	}
+}
+
+static void video_mux(struct em28xx *dev, int index)
+{
+	int input, ainput;
+
+	input = INPUT(index)->vmux;
+	dev->ctl_input = index;
+	dev->ctl_ainput = INPUT(index)->amux;
+
+	em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input);
+
+
+	em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
+
+	if (dev->has_msp34xx) {
+		em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
+		ainput = EM28XX_AUDIO_SRC_TUNER;
+		em28xx_audio_source(dev, ainput);
+	} else {
+		switch (dev->ctl_ainput) {
+		case 0:
+			ainput = EM28XX_AUDIO_SRC_TUNER;
+			break;
+		default:
+			ainput = EM28XX_AUDIO_SRC_LINE;
+		}
+		em28xx_audio_source(dev, ainput);
+	}
+}
+
+/*
+ * em28xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+{
+	int minor = iminor(inode);
+	int errCode = 0;
+	struct em28xx *h,*dev = NULL;
+	struct list_head *list;
+
+	list_for_each(list,&em28xx_devlist) {
+		h = list_entry(list, struct em28xx, devlist);
+		if (h->vdev->minor == minor) {
+			dev  = h;
+		}
+	}
+
+	filp->private_data=dev;
+
+
+	em28xx_videodbg("users=%d\n", dev->users);
+
+	if (!down_read_trylock(&em28xx_disconnect))
+		return -ERESTARTSYS;
+
+	if (dev->users) {
+		em28xx_warn("this driver can be opened only once\n");
+		up_read(&em28xx_disconnect);
+		return -EBUSY;
+	}
+
+/*	if(dev->vbi_dev->minor == minor){
+		dev->type=V4L2_BUF_TYPE_VBI_CAPTURE;
+	}*/
+	if (dev->vdev->minor == minor) {
+		dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	}
+
+	init_MUTEX(&dev->fileop_lock);	/* to 1 == available */
+	spin_lock_init(&dev->queue_lock);
+	init_waitqueue_head(&dev->wait_frame);
+	init_waitqueue_head(&dev->wait_stream);
+
+	down(&dev->lock);
+
+	em28xx_set_alternate(dev);
+
+	dev->width = norm_maxw(dev);
+	dev->height = norm_maxh(dev);
+	dev->frame_size = dev->width * dev->height * 2;
+	dev->field_size = dev->frame_size >> 1;	/*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+	dev->bytesperline = dev->width * 2;
+	dev->hscale = 0;
+	dev->vscale = 0;
+
+	em28xx_capture_start(dev, 1);
+	em28xx_resolution_set(dev);
+
+	/* start the transfer */
+	errCode = em28xx_init_isoc(dev);
+	if (errCode)
+		goto err;
+
+	dev->users++;
+	filp->private_data = dev;
+	dev->io = IO_NONE;
+	dev->stream = STREAM_OFF;
+	dev->num_frames = 0;
+
+	/* prepare queues */
+	em28xx_empty_framequeues(dev);
+
+	dev->state |= DEV_INITIALIZED;
+
+	video_mux(dev, 0);
+
+      err:
+	up(&dev->lock);
+	up_read(&em28xx_disconnect);
+	return errCode;
+}
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+static void em28xx_release_resources(struct em28xx *dev)
+{
+	down(&em28xx_sysfs_lock);
+
+	em28xx_info("V4L2 device /dev/video%d deregistered\n",
+		    dev->vdev->minor);
+	list_del(&dev->devlist);
+	video_unregister_device(dev->vdev);
+/*	video_unregister_device(dev->vbi_dev); */
+	em28xx_i2c_unregister(dev);
+	usb_put_dev(dev->udev);
+	up(&em28xx_sysfs_lock);
+}
+
+/*
+ * em28xx_v4l2_close()
+ * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ */
+static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
+{
+	int errCode;
+	struct em28xx *dev=filp->private_data;
+
+	em28xx_videodbg("users=%d\n", dev->users);
+
+	down(&dev->lock);
+
+	em28xx_uninit_isoc(dev);
+
+	em28xx_release_buffers(dev);
+
+	/* the device is already disconnect, free the remaining resources */
+	if (dev->state & DEV_DISCONNECTED) {
+		em28xx_release_resources(dev);
+		up(&dev->lock);
+		kfree(dev);
+		return 0;
+	}
+
+	/* set alternate 0 */
+	dev->alt = 0;
+	em28xx_videodbg("setting alternate 0\n");
+	errCode = usb_set_interface(dev->udev, 0, 0);
+	if (errCode < 0) {
+		em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n",
+		     errCode);
+	}
+
+	dev->users--;
+	wake_up_interruptible_nr(&dev->open, 1);
+	up(&dev->lock);
+	return 0;
+}
+
+/*
+ * em28xx_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t
+em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
+		 loff_t * f_pos)
+{
+	struct em28xx_frame_t *f, *i;
+	unsigned long lock_flags;
+	int ret = 0;
+	struct em28xx *dev = filp->private_data;
+
+	if (down_interruptible(&dev->fileop_lock))
+		return -ERESTARTSYS;
+
+	if (dev->state & DEV_DISCONNECTED) {
+		em28xx_videodbg("device not present\n");
+		up(&dev->fileop_lock);
+		return -ENODEV;
+	}
+
+	if (dev->state & DEV_MISCONFIGURED) {
+		em28xx_videodbg("device misconfigured; close and open it again\n");
+		up(&dev->fileop_lock);
+		return -EIO;
+	}
+
+	if (dev->io == IO_MMAP) {
+		em28xx_videodbg ("IO method is set to mmap; close and open"
+				" the device again to choose the read method\n");
+		up(&dev->fileop_lock);
+		return -EINVAL;
+	}
+
+	if (dev->io == IO_NONE) {
+		if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
+			em28xx_errdev("read failed, not enough memory\n");
+			up(&dev->fileop_lock);
+			return -ENOMEM;
+		}
+		dev->io = IO_READ;
+		dev->stream = STREAM_ON;
+		em28xx_queue_unusedframes(dev);
+	}
+
+	if (!count) {
+		up(&dev->fileop_lock);
+		return 0;
+	}
+
+	if (list_empty(&dev->outqueue)) {
+		if (filp->f_flags & O_NONBLOCK) {
+			up(&dev->fileop_lock);
+			return -EAGAIN;
+		}
+		ret = wait_event_interruptible
+		    (dev->wait_frame,
+		     (!list_empty(&dev->outqueue)) ||
+		     (dev->state & DEV_DISCONNECTED));
+		if (ret) {
+			up(&dev->fileop_lock);
+			return ret;
+		}
+		if (dev->state & DEV_DISCONNECTED) {
+			up(&dev->fileop_lock);
+			return -ENODEV;
+		}
+	}
+
+	f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
+
+	spin_lock_irqsave(&dev->queue_lock, lock_flags);
+	list_for_each_entry(i, &dev->outqueue, frame)
+	    i->state = F_UNUSED;
+	INIT_LIST_HEAD(&dev->outqueue);
+	spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+	em28xx_queue_unusedframes(dev);
+
+	if (count > f->buf.length)
+		count = f->buf.length;
+
+	if (copy_to_user(buf, f->bufmem, count)) {
+		up(&dev->fileop_lock);
+		return -EFAULT;
+	}
+	*f_pos += count;
+
+	up(&dev->fileop_lock);
+
+	return count;
+}
+
+/*
+ * em28xx_v4l2_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+{
+	unsigned int mask = 0;
+	struct em28xx *dev = filp->private_data;
+
+	if (down_interruptible(&dev->fileop_lock))
+		return POLLERR;
+
+	if (dev->state & DEV_DISCONNECTED) {
+		em28xx_videodbg("device not present\n");
+	} else if (dev->state & DEV_MISCONFIGURED) {
+		em28xx_videodbg("device is misconfigured; close and open it again\n");
+	} else {
+		if (dev->io == IO_NONE) {
+			if (!em28xx_request_buffers
+			    (dev, EM28XX_NUM_READ_FRAMES)) {
+				em28xx_warn
+				    ("poll() failed, not enough memory\n");
+			} else {
+				dev->io = IO_READ;
+				dev->stream = STREAM_ON;
+			}
+		}
+
+		if (dev->io == IO_READ) {
+			em28xx_queue_unusedframes(dev);
+			poll_wait(filp, &dev->wait_frame, wait);
+
+			if (!list_empty(&dev->outqueue))
+				mask |= POLLIN | POLLRDNORM;
+
+			up(&dev->fileop_lock);
+
+			return mask;
+		}
+	}
+
+	up(&dev->fileop_lock);
+	return POLLERR;
+}
+
+/*
+ * em28xx_vm_open()
+ */
+static void em28xx_vm_open(struct vm_area_struct *vma)
+{
+	struct em28xx_frame_t *f = vma->vm_private_data;
+	f->vma_use_count++;
+}
+
+/*
+ * em28xx_vm_close()
+ */
+static void em28xx_vm_close(struct vm_area_struct *vma)
+{
+	/* NOTE: buffers are not freed here */
+	struct em28xx_frame_t *f = vma->vm_private_data;
+	f->vma_use_count--;
+}
+
+static struct vm_operations_struct em28xx_vm_ops = {
+	.open = em28xx_vm_open,
+	.close = em28xx_vm_close,
+};
+
+/*
+ * em28xx_v4l2_mmap()
+ */
+static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	unsigned long size = vma->vm_end - vma->vm_start,
+	    start = vma->vm_start, pos, page;
+	u32 i;
+
+	struct em28xx *dev = filp->private_data;
+
+	if (down_interruptible(&dev->fileop_lock))
+		return -ERESTARTSYS;
+
+	if (dev->state & DEV_DISCONNECTED) {
+		em28xx_videodbg("mmap: device not present\n");
+		up(&dev->fileop_lock);
+		return -ENODEV;
+	}
+
+	if (dev->state & DEV_MISCONFIGURED) {
+		em28xx_videodbg ("mmap: Device is misconfigured; close and "
+						"open it again\n");
+		up(&dev->fileop_lock);
+		return -EIO;
+	}
+
+	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+	    size != PAGE_ALIGN(dev->frame[0].buf.length)) {
+		up(&dev->fileop_lock);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < dev->num_frames; i++) {
+		if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+			break;
+	}
+	if (i == dev->num_frames) {
+		em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
+		up(&dev->fileop_lock);
+		return -EINVAL;
+	}
+
+	/* VM_IO is eventually going to replace PageReserved altogether */
+	vma->vm_flags |= VM_IO;
+	vma->vm_flags |= VM_RESERVED;	/* avoid to swap out this VMA */
+
+	pos = (unsigned long)dev->frame[i].bufmem;
+	while (size > 0) {	/* size is page-aligned */
+		page = vmalloc_to_pfn((void *)pos);
+		if (remap_pfn_range(vma, start, page, PAGE_SIZE,
+				    vma->vm_page_prot)) {
+			em28xx_videodbg("mmap: rename page map failed\n");
+			up(&dev->fileop_lock);
+			return -EAGAIN;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	vma->vm_ops = &em28xx_vm_ops;
+	vma->vm_private_data = &dev->frame[i];
+
+	em28xx_vm_open(vma);
+	up(&dev->fileop_lock);
+	return 0;
+}
+
+/*
+ * em28xx_get_ctrl()
+ * return the current saturation, brightness or contrast, mute state
+ */
+static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+	s32 tmp;
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = dev->mute;
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		ctrl->value = dev->volume;
+		return 0;
+	case V4L2_CID_BRIGHTNESS:
+		if ((tmp = em28xx_brightness_get(dev)) < 0)
+			return -EIO;
+		ctrl->value = (s32) ((s8) tmp);	/* FIXME: clenaer way to extend sign? */
+		return 0;
+	case V4L2_CID_CONTRAST:
+		if ((ctrl->value = em28xx_contrast_get(dev)) < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_SATURATION:
+		if ((ctrl->value = em28xx_saturation_get(dev)) < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_RED_BALANCE:
+		if ((tmp = em28xx_v_balance_get(dev)) < 0)
+			return -EIO;
+		ctrl->value = (s32) ((s8) tmp);	/* FIXME: clenaer way to extend sign? */
+		return 0;
+	case V4L2_CID_BLUE_BALANCE:
+		if ((tmp = em28xx_u_balance_get(dev)) < 0)
+			return -EIO;
+		ctrl->value = (s32) ((s8) tmp);	/* FIXME: clenaer way to extend sign? */
+		return 0;
+	case V4L2_CID_GAMMA:
+		if ((ctrl->value = em28xx_gamma_get(dev)) < 0)
+			return -EIO;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ * em28xx_set_ctrl()
+ * mute or set new saturation, brightness or contrast
+ */
+static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		if (ctrl->value != dev->mute) {
+			dev->mute = ctrl->value;
+			em28xx_audio_usb_mute(dev, ctrl->value);
+			return em28xx_audio_analog_set(dev);
+		}
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		dev->volume = ctrl->value;
+		return em28xx_audio_analog_set(dev);
+	case V4L2_CID_BRIGHTNESS:
+		return em28xx_brightness_set(dev, ctrl->value);
+	case V4L2_CID_CONTRAST:
+		return em28xx_contrast_set(dev, ctrl->value);
+	case V4L2_CID_SATURATION:
+		return em28xx_saturation_set(dev, ctrl->value);
+	case V4L2_CID_RED_BALANCE:
+		return em28xx_v_balance_set(dev, ctrl->value);
+	case V4L2_CID_BLUE_BALANCE:
+		return em28xx_u_balance_set(dev, ctrl->value);
+	case V4L2_CID_GAMMA:
+		return em28xx_gamma_set(dev, ctrl->value);
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ * em28xx_stream_interrupt()
+ * stops streaming
+ */
+static int em28xx_stream_interrupt(struct em28xx *dev)
+{
+	int ret = 0;
+
+	/* stop reading from the device */
+
+	dev->stream = STREAM_INTERRUPT;
+	ret = wait_event_timeout(dev->wait_stream,
+				 (dev->stream == STREAM_OFF) ||
+				 (dev->state & DEV_DISCONNECTED),
+				 EM28XX_URB_TIMEOUT);
+	if (dev->state & DEV_DISCONNECTED)
+		return -ENODEV;
+	else if (ret) {
+		dev->state |= DEV_MISCONFIGURED;
+		em28xx_videodbg("device is misconfigured; close and "
+			"open /dev/video%d again\n", dev->vdev->minor);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int em28xx_set_norm(struct em28xx *dev, int width, int height)
+{
+	unsigned int hscale, vscale;
+	unsigned int maxh, maxw;
+
+	maxw = norm_maxw(dev);
+	maxh = norm_maxh(dev);
+
+	/* width must even because of the YUYV format */
+	/* height must be even because of interlacing */
+	height &= 0xfffe;
+	width &= 0xfffe;
+
+	if (height < 32)
+		height = 32;
+	if (height > maxh)
+		height = maxh;
+	if (width < 48)
+		width = 48;
+	if (width > maxw)
+		width = maxw;
+
+	if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
+		hscale = 0x3fff;
+	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+	if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
+		vscale = 0x3fff;
+	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+	/* set new image size */
+	dev->width = width;
+	dev->height = height;
+	dev->frame_size = dev->width * dev->height * 2;
+	dev->field_size = dev->frame_size >> 1;	/*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+	dev->bytesperline = dev->width * 2;
+	dev->hscale = hscale;
+	dev->vscale = vscale;
+
+	em28xx_resolution_set(dev);
+
+	return 0;
+}
+
+/*
+ * em28xx_v4l2_do_ioctl()
+ * This function is _not_ called directly, but from
+ * em28xx_v4l2_ioctl. Userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
+			   struct em28xx *dev, unsigned int cmd, void *arg,
+			   v4l2_kioctl driver_ioctl)
+{
+	int ret;
+
+	switch (cmd) {
+		/* ---------- tv norms ---------- */
+	case VIDIOC_ENUMSTD:
+		{
+			struct v4l2_standard *e = arg;
+			unsigned int i;
+
+			i = e->index;
+			if (i >= TVNORMS)
+				return -EINVAL;
+			ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+						       tvnorms[e->index].name);
+			e->index = i;
+			if (ret < 0)
+				return ret;
+			return 0;
+		}
+	case VIDIOC_G_STD:
+		{
+			v4l2_std_id *id = arg;
+
+			*id = dev->tvnorm->id;
+			return 0;
+		}
+	case VIDIOC_S_STD:
+		{
+			v4l2_std_id *id = arg;
+			unsigned int i;
+
+			for (i = 0; i < TVNORMS; i++)
+				if (*id == tvnorms[i].id)
+					break;
+			if (i == TVNORMS)
+				for (i = 0; i < TVNORMS; i++)
+					if (*id & tvnorms[i].id)
+						break;
+			if (i == TVNORMS)
+				return -EINVAL;
+
+			down(&dev->lock);
+			dev->tvnorm = &tvnorms[i];
+
+			em28xx_set_norm(dev, dev->width, dev->height);
+
+/*
+		dev->width=norm_maxw(dev);
+		dev->height=norm_maxh(dev);
+		dev->frame_size=dev->width*dev->height*2;
+		dev->field_size=dev->frame_size>>1;
+		dev->bytesperline=dev->width*2;
+		dev->hscale=0;
+		dev->vscale=0;
+
+		em28xx_resolution_set(dev);
+*/
+/*
+		em28xx_uninit_isoc(dev);
+		em28xx_set_alternate(dev);
+		em28xx_capture_start(dev, 1);
+		em28xx_resolution_set(dev);
+		em28xx_init_isoc(dev);
+*/
+			em28xx_i2c_call_clients(dev, DECODER_SET_NORM,
+						&tvnorms[i].mode);
+			em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
+						&dev->tvnorm->id);
+
+			up(&dev->lock);
+
+			return 0;
+		}
+
+		/* ------ input switching ---------- */
+	case VIDIOC_ENUMINPUT:
+		{
+			struct v4l2_input *i = arg;
+			unsigned int n;
+			static const char *iname[] = {
+				[EM28XX_VMUX_COMPOSITE1] = "Composite1",
+				[EM28XX_VMUX_COMPOSITE2] = "Composite2",
+				[EM28XX_VMUX_COMPOSITE3] = "Composite3",
+				[EM28XX_VMUX_COMPOSITE4] = "Composite4",
+				[EM28XX_VMUX_SVIDEO] = "S-Video",
+				[EM28XX_VMUX_TELEVISION] = "Television",
+				[EM28XX_VMUX_CABLE] = "Cable TV",
+				[EM28XX_VMUX_DVB] = "DVB",
+				[EM28XX_VMUX_DEBUG] = "for debug only",
+			};
+
+			n = i->index;
+			if (n >= MAX_EM28XX_INPUT)
+				return -EINVAL;
+			if (0 == INPUT(n)->type)
+				return -EINVAL;
+			memset(i, 0, sizeof(*i));
+			i->index = n;
+			i->type = V4L2_INPUT_TYPE_CAMERA;
+			strcpy(i->name, iname[INPUT(n)->type]);
+			if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+			    (EM28XX_VMUX_CABLE == INPUT(n)->type))
+				i->type = V4L2_INPUT_TYPE_TUNER;
+			for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
+				i->std |= tvnorms[n].id;
+			return 0;
+		}
+
+	case VIDIOC_G_INPUT:
+		{
+			int *i = arg;
+			*i = dev->ctl_input;
+
+			return 0;
+		}
+
+	case VIDIOC_S_INPUT:
+		{
+			int *index = arg;
+
+			if (*index >= MAX_EM28XX_INPUT)
+				return -EINVAL;
+			if (0 == INPUT(*index)->type)
+				return -EINVAL;
+
+			down(&dev->lock);
+			video_mux(dev, *index);
+			up(&dev->lock);
+
+			return 0;
+		}
+
+	case VIDIOC_G_AUDIO:
+		{
+			struct v4l2_audio *a = arg;
+			unsigned int index = a->index;
+
+			if (a->index > 1)
+				return -EINVAL;
+			memset(a, 0, sizeof(*a));
+			index = dev->ctl_ainput;
+
+			if (index == 0) {
+				strcpy(a->name, "Television");
+			} else {
+				strcpy(a->name, "Line In");
+			}
+			a->capability = V4L2_AUDCAP_STEREO;
+			a->index = index;
+			return 0;
+		}
+
+	case VIDIOC_S_AUDIO:
+		{
+			struct v4l2_audio *a = arg;
+			if (a->index != dev->ctl_ainput)
+				return -EINVAL;
+
+			return 0;
+		}
+
+		/* --- controls ---------------------------------------------- */
+	case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			u8 i, n;
+			n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
+			for (i = 0; i < n; i++)
+				if (qc->id && qc->id == em28xx_qctrl[i].id) {
+					memcpy(qc, &(em28xx_qctrl[i]),
+					       sizeof(*qc));
+					return 0;
+				}
+
+			return -EINVAL;
+		}
+
+	case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl = arg;
+
+
+			return em28xx_get_ctrl(dev, ctrl);
+		}
+
+	case VIDIOC_S_CTRL_OLD:	/* ??? */
+	case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl = arg;
+			u8 i, n;
+
+
+			n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
+			for (i = 0; i < n; i++)
+				if (ctrl->id == em28xx_qctrl[i].id) {
+					if (ctrl->value <
+					    em28xx_qctrl[i].minimum
+					    || ctrl->value >
+					    em28xx_qctrl[i].maximum)
+						return -ERANGE;
+
+					return em28xx_set_ctrl(dev, ctrl);
+				}
+			return -EINVAL;
+		}
+
+		/* --- tuner ioctls ------------------------------------------ */
+	case VIDIOC_G_TUNER:
+		{
+			struct v4l2_tuner *t = arg;
+			int status = 0;
+
+			if (0 != t->index)
+				return -EINVAL;
+
+			memset(t, 0, sizeof(*t));
+			strcpy(t->name, "Tuner");
+			t->type = V4L2_TUNER_ANALOG_TV;
+			t->capability = V4L2_TUNER_CAP_NORM;
+			t->rangehigh = 0xffffffffUL;	/* FIXME: set correct range */
+/*		t->signal = 0xffff;*/
+/*		em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/
+			/* No way to get signal strength? */
+			down(&dev->lock);
+			em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+						&status);
+			up(&dev->lock);
+			t->signal =
+			    (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+			em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
+				 t->afc);
+			return 0;
+		}
+	case VIDIOC_S_TUNER:
+		{
+			struct v4l2_tuner *t = arg;
+			int status = 0;
+
+			if (0 != t->index)
+				return -EINVAL;
+			memset(t, 0, sizeof(*t));
+			strcpy(t->name, "Tuner");
+			t->type = V4L2_TUNER_ANALOG_TV;
+			t->capability = V4L2_TUNER_CAP_NORM;
+			t->rangehigh = 0xffffffffUL;	/* FIXME: set correct range */
+/*		t->signal = 0xffff; */
+			/* No way to get signal strength? */
+			down(&dev->lock);
+			em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+						&status);
+			up(&dev->lock);
+			t->signal =
+			    (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+			em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
+				 t->signal, t->afc);
+			return 0;
+		}
+	case VIDIOC_G_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+
+			memset(f, 0, sizeof(*f));
+			f->type = V4L2_TUNER_ANALOG_TV;
+			f->frequency = dev->ctl_freq;
+
+			return 0;
+		}
+	case VIDIOC_S_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+
+			if (0 != f->tuner)
+				return -EINVAL;
+
+			if (V4L2_TUNER_ANALOG_TV != f->type)
+				return -EINVAL;
+
+			down(&dev->lock);
+			dev->ctl_freq = f->frequency;
+			em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+			up(&dev->lock);
+			return 0;
+		}
+
+	case VIDIOC_CROPCAP:
+		{
+			struct v4l2_cropcap *cc = arg;
+
+			if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+				return -EINVAL;
+			cc->bounds.left = 0;
+			cc->bounds.top = 0;
+			cc->bounds.width = dev->width;
+			cc->bounds.height = dev->height;
+			cc->defrect = cc->bounds;
+			cc->pixelaspect.numerator = 54;	/* 4:3 FIXME: remove magic numbers */
+			cc->pixelaspect.denominator = 59;
+			return 0;
+		}
+	case VIDIOC_STREAMON:
+		{
+			int *type = arg;
+
+			if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+			    || dev->io != IO_MMAP)
+				return -EINVAL;
+
+			if (list_empty(&dev->inqueue))
+				return -EINVAL;
+
+			dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
+
+			em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
+
+			return 0;
+		}
+	case VIDIOC_STREAMOFF:
+		{
+			int *type = arg;
+			int ret;
+
+			if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+			    || dev->io != IO_MMAP)
+				return -EINVAL;
+
+			if (dev->stream == STREAM_ON) {
+				em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
+				if ((ret = em28xx_stream_interrupt(dev)))
+					return ret;
+			}
+			em28xx_empty_framequeues(dev);
+
+			return 0;
+		}
+	default:
+		return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
+						  driver_ioctl);
+	}
+	return 0;
+}
+
+/*
+ * em28xx_v4l2_do_ioctl()
+ * This function is _not_ called directly, but from
+ * em28xx_v4l2_ioctl. Userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
+				 unsigned int cmd, void *arg)
+{
+	struct em28xx *dev = filp->private_data;
+
+	if (!dev)
+		return -ENODEV;
+
+	if (video_debug > 1)
+		em28xx_print_ioctl(dev->name,cmd);
+
+	switch (cmd) {
+
+		/* --- capabilities ------------------------------------------ */
+	case VIDIOC_QUERYCAP:
+		{
+			struct v4l2_capability *cap = arg;
+
+			memset(cap, 0, sizeof(*cap));
+			strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+			strlcpy(cap->card, em28xx_boards[dev->model].name,
+				sizeof(cap->card));
+			strlcpy(cap->bus_info, dev->udev->dev.bus_id,
+				sizeof(cap->bus_info));
+			cap->version = EM28XX_VERSION_CODE;
+			cap->capabilities =
+			    V4L2_CAP_VIDEO_CAPTURE |
+			    V4L2_CAP_AUDIO |
+			    V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+			if (dev->has_tuner)
+				cap->capabilities |= V4L2_CAP_TUNER;
+			return 0;
+		}
+
+		/* --- capture ioctls ---------------------------------------- */
+	case VIDIOC_ENUM_FMT:
+		{
+			struct v4l2_fmtdesc *fmtd = arg;
+
+			if (fmtd->index != 0)
+				return -EINVAL;
+			memset(fmtd, 0, sizeof(*fmtd));
+			fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			strcpy(fmtd->description, "Packed YUY2");
+			fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+			memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+			return 0;
+		}
+
+	case VIDIOC_G_FMT:
+		{
+			struct v4l2_format *format = arg;
+
+			em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
+				 format->type ==
+				 V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+				 "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
+				 V4L2_BUF_TYPE_VBI_CAPTURE ?
+				 "V4L2_BUF_TYPE_VBI_CAPTURE " :
+				 "not supported");
+
+			if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+				return -EINVAL;
+
+			format->fmt.pix.width = dev->width;
+			format->fmt.pix.height = dev->height;
+			format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+			format->fmt.pix.bytesperline = dev->bytesperline;
+			format->fmt.pix.sizeimage = dev->frame_size;
+			format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+			format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+
+			em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
+				 dev->height);
+			return 0;
+		}
+
+	case VIDIOC_TRY_FMT:
+	case VIDIOC_S_FMT:
+		{
+			struct v4l2_format *format = arg;
+			u32 i;
+			int ret = 0;
+			int width = format->fmt.pix.width;
+			int height = format->fmt.pix.height;
+			unsigned int hscale, vscale;
+			unsigned int maxh, maxw;
+
+			maxw = norm_maxw(dev);
+			maxh = norm_maxh(dev);
+
+/*		int both_fields; */
+
+			em28xx_videodbg("%s: type=%s\n",
+				 cmd ==
+				 VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+				 "VIDIOC_S_FMT",
+				 format->type ==
+				 V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+				 "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
+				 V4L2_BUF_TYPE_VBI_CAPTURE ?
+				 "V4L2_BUF_TYPE_VBI_CAPTURE " :
+				 "not supported");
+
+			if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+				return -EINVAL;
+
+			em28xx_videodbg("%s: requested %dx%d\n",
+				 cmd ==
+				 VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+				 "VIDIOC_S_FMT", format->fmt.pix.width,
+				 format->fmt.pix.height);
+
+			/* FIXME: Move some code away from here */
+			/* width must even because of the YUYV format */
+			/* height must be even because of interlacing */
+			height &= 0xfffe;
+			width &= 0xfffe;
+
+			if (height < 32)
+				height = 32;
+			if (height > maxh)
+				height = maxh;
+			if (width < 48)
+				width = 48;
+			if (width > maxw)
+				width = maxw;
+
+			if(dev->is_em2800){
+				/* the em2800 can only scale down to 50% */
+				if(height % (maxh / 2))
+					height=maxh;
+				if(width % (maxw / 2))
+					width=maxw;
+				/* according to empiatech support */
+				/* the MaxPacketSize is to small to support */
+				/* framesizes larger than 640x480 @ 30 fps */
+				/* or 640x576 @ 25 fps. As this would cut */
+				/* of a part of the image we prefer */
+				/* 360x576 or 360x480 for now */
+				if(width == maxw && height == maxh)
+					width /= 2;
+			}
+
+			if ((hscale =
+			     (((unsigned long)maxw) << 12) / width - 4096L) >=
+			    0x4000)
+				hscale = 0x3fff;
+			width =
+			    (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+			if ((vscale =
+			     (((unsigned long)maxh) << 12) / height - 4096L) >=
+			    0x4000)
+				vscale = 0x3fff;
+			height =
+			    (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+			format->fmt.pix.width = width;
+			format->fmt.pix.height = height;
+			format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+			format->fmt.pix.bytesperline = width * 2;
+			format->fmt.pix.sizeimage = width * 2 * height;
+			format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+			format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+			em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
+				 cmd ==
+				 VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+				 "VIDIOC_S_FMT", format->fmt.pix.width,
+				 format->fmt.pix.height, hscale, vscale);
+
+			if (cmd == VIDIOC_TRY_FMT)
+				return 0;
+
+			for (i = 0; i < dev->num_frames; i++)
+				if (dev->frame[i].vma_use_count) {
+					em28xx_videodbg("VIDIOC_S_FMT failed. "
+						"Unmap the buffers first.\n");
+					return -EINVAL;
+				}
+
+			/* stop io in case it is already in progress */
+			if (dev->stream == STREAM_ON) {
+				em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
+				if ((ret = em28xx_stream_interrupt(dev)))
+					return ret;
+			}
+
+			em28xx_release_buffers(dev);
+			dev->io = IO_NONE;
+
+			/* set new image size */
+			dev->width = width;
+			dev->height = height;
+			dev->frame_size = dev->width * dev->height * 2;
+			dev->field_size = dev->frame_size >> 1;	/*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+			dev->bytesperline = dev->width * 2;
+			dev->hscale = hscale;
+			dev->vscale = vscale;
+/*			dev->both_fileds = both_fileds; */
+			em28xx_uninit_isoc(dev);
+			em28xx_set_alternate(dev);
+			em28xx_capture_start(dev, 1);
+			em28xx_resolution_set(dev);
+			em28xx_init_isoc(dev);
+
+			return 0;
+		}
+
+		/* --- streaming capture ------------------------------------- */
+	case VIDIOC_REQBUFS:
+		{
+			struct v4l2_requestbuffers *rb = arg;
+			u32 i;
+			int ret;
+
+			if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+			    rb->memory != V4L2_MEMORY_MMAP)
+				return -EINVAL;
+
+			if (dev->io == IO_READ) {
+				em28xx_videodbg ("method is set to read;"
+					" close and open the device again to"
+					" choose the mmap I/O method\n");
+				return -EINVAL;
+			}
+
+			for (i = 0; i < dev->num_frames; i++)
+				if (dev->frame[i].vma_use_count) {
+					em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
+					return -EINVAL;
+				}
+
+			if (dev->stream == STREAM_ON) {
+				em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+				if ((ret = em28xx_stream_interrupt(dev)))
+					return ret;
+			}
+
+			em28xx_empty_framequeues(dev);
+
+			em28xx_release_buffers(dev);
+			if (rb->count)
+				rb->count =
+				    em28xx_request_buffers(dev, rb->count);
+
+			dev->frame_current = NULL;
+
+			em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
+						     rb->count);
+			dev->io = rb->count ? IO_MMAP : IO_NONE;
+			return 0;
+		}
+
+	case VIDIOC_QUERYBUF:
+		{
+			struct v4l2_buffer *b = arg;
+
+			if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+			    b->index >= dev->num_frames || dev->io != IO_MMAP)
+				return -EINVAL;
+
+			memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+
+			if (dev->frame[b->index].vma_use_count) {
+				b->flags |= V4L2_BUF_FLAG_MAPPED;
+			}
+			if (dev->frame[b->index].state == F_DONE)
+				b->flags |= V4L2_BUF_FLAG_DONE;
+			else if (dev->frame[b->index].state != F_UNUSED)
+				b->flags |= V4L2_BUF_FLAG_QUEUED;
+			return 0;
+		}
+	case VIDIOC_QBUF:
+		{
+			struct v4l2_buffer *b = arg;
+			unsigned long lock_flags;
+
+			if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+			    b->index >= dev->num_frames || dev->io != IO_MMAP) {
+				return -EINVAL;
+			}
+
+			if (dev->frame[b->index].state != F_UNUSED) {
+				return -EAGAIN;
+			}
+			dev->frame[b->index].state = F_QUEUED;
+
+			/* add frame to fifo */
+			spin_lock_irqsave(&dev->queue_lock, lock_flags);
+			list_add_tail(&dev->frame[b->index].frame,
+				      &dev->inqueue);
+			spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+			return 0;
+		}
+	case VIDIOC_DQBUF:
+		{
+			struct v4l2_buffer *b = arg;
+			struct em28xx_frame_t *f;
+			unsigned long lock_flags;
+			int ret = 0;
+
+			if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+			    || dev->io != IO_MMAP)
+				return -EINVAL;
+
+			if (list_empty(&dev->outqueue)) {
+				if (dev->stream == STREAM_OFF)
+					return -EINVAL;
+				if (filp->f_flags & O_NONBLOCK)
+					return -EAGAIN;
+				ret = wait_event_interruptible
+				    (dev->wait_frame,
+				     (!list_empty(&dev->outqueue)) ||
+				     (dev->state & DEV_DISCONNECTED));
+				if (ret)
+					return ret;
+				if (dev->state & DEV_DISCONNECTED)
+					return -ENODEV;
+			}
+
+			spin_lock_irqsave(&dev->queue_lock, lock_flags);
+			f = list_entry(dev->outqueue.next,
+				       struct em28xx_frame_t, frame);
+			list_del(dev->outqueue.next);
+			spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+			f->state = F_UNUSED;
+			memcpy(b, &f->buf, sizeof(*b));
+
+			if (f->vma_use_count)
+				b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+			return 0;
+		}
+	default:
+		return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
+				       em28xx_video_do_ioctl);
+	}
+	return 0;
+}
+
+/*
+ * em28xx_v4l2_ioctl()
+ * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl()
+ */
+static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
+			     unsigned int cmd, unsigned long arg)
+{
+	int ret = 0;
+	struct em28xx *dev = filp->private_data;
+
+	if (down_interruptible(&dev->fileop_lock))
+		return -ERESTARTSYS;
+
+	if (dev->state & DEV_DISCONNECTED) {
+		em28xx_errdev("v4l2 ioctl: device not present\n");
+		up(&dev->fileop_lock);
+		return -ENODEV;
+	}
+
+	if (dev->state & DEV_MISCONFIGURED) {
+		em28xx_errdev
+		    ("v4l2 ioctl: device is misconfigured; close and open it again\n");
+		up(&dev->fileop_lock);
+		return -EIO;
+	}
+
+	ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
+
+	up(&dev->fileop_lock);
+
+	return ret;
+}
+
+static struct file_operations em28xx_v4l_fops = {
+	.owner = THIS_MODULE,
+	.open = em28xx_v4l2_open,
+	.release = em28xx_v4l2_close,
+	.ioctl = em28xx_v4l2_ioctl,
+	.read = em28xx_v4l2_read,
+	.poll = em28xx_v4l2_poll,
+	.mmap = em28xx_v4l2_mmap,
+	.llseek = no_llseek,
+};
+
+/******************************** usb interface *****************************************/
+
+/*
+ * em28xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+			   int minor, int model)
+{
+	struct em28xx *dev = *devhandle;
+	int retval = -ENOMEM;
+	int errCode, i;
+	unsigned int maxh, maxw;
+
+	dev->udev = udev;
+	dev->model = model;
+	init_MUTEX(&dev->lock);
+	init_waitqueue_head(&dev->open);
+
+	dev->em28xx_write_regs = em28xx_write_regs;
+	dev->em28xx_read_reg = em28xx_read_reg;
+	dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
+	dev->em28xx_write_regs_req = em28xx_write_regs_req;
+	dev->em28xx_read_reg_req = em28xx_read_reg_req;
+	dev->is_em2800 = em28xx_boards[model].is_em2800;
+	dev->has_tuner = em28xx_boards[model].has_tuner;
+	dev->has_msp34xx = em28xx_boards[model].has_msp34xx;
+	dev->tda9887_conf = em28xx_boards[model].tda9887_conf;
+	dev->decoder = em28xx_boards[model].decoder;
+
+	if (tuner >= 0)
+		dev->tuner_type = tuner;
+	else
+		dev->tuner_type = em28xx_boards[model].tuner_type;
+
+	dev->video_inputs = em28xx_boards[model].vchannels;
+
+	for (i = 0; i < TVNORMS; i++)
+		if (em28xx_boards[model].norm == tvnorms[i].mode)
+			break;
+	if (i == TVNORMS)
+		i = 0;
+
+	dev->tvnorm = &tvnorms[i];	/* set default norm */
+
+	em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
+
+	maxw = norm_maxw(dev);
+	maxh = norm_maxh(dev);
+
+	/* set default image size */
+	dev->width = maxw;
+	dev->height = maxh;
+	dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+	dev->field_size = dev->width * dev->height;
+	dev->frame_size =
+	    dev->interlaced ? dev->field_size << 1 : dev->field_size;
+	dev->bytesperline = dev->width * 2;
+	dev->hscale = 0;
+	dev->vscale = 0;
+	dev->ctl_input = 2;
+
+	/* setup video picture settings for saa7113h */
+	memset(&dev->vpic, 0, sizeof(dev->vpic));
+	dev->vpic.colour = 128 << 8;
+	dev->vpic.hue = 128 << 8;
+	dev->vpic.brightness = 128 << 8;
+	dev->vpic.contrast = 192 << 8;
+	dev->vpic.whiteness = 128 << 8;	/* This one isn't used */
+	dev->vpic.depth = 16;
+	dev->vpic.palette = VIDEO_PALETTE_YUV422;
+
+#ifdef CONFIG_MODULES
+	/* request some modules */
+	if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
+		request_module("saa711x");
+	if (dev->decoder == EM28XX_TVP5150)
+		request_module("tvp5150");
+	if (dev->has_tuner)
+		request_module("tuner");
+	if (dev->tda9887_conf)
+		request_module("tda9887");
+#endif
+	errCode = em28xx_config(dev);
+	if (errCode) {
+		em28xx_errdev("error configuring device\n");
+		kfree(dev);
+		return -ENOMEM;
+	}
+
+	down(&dev->lock);
+	/* register i2c bus */
+	em28xx_i2c_register(dev);
+
+	/* Do board specific init and eeprom reading */
+	em28xx_card_setup(dev);
+
+	/* configure the device */
+	em28xx_config_i2c(dev);
+
+	up(&dev->lock);
+
+	errCode = em28xx_config(dev);
+
+#ifdef CONFIG_MODULES
+	if (dev->has_msp34xx)
+		request_module("msp3400");
+#endif
+	/* allocate and fill v4l2 device struct */
+	dev->vdev = video_device_alloc();
+	if (NULL == dev->vdev) {
+		em28xx_errdev("cannot allocate video_device.\n");
+		kfree(dev);
+		return -ENOMEM;
+	}
+
+	dev->vdev->type = VID_TYPE_CAPTURE;
+	if (dev->has_tuner)
+		dev->vdev->type |= VID_TYPE_TUNER;
+	dev->vdev->hardware = 0;
+	dev->vdev->fops = &em28xx_v4l_fops;
+	dev->vdev->minor = -1;
+	dev->vdev->dev = &dev->udev->dev;
+	dev->vdev->release = video_device_release;
+	snprintf(dev->vdev->name, sizeof(dev->vdev->name), "%s",
+		 "em28xx video");
+	list_add_tail(&dev->devlist,&em28xx_devlist);
+
+	/* register v4l2 device */
+	down(&dev->lock);
+	if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1))) {
+		em28xx_errdev("unable to register video device (error=%i).\n",
+			      retval);
+		up(&dev->lock);
+		list_del(&dev->devlist);
+		video_device_release(dev->vdev);
+		kfree(dev);
+		return -ENODEV;
+	}
+	if (dev->has_msp34xx) {
+		/* Send a reset to other chips via gpio */
+		em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+		udelay(2500);
+		em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+		udelay(2500);
+
+	}
+	video_mux(dev, 0);
+
+	up(&dev->lock);
+
+	em28xx_info("V4L2 device registered as /dev/video%d\n",
+		    dev->vdev->minor);
+
+	return 0;
+}
+
+/*
+ * em28xx_usb_probe()
+ * checks for supported devices
+ */
+static int em28xx_usb_probe(struct usb_interface *interface,
+			    const struct usb_device_id *id)
+{
+	const struct usb_endpoint_descriptor *endpoint;
+	struct usb_device *udev;
+	struct usb_interface *uif;
+	struct em28xx *dev = NULL;
+	int retval = -ENODEV;
+	int model,i,nr,ifnum;
+
+	udev = usb_get_dev(interface_to_usbdev(interface));
+	ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+
+
+	/* Don't register audio interfaces */
+	if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+		em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
+				udev->descriptor.idVendor,udev->descriptor.idProduct,
+				ifnum,
+				interface->altsetting[0].desc.bInterfaceClass);
+		return -ENODEV;
+	}
+
+	em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
+			udev->descriptor.idVendor,udev->descriptor.idProduct,
+			ifnum,
+			interface->altsetting[0].desc.bInterfaceClass);
+
+	endpoint = &interface->cur_altsetting->endpoint[1].desc;
+
+	/* check if the the device has the iso in endpoint at the correct place */
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+	    USB_ENDPOINT_XFER_ISOC) {
+		em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
+		return -ENODEV;
+	}
+	if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+		em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
+		return -ENODEV;
+	}
+
+	model=id->driver_info;
+	nr=interface->minor;
+
+	if (nr>EM28XX_MAXBOARDS) {
+		printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
+		return -ENOMEM;
+	}
+
+	/* allocate memory for our device state and initialize it */
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		em28xx_err(DRIVER_NAME ": out of memory!\n");
+		return -ENOMEM;
+	}
+	memset(dev, 0, sizeof(*dev));
+
+	/* compute alternate max packet sizes */
+	uif = udev->actconfig->interface[0];
+
+	dev->num_alt=uif->num_altsetting;
+	printk(DRIVER_NAME ": Alternate settings: %i\n",dev->num_alt);
+//	dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
+	dev->alt_max_pkt_size = kmalloc(32*
+						dev->num_alt,GFP_KERNEL);
+	if (dev->alt_max_pkt_size == NULL) {
+		em28xx_err(DRIVER_NAME ": out of memory!\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < dev->num_alt ; i++) {
+		u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+							wMaxPacketSize);
+		dev->alt_max_pkt_size[i] =
+		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+		printk(DRIVER_NAME ": Alternate setting %i, max size= %i\n",i,
+							dev->alt_max_pkt_size[i]);
+	}
+
+	snprintf(dev->name, 29, "em28xx #%d", nr);
+
+	if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
+		model=card[nr];
+
+	if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
+		printk( "%s: Your board has no eeprom inside it and thus can't\n"
+			"%s: be autodetected.  Please pass card=<n> insmod option to\n"
+			"%s: workaround that.  Redirect complaints to the vendor of\n"
+			"%s: the TV card.  Best regards,\n"
+			"%s:         -- tux\n",
+			dev->name,dev->name,dev->name,dev->name,dev->name);
+		printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+			dev->name);
+		for (i = 0; i < em28xx_bcount; i++) {
+			printk("%s:    card=%d -> %s\n",
+				dev->name, i, em28xx_boards[i].name);
+		}
+	}
+
+	/* allocate device struct */
+	retval = em28xx_init_dev(&dev, udev, nr, model);
+	if (retval)
+		return retval;
+
+	em28xx_info("Found %s\n", em28xx_boards[model].name);
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, dev);
+	return 0;
+}
+
+/*
+ * em28xx_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void em28xx_usb_disconnect(struct usb_interface *interface)
+{
+	struct em28xx *dev = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	if (!dev)
+		return;
+
+	down_write(&em28xx_disconnect);
+
+	down(&dev->lock);
+
+	em28xx_info("disconnecting %s\n", dev->vdev->name);
+
+	wake_up_interruptible_all(&dev->open);
+
+	if (dev->users) {
+		em28xx_warn
+		    ("device /dev/video%d is open! Deregistration and memory "
+		     "deallocation are deferred on close.\n", dev->vdev->minor);
+		dev->state |= DEV_MISCONFIGURED;
+		em28xx_uninit_isoc(dev);
+		dev->state |= DEV_DISCONNECTED;
+		wake_up_interruptible(&dev->wait_frame);
+		wake_up_interruptible(&dev->wait_stream);
+	} else {
+		dev->state |= DEV_DISCONNECTED;
+		em28xx_release_resources(dev);
+	}
+
+	up(&dev->lock);
+
+	if (!dev->users) {
+		kfree(dev->alt_max_pkt_size);
+		kfree(dev);
+	}
+
+	up_write(&em28xx_disconnect);
+}
+
+static struct usb_driver em28xx_usb_driver = {
+	.owner = THIS_MODULE,
+	.name = "em28xx",
+	.probe = em28xx_usb_probe,
+	.disconnect = em28xx_usb_disconnect,
+	.id_table = em28xx_id_table,
+};
+
+static int __init em28xx_module_init(void)
+{
+	int result;
+
+	printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
+	       (EM28XX_VERSION_CODE >> 16) & 0xff,
+	       (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+	printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
+	       SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
+#endif
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&em28xx_usb_driver);
+	if (result)
+		em28xx_err(DRIVER_NAME
+			   " usb_register failed. Error number %d.\n", result);
+
+	return result;
+}
+
+static void __exit em28xx_module_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&em28xx_usb_driver);
+}
+
+module_init(em28xx_module_init);
+module_exit(em28xx_module_exit);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
new file mode 100644
index 0000000..5c7a41c
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -0,0 +1,513 @@
+/*
+   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
+		      Ludovico Cavedon <cavedon@sssup.it>
+		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+
+   Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _EM28XX_H
+#define _EM28XX_H
+
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <media/ir-kbd-i2c.h>
+
+/* Boards supported by driver */
+
+#define EM2800_BOARD_UNKNOWN			0
+#define EM2820_BOARD_UNKNOWN			1
+#define EM2820_BOARD_TERRATEC_CINERGY_250	2
+#define EM2820_BOARD_PINNACLE_USB_2		3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
+#define EM2820_BOARD_MSI_VOX_USB_2              5
+#define EM2800_BOARD_TERRATEC_CINERGY_200       6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
+#define EM2800_BOARD_KWORLD_USB2800             8
+#define EM2820_BOARD_PINNACLE_DVC_90		9
+
+#define UNSET -1
+
+/* maximum number of em28xx boards */
+#define EM28XX_MAXBOARDS 1 /*FIXME: should be bigger */
+
+/* maximum number of frames that can be queued */
+#define EM28XX_NUM_FRAMES 5
+/* number of frames that get used for v4l2_read() */
+#define EM28XX_NUM_READ_FRAMES 2
+
+/* number of buffers for isoc transfers */
+#define EM28XX_NUM_BUFS 5
+
+/* number of packets for each buffer
+   windows requests only 40 packets .. so we better do the same
+   this is what I found out for all alternate numbers there!
+ */
+#define EM28XX_NUM_PACKETS 40
+
+/* default alternate; 0 means choose the best */
+#define EM28XX_PINOUT 0
+
+#define EM28XX_INTERLACED_DEFAULT 1
+
+/*
+#define (use usbview if you want to get the other alternate number infos)
+#define
+#define alternate number 2
+#define 			Endpoint Address: 82
+			Direction: in
+			Attribute: 1
+			Type: Isoc
+			Max Packet Size: 1448
+			Interval: 125us
+
+  alternate number 7
+
+			Endpoint Address: 82
+			Direction: in
+			Attribute: 1
+			Type: Isoc
+			Max Packet Size: 3072
+			Interval: 125us
+*/
+
+/* time to wait when stopping the isoc transfer */
+#define EM28XX_URB_TIMEOUT       msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
+
+/* time in msecs to wait for i2c writes to finish */
+#define EM2800_I2C_WRITE_TIMEOUT 20
+
+/* the various frame states */
+enum em28xx_frame_state {
+	F_UNUSED = 0,
+	F_QUEUED,
+	F_GRABBING,
+	F_DONE,
+	F_ERROR,
+};
+
+/* stream states */
+enum em28xx_stream_state {
+	STREAM_OFF,
+	STREAM_INTERRUPT,
+	STREAM_ON,
+};
+
+/* frames */
+struct em28xx_frame_t {
+	void *bufmem;
+	struct v4l2_buffer buf;
+	enum em28xx_frame_state state;
+	struct list_head frame;
+	unsigned long vma_use_count;
+	int top_field;
+	int fieldbytesused;
+};
+
+/* io methods */
+enum em28xx_io_method {
+	IO_NONE,
+	IO_READ,
+	IO_MMAP,
+};
+
+/* inputs */
+
+#define MAX_EM28XX_INPUT 4
+enum enum28xx_itype {
+	EM28XX_VMUX_COMPOSITE1 = 1,
+	EM28XX_VMUX_COMPOSITE2,
+	EM28XX_VMUX_COMPOSITE3,
+	EM28XX_VMUX_COMPOSITE4,
+	EM28XX_VMUX_SVIDEO,
+	EM28XX_VMUX_TELEVISION,
+	EM28XX_VMUX_CABLE,
+	EM28XX_VMUX_DVB,
+	EM28XX_VMUX_DEBUG,
+	EM28XX_RADIO,
+};
+
+struct em28xx_input {
+	enum enum28xx_itype type;
+	unsigned int vmux;
+	unsigned int amux;
+};
+
+#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
+
+enum em28xx_decoder {
+	EM28XX_TVP5150,
+	EM28XX_SAA7113,
+	EM28XX_SAA7114
+};
+
+struct em28xx_board {
+	char *name;
+	int vchannels;
+	int norm;
+	int tuner_type;
+
+	/* i2c flags */
+	unsigned int is_em2800;
+	unsigned int tda9887_conf;
+
+	unsigned int has_tuner:1;
+	unsigned int has_msp34xx:1;
+
+	enum em28xx_decoder decoder;
+
+	struct em28xx_input       input[MAX_EM28XX_INPUT];
+};
+
+struct em28xx_eeprom {
+	u32 id;			/* 0x9567eb1a */
+	u16 vendor_ID;
+	u16 product_ID;
+
+	u16 chip_conf;
+
+	u16 board_conf;
+
+	u16 string1, string2, string3;
+
+	u8 string_idx_table;
+};
+
+/* device states */
+enum em28xx_dev_state {
+	DEV_INITIALIZED = 0x01,
+	DEV_DISCONNECTED = 0x02,
+	DEV_MISCONFIGURED = 0x04,
+};
+
+/* tvnorms */
+struct em28xx_tvnorm {
+	char *name;
+	v4l2_std_id id;
+	/* mode for saa7113h */
+	int mode;
+};
+
+/* main device struct */
+struct em28xx {
+	/* generic device properties */
+	char name[30];		/* name (including minor) of the device */
+	int model;		/* index in the device_data struct */
+	unsigned int is_em2800;
+	int video_inputs;	/* number of video inputs */
+	struct list_head	devlist;
+	unsigned int has_tuner:1;
+	unsigned int has_msp34xx:1;
+	unsigned int has_tda9887:1;
+
+	enum em28xx_decoder decoder;
+
+	int tuner_type;		/* type of the tuner */
+	int tuner_addr;		/* tuner address */
+	int tda9887_conf;
+	/* i2c i/o */
+	struct i2c_adapter i2c_adap;
+	struct i2c_client i2c_client;
+	/* video for linux */
+	int users;		/* user count for exclusive use */
+	struct video_device *vdev;	/* video for linux device struct */
+	struct video_picture vpic;	/* picture settings only used to init saa7113h */
+	struct em28xx_tvnorm *tvnorm;	/* selected tv norm */
+	int ctl_freq;		/* selected frequency */
+	unsigned int ctl_input;	/* selected input */
+	unsigned int ctl_ainput;	/* slected audio input */
+	int mute;
+	int volume;
+	/* frame properties */
+	struct em28xx_frame_t frame[EM28XX_NUM_FRAMES];	/* list of frames */
+	int num_frames;		/* number of frames currently in use */
+	unsigned int frame_count;	/* total number of transfered frames */
+	struct em28xx_frame_t *frame_current;	/* the frame that is being filled */
+	int width;		/* current frame width */
+	int height;		/* current frame height */
+	int frame_size;		/* current frame size */
+	int field_size;		/* current field size */
+	int bytesperline;
+	int hscale;		/* horizontal scale factor (see datasheet) */
+	int vscale;		/* vertical scale factor (see datasheet) */
+	int interlaced;		/* 1=interlace fileds, 0=just top fileds */
+	int type;
+
+	/* states */
+	enum em28xx_dev_state state;
+	enum em28xx_stream_state stream;
+	enum em28xx_io_method io;
+	/* locks */
+	struct semaphore lock, fileop_lock;
+	spinlock_t queue_lock;
+	struct list_head inqueue, outqueue;
+	wait_queue_head_t open, wait_frame, wait_stream;
+	struct video_device *vbi_dev;
+
+	unsigned char eedata[256];
+
+	/* usb transfer */
+	struct usb_device *udev;	/* the usb device */
+	int alt;		/* alternate */
+	int max_pkt_size;	/* max packet size of isoc transaction */
+	int num_alt;		/* Number of alternative settings */
+	unsigned int *alt_max_pkt_size;	/* array of wMaxPacketSize */
+	struct urb *urb[EM28XX_NUM_BUFS];	/* urb for isoc transfers */
+	char *transfer_buffer[EM28XX_NUM_BUFS];	/* transfer buffers for isoc transfer */
+	/* helper funcs that call usb_control_msg */
+	int (*em28xx_write_regs) (struct em28xx * dev, u16 reg, char *buf,
+				  int len);
+	int (*em28xx_read_reg) (struct em28xx * dev, u16 reg);
+	int (*em28xx_read_reg_req_len) (struct em28xx * dev, u8 req, u16 reg,
+					char *buf, int len);
+	int (*em28xx_write_regs_req) (struct em28xx * dev, u8 req, u16 reg,
+				      char *buf, int len);
+	int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
+};
+
+/* Provided by em28xx-i2c.c */
+
+void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg);
+int em28xx_i2c_register(struct em28xx *dev);
+int em28xx_i2c_unregister(struct em28xx *dev);
+
+/* Provided by em28xx-input.c */
+
+void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
+
+/* Provided by em28xx-core.c */
+
+void em28xx_print_ioctl(char *name, unsigned int cmd);
+
+u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
+void em28xx_queue_unusedframes(struct em28xx *dev);
+void em28xx_release_buffers(struct em28xx *dev);
+
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+			    char *buf, int len);
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg);
+int em28xx_read_reg(struct em28xx *dev, u16 reg);
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+			  int len);
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+			  u8 bitmask);
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val);
+int em28xx_audio_analog_set(struct em28xx *dev);
+int em28xx_colorlevels_set_default(struct em28xx *dev);
+int em28xx_capture_start(struct em28xx *dev, int start);
+int em28xx_outfmt_set_yuv422(struct em28xx *dev);
+int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
+			   u8 ymax);
+int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+			    u16 width, u16 height);
+int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v);
+int em28xx_resolution_set(struct em28xx *dev);
+void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs);
+int em28xx_init_isoc(struct em28xx *dev);
+void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_set_alternate(struct em28xx *dev);
+
+/* Provided by em28xx-cards.c */
+extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern void em28xx_card_setup(struct em28xx *dev);
+extern struct em28xx_board em28xx_boards[];
+extern struct usb_device_id em28xx_id_table[];
+extern const unsigned int em28xx_bcount;
+
+/* em28xx registers */
+#define CHIPID_REG	0x0a
+#define USBSUSP_REG	0x0c	/* */
+
+#define AUDIOSRC_REG	0x0e
+#define XCLK_REG	0x0f
+
+#define VINMODE_REG	0x10
+#define VINCTRL_REG	0x11
+#define VINENABLE_REG	0x12	/* */
+
+#define GAMMA_REG	0x14
+#define RGAIN_REG	0x15
+#define GGAIN_REG	0x16
+#define BGAIN_REG	0x17
+#define ROFFSET_REG	0x18
+#define GOFFSET_REG	0x19
+#define BOFFSET_REG	0x1a
+
+#define OFLOW_REG	0x1b
+#define HSTART_REG	0x1c
+#define VSTART_REG	0x1d
+#define CWIDTH_REG	0x1e
+#define CHEIGHT_REG	0x1f
+
+#define YGAIN_REG	0x20
+#define YOFFSET_REG	0x21
+#define UVGAIN_REG	0x22
+#define UOFFSET_REG	0x23
+#define VOFFSET_REG	0x24
+#define SHARPNESS_REG	0x25
+
+#define COMPR_REG	0x26
+#define OUTFMT_REG	0x27
+
+#define XMIN_REG	0x28
+#define XMAX_REG	0x29
+#define YMIN_REG	0x2a
+#define YMAX_REG	0x2b
+
+#define HSCALELOW_REG	0x30
+#define HSCALEHIGH_REG	0x31
+#define VSCALELOW_REG	0x32
+#define VSCALEHIGH_REG	0x33
+
+#define AC97LSB_REG	0x40
+#define AC97MSB_REG	0x41
+#define AC97ADDR_REG	0x42
+#define AC97BUSY_REG	0x43
+
+/* em202 registers */
+#define MASTER_AC97	0x02
+#define VIDEO_AC97	0x14
+
+/* register settings */
+#define EM28XX_AUDIO_SRC_TUNER	0xc0
+#define EM28XX_AUDIO_SRC_LINE	0x80
+
+/* printk macros */
+
+#define em28xx_err(fmt, arg...) do {\
+	printk(KERN_ERR fmt , ##arg); } while (0)
+
+#define em28xx_errdev(fmt, arg...) do {\
+	printk(KERN_ERR "%s: "fmt,\
+			dev->name , ##arg); } while (0)
+
+#define em28xx_info(fmt, arg...) do {\
+	printk(KERN_INFO "%s: "fmt,\
+			dev->name , ##arg); } while (0)
+#define em28xx_warn(fmt, arg...) do {\
+	printk(KERN_WARNING "%s: "fmt,\
+			dev->name , ##arg); } while (0)
+
+inline static int em28xx_audio_source(struct em28xx *dev, int input)
+{
+	return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+}
+
+inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute)
+{
+	return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80);
+}
+
+inline static int em28xx_audio_analog_setup(struct em28xx *dev)
+{
+	/* unmute video mixer with default volume level */
+	return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08");
+}
+
+inline static int em28xx_compression_disable(struct em28xx *dev)
+{
+	/* side effect of disabling scaler and mixer */
+	return em28xx_write_regs(dev, COMPR_REG, "\x00", 1);
+}
+
+inline static int em28xx_contrast_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, YGAIN_REG) & 0x1f;
+}
+
+inline static int em28xx_brightness_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, YOFFSET_REG);
+}
+
+inline static int em28xx_saturation_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, UVGAIN_REG) & 0x1f;
+}
+
+inline static int em28xx_u_balance_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, UOFFSET_REG);
+}
+
+inline static int em28xx_v_balance_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, VOFFSET_REG);
+}
+
+inline static int em28xx_gamma_get(struct em28xx *dev)
+{
+	return em28xx_read_reg(dev, GAMMA_REG) & 0x3f;
+}
+
+inline static int em28xx_contrast_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, YGAIN_REG, &tmp, 1);
+}
+
+inline static int em28xx_brightness_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, YOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_saturation_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, UVGAIN_REG, &tmp, 1);
+}
+
+inline static int em28xx_u_balance_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, UOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_v_balance_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, VOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
+{
+	u8 tmp = (u8) val;
+	return em28xx_write_regs(dev, GAMMA_REG, &tmp, 1);
+}
+
+/*FIXME: maxw should be dependent of alt mode */
+inline static unsigned int norm_maxw(struct em28xx *dev)
+{
+	switch(dev->model){
+		case (EM2820_BOARD_MSI_VOX_USB_2): return(640);
+		default: return(720);
+	}
+}
+
+inline static unsigned int norm_maxh(struct em28xx *dev)
+{
+	switch(dev->model){
+		case (EM2820_BOARD_MSI_VOX_USB_2): return(480);
+		default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480;
+	}
+}
+
+#endif
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c
index 234151e..ed81934 100644
--- a/drivers/media/video/ir-kbd-gpio.c
+++ b/drivers/media/video/ir-kbd-gpio.c
@@ -156,6 +156,71 @@
 
 /* ---------------------------------------------------------------------- */
 
+/* Ricardo Cerqueira <v4l@cerqueira.org> */
+/* Weird matching, since the remote has "uncommon" keys */
+
+static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
+
+	[ 30 ] = KEY_POWER,       // power
+	[ 7  ] = KEY_MEDIA,       // source
+	[ 28 ] = KEY_SEARCH,      // scan
+
+/* FIXME: duplicate keycodes?
+ *
+ * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
+ * The GPIO values are
+ * 6397fb for both "Scan <" and "CH -",
+ * 639ffb for "Scan >" and "CH+",
+ * 6384fb for "Tune <" and "<<<",
+ * 638cfb for "Tune >" and ">>>", regardless of the mask.
+ *
+ *	[ 23 ] = KEY_BACK,        // fm scan <<
+ *	[ 31 ] = KEY_FORWARD,     // fm scan >>
+ *
+ *	[ 4  ] = KEY_LEFT,        // fm tuning <
+ *	[ 12 ] = KEY_RIGHT,       // fm tuning >
+ *
+ * For now, these four keys are disabled. Pressing them will generate
+ * the CH+/CH-/<<</>>> events
+ */
+
+	[ 3  ] = KEY_TUNER,       // TV/FM
+
+	[ 0  ] = KEY_RECORD,
+	[ 8  ] = KEY_STOP,
+	[ 17 ] = KEY_PLAY,
+
+	[ 26 ] = KEY_PLAYPAUSE,   // freeze
+	[ 25 ] = KEY_ZOOM,        // zoom
+	[ 15 ] = KEY_TEXT,        // min
+
+	[ 1  ] = KEY_KP1,
+	[ 11 ] = KEY_KP2,
+	[ 27 ] = KEY_KP3,
+	[ 5  ] = KEY_KP4,
+	[ 9  ] = KEY_KP5,
+	[ 21 ] = KEY_KP6,
+	[ 6  ] = KEY_KP7,
+	[ 10 ] = KEY_KP8,
+	[ 18 ] = KEY_KP9,
+	[ 2  ] = KEY_KP0,
+	[ 16 ] = KEY_LAST,        // +100
+	[ 19 ] = KEY_LIST,        // recall
+
+	[ 31 ] = KEY_CHANNELUP,   // chn down
+	[ 23 ] = KEY_CHANNELDOWN, // chn up
+	[ 22 ] = KEY_VOLUMEUP,    // vol down
+	[ 20 ] = KEY_VOLUMEDOWN,  // vol up
+
+	[ 4  ] = KEY_KPMINUS,     // <<<
+	[ 14 ] = KEY_SETUP,       // function
+	[ 12 ] = KEY_KPPLUS,      // >>>
+
+	[ 13 ] = KEY_GOTO,        // mts
+	[ 29 ] = KEY_REFRESH,     // reset
+	[ 24 ] = KEY_MUTE         // mute/unmute
+};
+
 struct IR {
 	struct bttv_sub_device  *sub;
 	struct input_dev        *input;
@@ -282,53 +347,59 @@
 
 	/* detect & configure */
 	switch (sub->core->type) {
-	case BTTV_AVERMEDIA:
-	case BTTV_AVPHONE98:
-	case BTTV_AVERMEDIA98:
+	case BTTV_BOARD_AVERMEDIA:
+	case BTTV_BOARD_AVPHONE98:
+	case BTTV_BOARD_AVERMEDIA98:
 		ir_codes         = ir_codes_avermedia;
 		ir->mask_keycode = 0xf88000;
 		ir->mask_keydown = 0x010000;
 		ir->polling      = 50; // ms
 		break;
 
-	case BTTV_AVDVBT_761:
-	case BTTV_AVDVBT_771:
+	case BTTV_BOARD_AVDVBT_761:
+	case BTTV_BOARD_AVDVBT_771:
 		ir_codes         = ir_codes_avermedia_dvbt;
 		ir->mask_keycode = 0x0f00c0;
 		ir->mask_keydown = 0x000020;
 		ir->polling      = 50; // ms
 		break;
 
-	case BTTV_PXELVWPLTVPAK:
+	case BTTV_BOARD_PXELVWPLTVPAK:
 		ir_codes         = ir_codes_pixelview;
 		ir->mask_keycode = 0x003e00;
 		ir->mask_keyup   = 0x010000;
 		ir->polling      = 50; // ms
-                break;
-	case BTTV_PV_BT878P_9B:
-	case BTTV_PV_BT878P_PLUS:
+		break;
+	case BTTV_BOARD_PV_BT878P_9B:
+	case BTTV_BOARD_PV_BT878P_PLUS:
 		ir_codes         = ir_codes_pixelview;
 		ir->mask_keycode = 0x001f00;
 		ir->mask_keyup   = 0x008000;
 		ir->polling      = 50; // ms
-                break;
+		break;
 
-	case BTTV_WINFAST2000:
+	case BTTV_BOARD_WINFAST2000:
 		ir_codes         = ir_codes_winfast;
 		ir->mask_keycode = 0x1f8;
 		break;
-	case BTTV_MAGICTVIEW061:
-	case BTTV_MAGICTVIEW063:
+	case BTTV_BOARD_MAGICTVIEW061:
+	case BTTV_BOARD_MAGICTVIEW063:
 		ir_codes         = ir_codes_winfast;
 		ir->mask_keycode = 0x0008e000;
 		ir->mask_keydown = 0x00200000;
 		break;
-	case BTTV_APAC_VIEWCOMP:
+	case BTTV_BOARD_APAC_VIEWCOMP:
 		ir_codes         = ir_codes_apac_viewcomp;
 		ir->mask_keycode = 0x001f00;
 		ir->mask_keyup   = 0x008000;
 		ir->polling      = 50; // ms
 		break;
+	case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
+		ir_codes         = ir_codes_conceptronic;
+		ir->mask_keycode = 0x001F00;
+		ir->mask_keyup   = 0x006000;
+		ir->polling      = 50; // ms
+		break;
 	}
 	if (NULL == ir_codes) {
 		kfree(ir);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 9703d3d..0085567 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -8,6 +8,8 @@
  *      Christoph Bartelmus <lirc@bartelmus.de>
  * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
  *      Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for em2820 based USB TV tuners by
+ *      Markus Rechberger <mrechberger@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
@@ -37,10 +39,9 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/workqueue.h>
-
 #include <asm/semaphore.h>
-
 #include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
 
 /* Mark Phalan <phalanm@o2.ie> */
 static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
@@ -81,57 +82,6 @@
 	[ 28 ] = KEY_MEDIA,             /* PC/TV */
 };
 
-static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
-	[ 0x3  ] = KEY_POWER,
-	[ 0x6f ] = KEY_MUTE,
-	[ 0x10 ] = KEY_BACKSPACE,	/* Recall */
-
-	[ 0x11 ] = KEY_KP0,
-	[ 0x4  ] = KEY_KP1,
-	[ 0x5  ] = KEY_KP2,
-	[ 0x6  ] = KEY_KP3,
-	[ 0x8  ] = KEY_KP4,
-	[ 0x9  ] = KEY_KP5,
-	[ 0xa  ] = KEY_KP6,
-	[ 0xc  ] = KEY_KP7,
-	[ 0xd  ] = KEY_KP8,
-	[ 0xe  ] = KEY_KP9,
-	[ 0x12 ] = KEY_KPDOT,		/* 100+ */
-
-	[ 0x7  ] = KEY_VOLUMEUP,
-	[ 0xb  ] = KEY_VOLUMEDOWN,
-	[ 0x1a ] = KEY_KPPLUS,
-	[ 0x18 ] = KEY_KPMINUS,
-	[ 0x15 ] = KEY_UP,
-	[ 0x1d ] = KEY_DOWN,
-	[ 0xf  ] = KEY_CHANNELUP,
-	[ 0x13 ] = KEY_CHANNELDOWN,
-	[ 0x48 ] = KEY_ZOOM,
-
-	[ 0x1b ] = KEY_VIDEO,		/* Video source */
-	[ 0x49 ] = KEY_LANGUAGE,	/* MTS Select */
-	[ 0x19 ] = KEY_SEARCH,		/* Auto Scan */
-
-	[ 0x4b ] = KEY_RECORD,
-	[ 0x46 ] = KEY_PLAY,
-	[ 0x45 ] = KEY_PAUSE,   	/* Pause */
-	[ 0x44 ] = KEY_STOP,
-	[ 0x40 ] = KEY_FORWARD,   	/* Forward ? */
-	[ 0x42 ] = KEY_REWIND,   	/* Backward ? */
-
-};
-
-struct IR {
-	struct i2c_client      c;
-	struct input_dev       *input;
-	struct ir_input_state  ir;
-
-	struct work_struct     work;
-	struct timer_list      timer;
-	char                   phys[32];
-	int                    (*get_key)(struct IR*, u32*, u32*);
-};
-
 /* ----------------------------------------------------------------------- */
 /* insmod parameters                                                       */
 
@@ -144,7 +94,7 @@
 
 /* ----------------------------------------------------------------------- */
 
-static int get_key_haup(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char buf[3];
 	int start, toggle, dev, code;
@@ -171,9 +121,9 @@
 	return 1;
 }
 
-static int get_key_pixelview(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
-        unsigned char b;
+	unsigned char b;
 
 	/* poll IR chip */
 	if (1 != i2c_master_recv(&ir->c,&b,1)) {
@@ -185,9 +135,9 @@
 	return 1;
 }
 
-static int get_key_pv951(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
-        unsigned char b;
+	unsigned char b;
 
 	/* poll IR chip */
 	if (1 != i2c_master_recv(&ir->c,&b,1)) {
@@ -205,7 +155,7 @@
 	return 1;
 }
 
-static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char b;
 
@@ -216,15 +166,15 @@
 	}
 
 	/* it seems that 0xFE indicates that a button is still hold
-	   down, while 0xFF indicates that no button is hold
-	   down. 0xFE sequences are sometimes interrupted by 0xFF */
+	   down, while 0xff indicates that no button is hold
+	   down. 0xfe sequences are sometimes interrupted by 0xFF */
 
 	dprintk(2,"key %02x\n", b);
 
-	if (b == 0xFF)
+	if (b == 0xff)
 		return 0;
 
-	if (b == 0xFE)
+	if (b == 0xfe)
 		/* keep old data */
 		return 1;
 
@@ -233,31 +183,9 @@
 	return 1;
 }
 
-static int get_key_purpletv(struct IR *ir, u32 *ir_key, u32 *ir_raw)
-{
-        unsigned char b;
-
-	/* poll IR chip */
-	if (1 != i2c_master_recv(&ir->c,&b,1)) {
-		dprintk(1,"read error\n");
-		return -EIO;
-	}
-
-	/* no button press */
-	if (b==0)
-		return 0;
-
-	/* repeating */
-	if (b & 0x80)
-		return 1;
-
-	*ir_key = b;
-	*ir_raw = b;
-	return 1;
-}
 /* ----------------------------------------------------------------------- */
 
-static void ir_key_poll(struct IR *ir)
+static void ir_key_poll(struct IR_i2c *ir)
 {
 	static u32 ir_key, ir_raw;
 	int rc;
@@ -278,13 +206,13 @@
 
 static void ir_timer(unsigned long data)
 {
-	struct IR *ir = (struct IR*)data;
+	struct IR_i2c *ir = (struct IR_i2c*)data;
 	schedule_work(&ir->work);
 }
 
 static void ir_work(void *data)
 {
-	struct IR *ir = data;
+	struct IR_i2c *ir = data;
 	ir_key_poll(ir);
 	mod_timer(&ir->timer, jiffies+HZ/10);
 }
@@ -297,17 +225,17 @@
 static int ir_probe(struct i2c_adapter *adap);
 
 static struct i2c_driver driver = {
-        .name           = "ir remote kbd driver",
-        .id             = I2C_DRIVERID_EXP3, /* FIXME */
-        .flags          = I2C_DF_NOTIFY,
-        .attach_adapter = ir_probe,
-        .detach_client  = ir_detach,
+	.name           = "ir remote kbd driver",
+	.id             = I2C_DRIVERID_EXP3, /* FIXME */
+	.flags          = I2C_DF_NOTIFY,
+	.attach_adapter = ir_probe,
+	.detach_client  = ir_detach,
 };
 
 static struct i2c_client client_template =
 {
-        .name = "unset",
-        .driver = &driver
+	.name = "unset",
+	.driver = &driver
 };
 
 static int ir_attach(struct i2c_adapter *adap, int addr,
@@ -316,10 +244,10 @@
 	IR_KEYTAB_TYPE *ir_codes = NULL;
 	char *name;
 	int ir_type;
-        struct IR *ir;
+        struct IR_i2c *ir;
 	struct input_dev *input_dev;
 
-	ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+	ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!ir || !input_dev) {
 		kfree(ir);
@@ -361,10 +289,10 @@
 		ir_codes    = ir_codes_empty;
 		break;
 	case 0x7a:
-		name        = "Purple TV";
-		ir->get_key = get_key_purpletv;
+	case 0x47:
+		/* Handled by saa7134-input */
+		name        = "SAA713x remote";
 		ir_type     = IR_TYPE_OTHER;
-		ir_codes    = ir_codes_purpletv;
 		break;
 	default:
 		/* shouldn't happen */
@@ -373,9 +301,24 @@
 		return -1;
 	}
 
-	/* register i2c device */
-	i2c_attach_client(&ir->c);
+	/* Sets name */
 	snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
+	ir->ir_codes=ir_codes;
+
+	/* register i2c device
+	 * At device register, IR codes may be changed to be
+	 * board dependent.
+	*/
+	i2c_attach_client(&ir->c);
+
+	/* If IR not supported or disabled, unregisters driver */
+	if (ir->get_key == NULL) {
+		i2c_detach_client(&ir->c);
+		kfree(ir);
+		return -1;
+	}
+
+	/* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */
 	snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
 		 ir->c.adapter->dev.bus_id,
 		 ir->c.dev.bus_id);
@@ -386,6 +329,7 @@
 	input_dev->name		= ir->c.name;
 	input_dev->phys		= ir->phys;
 
+	/* register event device */
 	input_register_device(ir->input);
 
 	/* start polling via eventd */
@@ -400,7 +344,7 @@
 
 static int ir_detach(struct i2c_client *client)
 {
-        struct IR *ir = i2c_get_clientdata(client);
+	struct IR_i2c *ir = i2c_get_clientdata(client);
 
 	/* kill outstanding polls */
 	del_timer(&ir->timer);
@@ -428,9 +372,12 @@
 	*/
 
 	static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
-	static const int probe_saa7134[] = { 0x7a, -1 };
+	static const int probe_saa7134[] = { 0x7a, 0x47, -1 };
+	static const int probe_em28XX[] = { 0x30, 0x47, -1 };
 	const int *probe = NULL;
-	struct i2c_client c; char buf; int i,rc;
+	struct i2c_client c;
+	unsigned char buf;
+	int i,rc;
 
 	switch (adap->id) {
 	case I2C_HW_B_BT848:
@@ -439,6 +386,9 @@
 	case I2C_HW_SAA7134:
 		probe = probe_saa7134;
 		break;
+	case I2C_HW_B_EM28XX:
+		probe = probe_em28XX;
+		break;
 	}
 	if (NULL == probe)
 		return 0;
@@ -447,11 +397,11 @@
 	c.adapter = adap;
 	for (i = 0; -1 != probe[i]; i++) {
 		c.addr = probe[i];
-		rc = i2c_master_recv(&c,&buf,1);
+		rc = i2c_master_recv(&c,&buf,0);
 		dprintk(1,"probe 0x%02x @ %s: %s\n",
 			probe[i], adap->name,
-			(1 == rc) ? "yes" : "no");
-		if (1 == rc) {
+			(0 == rc) ? "yes" : "no");
+		if (0 == rc) {
 			ir_attach(adap,probe[i],0,0);
 			break;
 		}
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
index e75e794..a23fb03 100644
--- a/drivers/media/video/msp3400.c
+++ b/drivers/media/video/msp3400.c
@@ -54,9 +54,41 @@
 #include <asm/pgtable.h>
 
 #include <media/audiochip.h>
-#include <media/id.h>
 #include "msp3400.h"
 
+#define msp3400_dbg(fmt, arg...) \
+	do { \
+		if (debug) \
+			printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
+	} while (0)
+
+/* Medium volume debug. */
+#define msp3400_dbg_mediumvol(fmt, arg...) \
+	do { \
+		if (debug >= 2) \
+			printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+				i2c_adapter_id(client->adapter), client->addr , ## arg); \
+	} while (0)
+
+/* High volume debug. Use with care. */
+#define msp3400_dbg_highvol(fmt, arg...) \
+	do { \
+		if (debug >= 16) \
+			printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+				i2c_adapter_id(client->adapter), client->addr , ## arg); \
+	} while (0)
+
+#define msp3400_err(fmt, arg...) do { \
+	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define msp3400_warn(fmt, arg...) do { \
+	printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->name, \
+		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define msp3400_info(fmt, arg...) do { \
+	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
 #define OPMODE_AUTO    -1
 #define OPMODE_MANUAL   0
 #define OPMODE_SIMPLE   1   /* use short programming (>= msp3410 only) */
@@ -73,15 +105,26 @@
 
 static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
 					(msp34xxg only) 0x00a0-0x03c0 */
+#define DFP_COUNT 0x41
+static const int bl_dfp[] = {
+	0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a,
+	0x0b, 0x0d, 0x0e, 0x10
+};
+
+#define IS_MSP34XX_G(msp) ((msp)->opmode==2)
 
 struct msp3400c {
 	int rev1,rev2;
 
 	int opmode;
+	int nicam;
 	int mode;
 	int norm;
+	int stereo;
 	int nicam_on;
 	int acb;
+	int in_scart;
+	int i2s_mode;
 	int main, second;	/* sound carrier */
 	int input;
 	int source;             /* see msp34xxg_set_source */
@@ -91,9 +134,12 @@
 	int rxsubchans;
 
 	int muted;
-	int volume, balance;
+	int left, right;        /* volume */
 	int bass, treble;
 
+	/* shadow register set */
+	int dfp_regs[DFP_COUNT];
+
 	/* thread */
 	struct task_struct   *kthread;
 	wait_queue_head_t    wq;
@@ -101,6 +147,8 @@
 	int                  watch_stereo:1;
 };
 
+#define MIN(a,b) (((a)>(b))?(b):(a))
+#define MAX(a,b) (((a)>(b))?(a):(b))
 #define HAVE_NICAM(msp)   (((msp->rev2>>8) & 0xff) != 00)
 #define HAVE_SIMPLE(msp)  ((msp->rev1      & 0xff) >= 'D'-'@')
 #define HAVE_SIMPLER(msp) ((msp->rev1      & 0xff) >= 'G'-'@')
@@ -110,9 +158,6 @@
 
 /* ---------------------------------------------------------------------- */
 
-#define dprintk      if (debug >= 1) printk
-#define d2printk     if (debug >= 2) printk
-
 /* read-only */
 module_param(opmode,           int, 0444);
 
@@ -132,11 +177,6 @@
 MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
 MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
 
-
-MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("Dual BSD/GPL"); /* FreeBSD uses this too */
-
 /* ---------------------------------------------------------------------- */
 
 #define I2C_MSP3400C       0x80
@@ -153,6 +193,10 @@
 };
 I2C_CLIENT_INSMOD;
 
+MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
 /* ----------------------------------------------------------------------- */
 /* functions for talking to the MSP3400C Sound processor                   */
 
@@ -172,68 +216,73 @@
 		{ client->addr, I2C_M_RD, 2, read  },
 	};
 
+	msp3400_dbg_highvol("msp3400c_reset\n");
 	if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) ||
 	     (1 != i2c_transfer(client->adapter,&reset[1],1)) ||
 	     (2 != i2c_transfer(client->adapter,test,2)) ) {
-		printk(KERN_ERR "msp3400: chip reset failed\n");
+		msp3400_err("chip reset failed\n");
 		return -1;
-        }
+	}
 	return 0;
 }
 
-static int
-msp3400c_read(struct i2c_client *client, int dev, int addr)
+static int msp3400c_read(struct i2c_client *client, int dev, int addr)
 {
-	int err;
+	int err,retval;
 
-        unsigned char write[3];
-        unsigned char read[2];
-        struct i2c_msg msgs[2] = {
-                { client->addr, 0,        3, write },
-                { client->addr, I2C_M_RD, 2, read  }
-        };
-        write[0] = dev+1;
-        write[1] = addr >> 8;
-        write[2] = addr & 0xff;
+	unsigned char write[3];
+	unsigned char read[2];
+	struct i2c_msg msgs[2] = {
+		{ client->addr, 0,        3, write },
+		{ client->addr, I2C_M_RD, 2, read  }
+	};
+
+	write[0] = dev+1;
+	write[1] = addr >> 8;
+	write[2] = addr & 0xff;
 
 	for (err = 0; err < 3;) {
 		if (2 == i2c_transfer(client->adapter,msgs,2))
 			break;
 		err++;
-		printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n",
-		       err, dev, addr);
-		msleep(10);
+		msp3400_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err,
+		       dev, addr);
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(msecs_to_jiffies(10));
 	}
 	if (3 == err) {
-		printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n");
+		msp3400_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n");
 		msp3400c_reset(client);
 		return -1;
 	}
-	return read[0] << 8 | read[1];
+	retval = read[0] << 8 | read[1];
+	msp3400_dbg_highvol("msp3400c_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
+	return retval;
 }
 
-static int
-msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
+static int msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
 {
 	int err;
-        unsigned char buffer[5];
+	unsigned char buffer[5];
 
-        buffer[0] = dev;
-        buffer[1] = addr >> 8;
-        buffer[2] = addr &  0xff;
-        buffer[3] = val  >> 8;
-        buffer[4] = val  &  0xff;
+	buffer[0] = dev;
+	buffer[1] = addr >> 8;
+	buffer[2] = addr &  0xff;
+	buffer[3] = val  >> 8;
+	buffer[4] = val  &  0xff;
 
+	msp3400_dbg_highvol("msp3400c_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
 	for (err = 0; err < 3;) {
 		if (5 == i2c_master_send(client, buffer, 5))
 			break;
 		err++;
-		printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n",
-		       err, dev, addr);
-		msleep(10);
+		msp3400_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err,
+		       dev, addr);
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(msecs_to_jiffies(10));
 	}
 	if (3 == err) {
-		printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n");
+		msp3400_warn("giving up, reseting chip. Sound will go off, sorry folks :-|\n");
 		msp3400c_reset(client);
 		return -1;
 	}
@@ -266,45 +315,47 @@
 	int dfp_src;
 	int dfp_matrix;
 } msp_init_data[] = {
-	/* AM (for carrier detect / msp3400) */
-	{ { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 },
-	  MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-	  0x00d0, 0x0500,   0x0020, 0x3000},
-
-	/* AM (for carrier detect / msp3410) */
-	{ { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 },
-	  MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-	  0x00d0, 0x0100,   0x0020, 0x3000},
-
-	/* FM Radio */
-	{ { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 },
-	  MSP_CARRIER(10.7), MSP_CARRIER(10.7),
-	  0x00d0, 0x0480, 0x0020, 0x3000 },
-
-	/* Terrestial FM-mono + FM-stereo */
-	{ {  3, 18, 27, 48, 66, 72 }, {  3, 18, 27, 48, 66, 72 },
-	  MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-	  0x00d0, 0x0480,   0x0030, 0x3000},
-
-	/* Sat FM-mono */
-	{ {  1,  9, 14, 24, 33, 37 }, {  3, 18, 27, 48, 66, 72 },
-	  MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-	  0x00c6, 0x0480,   0x0000, 0x3000},
-
-	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
-	{ { -2, -8, -10, 10, 50, 86 }, {  3, 18, 27, 48, 66, 72 },
-	  MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-	  0x00d0, 0x0040,   0x0120, 0x3000},
-
-	/* NICAM/FM -- I (6.0/6.552) */
-	{ {  2, 4, -6, -4, 40, 94 }, {  3, 18, 27, 48, 66, 72 },
-	  MSP_CARRIER(6.0), MSP_CARRIER(6.0),
-	  0x00d0, 0x0040,   0x0120, 0x3000},
-
-	/* NICAM/AM -- L (6.5/5.85) */
-	{ {  -2, -8, -10, 10, 50, 86 }, {  -4, -12, -9, 23, 79, 126 },
-	  MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-	  0x00c6, 0x0140,   0x0120, 0x7c03},
+	{	/* AM (for carrier detect / msp3400) */
+		{75, 19, 36, 35, 39, 40},
+		{75, 19, 36, 35, 39, 40},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0500, 0x0020, 0x3000
+	},{	/* AM (for carrier detect / msp3410) */
+		{-1, -1, -8, 2, 59, 126},
+		{-1, -1, -8, 2, 59, 126},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0100, 0x0020, 0x3000
+	},{	/* FM Radio */
+		{-8, -8, 4, 6, 78, 107},
+		{-8, -8, 4, 6, 78, 107},
+		MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+		0x00d0, 0x0480, 0x0020, 0x3000
+	},{	/* Terrestial FM-mono + FM-stereo */
+		{3, 18, 27, 48, 66, 72},
+		{3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0480, 0x0030, 0x3000
+	},{	/* Sat FM-mono */
+		{ 1, 9, 14, 24, 33, 37},
+		{ 3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+		0x00c6, 0x0480, 0x0000, 0x3000
+	},{	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
+		{-2, -8, -10, 10, 50, 86},
+		{3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0040, 0x0120, 0x3000
+	},{	/* NICAM/FM -- I (6.0/6.552) */
+		{2, 4, -6, -4, 40, 94},
+		{3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(6.0), MSP_CARRIER(6.0),
+		0x00d0, 0x0040, 0x0120, 0x3000
+	},{	/* NICAM/AM -- L (6.5/5.85) */
+		{-2, -8, -10, 10, 50, 86},
+		{-4, -12, -9, 23, 79, 126},
+		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+		0x00c6, 0x0140, 0x0120, 0x7c03
+	},
 };
 
 struct CARRIER_DETECT {
@@ -338,32 +389,68 @@
 
 #define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
 
-/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- *
+ * bits  9  8  5 - SCART DSP input Select:
+ *       0  0  0 - SCART 1 to DSP input (reset position)
+ *       0  1  0 - MONO to DSP input
+ *       1  0  0 - SCART 2 to DSP input
+ *       1  1  1 - Mute DSP input
+ *
+ * bits 11 10  6 - SCART 1 Output Select:
+ *       0  0  0 - undefined (reset position)
+ *       0  1  0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
+ *       1  0  0 - MONO input to SCART 1 Output
+ *       1  1  0 - SCART 1 DA to SCART 1 Output
+ *       0  0  1 - SCART 2 DA to SCART 1 Output
+ *       0  1  1 - SCART 1 Input to SCART 1 Output
+ *       1  1  1 - Mute SCART 1 Output
+ *
+ * bits 13 12  7 - SCART 2 Output Select (for devices with 2 Output SCART):
+ *       0  0  0 - SCART 1 DA to SCART 2 Output (reset position)
+ *       0  1  0 - SCART 1 Input to SCART 2 Output
+ *       1  0  0 - MONO input to SCART 2 Output
+ *       0  0  1 - SCART 2 DA to SCART 2 Output
+ *       0  1  1 - SCART 2 Input to SCART 2 Output
+ *       1  1  0 - Mute SCART 2 Output
+ *
+ * Bits 4 to 0 should be zero.
+ * ----------------------------------------------------------------------- */
 
 static int scarts[3][9] = {
-  /* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
-  {  0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
-  {  0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
-  {  0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+	/* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
+	/* SCART DSP Input select */
+	{ 0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
+	/* SCART1 Output select */
+	{ 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+	/* SCART2 Output select */
+	{ 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
 };
 
 static char *scart_names[] = {
-  "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+	"mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
 };
 
-static void
-msp3400c_set_scart(struct i2c_client *client, int in, int out)
+static void msp3400c_set_scart(struct i2c_client *client, int in, int out)
 {
 	struct msp3400c *msp = i2c_get_clientdata(client);
 
-	if (-1 == scarts[out][in])
-		return;
+	msp->in_scart=in;
 
-	dprintk(KERN_DEBUG
-		"msp34xx: scart switch: %s => %d\n",scart_names[in],out);
-	msp->acb &= ~scarts[out][SCART_MASK];
-	msp->acb |=  scarts[out][in];
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb);
+	if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
+		if (-1 == scarts[out][in])
+			return;
+
+		msp->acb &= ~scarts[out][SCART_MASK];
+		msp->acb |=  scarts[out][in];
+	} else
+		msp->acb = 0xf60; /* Mute Input and SCART 1 Output */
+
+	msp3400_dbg("scart switch: %s => %d (ACB=0x%04x)\n",
+						scart_names[in], out, msp->acb);
+	msp3400c_write(client,I2C_MSP3400C_DFP, 0x13, msp->acb);
+
+	/* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
+	msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
 }
 
 /* ------------------------------------------------------------------------ */
@@ -378,33 +465,34 @@
 }
 
 static void msp3400c_setvolume(struct i2c_client *client,
-			       int muted, int volume, int balance)
-{
-	int val = 0, bal = 0;
+			       int muted, int left, int right)
+ {
+	int vol = 0, val = 0, balance = 0;
 
 	if (!muted) {
 		/* 0x7f instead if 0x73 here has sound quality issues,
 		 * probably due to overmodulation + clipping ... */
-		val = (volume * 0x73 / 65535) << 8;
+		vol = (left > right) ? left : right;
+		val = (vol * 0x73 / 65535) << 8;
 	}
-	if (val) {
-		bal = (balance / 256) - 128;
+	if (vol > 0) {
+		balance = ((right - left) * 127) / vol;
 	}
-	dprintk(KERN_DEBUG
-		"msp34xx: setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
-		muted ? "on" : "off", volume, balance, val>>8, bal);
+
+	msp3400_dbg("setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
+		muted ? "on" : "off", left, right, val >> 8, balance);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones  */
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007,
-		       muted ? 0x01 : (val | 0x01));
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, bal << 8);
+					muted ? 0x1 : (val | 0x1));
+	msp3400c_write(client, I2C_MSP3400C_DFP, 0x0001, balance << 8);
 }
 
 static void msp3400c_setbass(struct i2c_client *client, int bass)
 {
 	int val = ((bass-32768) * 0x60 / 65535) << 8;
 
-	dprintk(KERN_DEBUG "msp34xx: setbass: %d 0x%02x\n",bass, val>>8);
+	msp3400_dbg("setbass: %d 0x%02x\n", bass, val >> 8);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
 }
 
@@ -412,7 +500,7 @@
 {
 	int val = ((treble-32768) * 0x60 / 65535) << 8;
 
-	dprintk(KERN_DEBUG "msp34xx: settreble: %d 0x%02x\n",treble, val>>8);
+	msp3400_dbg("settreble: %d 0x%02x\n",treble, val>>8);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
 }
 
@@ -421,7 +509,7 @@
 	struct msp3400c *msp = i2c_get_clientdata(client);
 	int i;
 
-	dprintk(KERN_DEBUG "msp3400: setmode: %d\n",type);
+	msp3400_dbg("setmode: %d\n",type);
 	msp->mode       = type;
 	msp->audmode    = V4L2_TUNER_MODE_MONO;
 	msp->rxsubchans = V4L2_TUNER_SUB_MONO;
@@ -474,7 +562,8 @@
 	}
 }
 
-static int best_audio_mode(int rxsubchans)
+/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */
+static int best_video_sound(int rxsubchans)
 {
 	if (rxsubchans & V4L2_TUNER_SUB_STEREO)
 		return V4L2_TUNER_MODE_STEREO;
@@ -486,31 +575,31 @@
 }
 
 /* turn on/off nicam + stereo */
-static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
+static void msp3400c_setstereo(struct i2c_client *client, int mode)
 {
-	static char *strmode[16] = {
-#if __GNUC__ >= 3
-		[ 0 ... 15 ]               = "invalid",
-#endif
-		[ V4L2_TUNER_MODE_MONO   ] = "mono",
-		[ V4L2_TUNER_MODE_STEREO ] = "stereo",
-		[ V4L2_TUNER_MODE_LANG1  ] = "lang1",
-		[ V4L2_TUNER_MODE_LANG2  ] = "lang2",
+	static char *strmode[] = { "0", "mono", "stereo", "3",
+		"lang1", "5", "6", "7", "lang2"
 	};
 	struct msp3400c *msp = i2c_get_clientdata(client);
-	int nicam=0; /* channel source: FM/AM or nicam */
-	int src=0;
+	int nicam = 0;		/* channel source: FM/AM or nicam */
+	int src = 0;
 
-	BUG_ON(msp->opmode == OPMODE_SIMPLER);
-	msp->audmode = audmode;
+	if (IS_MSP34XX_G(msp)) {
+		/* this method would break everything, let's make sure
+		 * it's never called
+		 */
+		msp3400_dbg
+		    ("DEBUG WARNING setstereo called with mode=%d instead of set_source (ignored)\n",
+		     mode);
+		return;
+	}
 
 	/* switch demodulator */
 	switch (msp->mode) {
 	case MSP_MODE_FM_TERRA:
-		dprintk(KERN_DEBUG "msp3400: FM setstereo: %s\n",
-			strmode[audmode]);
+		msp3400_dbg("FM setstereo: %s\n", strmode[mode]);
 		msp3400c_setcarrier(client,msp->second,msp->main);
-		switch (audmode) {
+		switch (mode) {
 		case V4L2_TUNER_MODE_STEREO:
 			msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001);
 			break;
@@ -522,9 +611,8 @@
 		}
 		break;
 	case MSP_MODE_FM_SAT:
-		dprintk(KERN_DEBUG "msp3400: SAT setstereo: %s\n",
-			strmode[audmode]);
-		switch (audmode) {
+		msp3400_dbg("SAT setstereo: %s\n", strmode[mode]);
+		switch (mode) {
 		case V4L2_TUNER_MODE_MONO:
 			msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
 			break;
@@ -542,39 +630,35 @@
 	case MSP_MODE_FM_NICAM1:
 	case MSP_MODE_FM_NICAM2:
 	case MSP_MODE_AM_NICAM:
-		dprintk(KERN_DEBUG "msp3400: NICAM setstereo: %s\n",
-			strmode[audmode]);
+		msp3400_dbg("NICAM setstereo: %s\n",strmode[mode]);
 		msp3400c_setcarrier(client,msp->second,msp->main);
 		if (msp->nicam_on)
 			nicam=0x0100;
 		break;
 	case MSP_MODE_BTSC:
-		dprintk(KERN_DEBUG "msp3400: BTSC setstereo: %s\n",
-			strmode[audmode]);
+		msp3400_dbg("BTSC setstereo: %s\n",strmode[mode]);
 		nicam=0x0300;
 		break;
 	case MSP_MODE_EXTERN:
-		dprintk(KERN_DEBUG "msp3400: extern setstereo: %s\n",
-			strmode[audmode]);
+		msp3400_dbg("extern setstereo: %s\n",strmode[mode]);
 		nicam = 0x0200;
 		break;
 	case MSP_MODE_FM_RADIO:
-		dprintk(KERN_DEBUG "msp3400: FM-Radio setstereo: %s\n",
-			strmode[audmode]);
+		msp3400_dbg("FM-Radio setstereo: %s\n",strmode[mode]);
 		break;
 	default:
-		dprintk(KERN_DEBUG "msp3400: mono setstereo\n");
+		msp3400_dbg("mono setstereo\n");
 		return;
 	}
 
 	/* switch audio */
-	switch (audmode) {
+	switch (best_video_sound(mode)) {
 	case V4L2_TUNER_MODE_STEREO:
 		src = 0x0020 | nicam;
 		break;
 	case V4L2_TUNER_MODE_MONO:
 		if (msp->mode == MSP_MODE_AM_NICAM) {
-			dprintk("msp3400: switching to AM mono\n");
+			msp3400_dbg("switching to AM mono\n");
 			/* AM mono decoding is handled by tuner, not MSP chip */
 			/* SCART switching control register */
 			msp3400c_set_scart(client,SCART_MONO,0);
@@ -588,8 +672,7 @@
 		src = 0x0010 | nicam;
 		break;
 	}
-	dprintk(KERN_DEBUG
-		"msp3400: setstereo final source/matrix = 0x%x\n", src);
+	msp3400_dbg("setstereo final source/matrix = 0x%x\n", src);
 
 	if (dolby) {
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
@@ -605,29 +688,55 @@
 }
 
 static void
-msp3400c_print_mode(struct msp3400c *msp)
+msp3400c_print_mode(struct i2c_client *client)
 {
+	struct msp3400c *msp = i2c_get_clientdata(client);
+
 	if (msp->main == msp->second) {
-		printk(KERN_DEBUG "msp3400: mono sound carrier: %d.%03d MHz\n",
+		msp3400_dbg("mono sound carrier: %d.%03d MHz\n",
 		       msp->main/910000,(msp->main/910)%1000);
 	} else {
-		printk(KERN_DEBUG "msp3400: main sound carrier: %d.%03d MHz\n",
+		msp3400_dbg("main sound carrier: %d.%03d MHz\n",
 		       msp->main/910000,(msp->main/910)%1000);
 	}
-	if (msp->mode == MSP_MODE_FM_NICAM1 ||
-	    msp->mode == MSP_MODE_FM_NICAM2)
-		printk(KERN_DEBUG "msp3400: NICAM/FM carrier   : %d.%03d MHz\n",
+	if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2)
+		msp3400_dbg("NICAM/FM carrier   : %d.%03d MHz\n",
 		       msp->second/910000,(msp->second/910)%1000);
 	if (msp->mode == MSP_MODE_AM_NICAM)
-		printk(KERN_DEBUG "msp3400: NICAM/AM carrier   : %d.%03d MHz\n",
+		msp3400_dbg("NICAM/AM carrier   : %d.%03d MHz\n",
 		       msp->second/910000,(msp->second/910)%1000);
 	if (msp->mode == MSP_MODE_FM_TERRA &&
 	    msp->main != msp->second) {
-		printk(KERN_DEBUG "msp3400: FM-stereo carrier : %d.%03d MHz\n",
+		msp3400_dbg("FM-stereo carrier : %d.%03d MHz\n",
 		       msp->second/910000,(msp->second/910)%1000);
 	}
 }
 
+#define MSP3400_MAX 4
+static struct i2c_client *msps[MSP3400_MAX];
+static void msp3400c_restore_dfp(struct i2c_client *client)
+{
+	struct msp3400c *msp = i2c_get_clientdata(client);
+	int i;
+
+	for (i = 0; i < DFP_COUNT; i++) {
+		if (-1 == msp->dfp_regs[i])
+			continue;
+		msp3400c_write(client, I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
+	}
+}
+
+/* if the dfp_regs is set, set what's in there. Otherwise, set the default value */
+static int msp3400c_write_dfp_with_default(struct i2c_client *client,
+					int addr, int default_value)
+{
+	struct msp3400c *msp = i2c_get_clientdata(client);
+	int value = default_value;
+	if (addr < DFP_COUNT && -1 != msp->dfp_regs[addr])
+		value = msp->dfp_regs[addr];
+	return msp3400c_write(client, I2C_MSP3400C_DFP, addr, value);
+}
+
 /* ----------------------------------------------------------------------- */
 
 struct REGISTER_DUMP {
@@ -635,8 +744,15 @@
 	char *name;
 };
 
-static int
-autodetect_stereo(struct i2c_client *client)
+struct REGISTER_DUMP d1[] = {
+	{0x007e, "autodetect"},
+	{0x0023, "C_AD_BITS "},
+	{0x0038, "ADD_BITS  "},
+	{0x003e, "CIB_BITS  "},
+	{0x0057, "ERROR_RATE"},
+};
+
+static int autodetect_stereo(struct i2c_client *client)
 {
 	struct msp3400c *msp = i2c_get_clientdata(client);
 	int val;
@@ -649,8 +765,7 @@
 		val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
 		if (val > 32767)
 			val -= 65536;
-		dprintk(KERN_DEBUG
-			"msp34xx: stereo detect register: %d\n",val);
+		msp3400_dbg("stereo detect register: %d\n",val);
 		if (val > 4096) {
 			rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
 		} else if (val < -4096) {
@@ -664,8 +779,7 @@
 	case MSP_MODE_FM_NICAM2:
 	case MSP_MODE_AM_NICAM:
 		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
-		dprintk(KERN_DEBUG
-			"msp34xx: nicam sync=%d, mode=%d\n",
+		msp3400_dbg("nicam sync=%d, mode=%d\n",
 			val & 1, (val & 0x1e) >> 1);
 
 		if (val & 1) {
@@ -698,8 +812,7 @@
 		break;
 	case MSP_MODE_BTSC:
 		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
-		dprintk(KERN_DEBUG
-			"msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+		msp3400_dbg("status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
 			val,
 			(val & 0x0002) ? "no"     : "yes",
 			(val & 0x0004) ? "no"     : "yes",
@@ -713,13 +826,13 @@
 	}
 	if (rxsubchans != msp->rxsubchans) {
 		update = 1;
-		dprintk(KERN_DEBUG "msp34xx: watch: rxsubchans %d => %d\n",
+		msp3400_dbg("watch: rxsubchans %d => %d\n",
 			msp->rxsubchans,rxsubchans);
 		msp->rxsubchans = rxsubchans;
 	}
 	if (newnicam != msp->nicam_on) {
 		update = 1;
-		dprintk(KERN_DEBUG "msp34xx: watch: nicam %d => %d\n",
+		msp3400_dbg("watch: nicam %d => %d\n",
 			msp->nicam_on,newnicam);
 		msp->nicam_on = newnicam;
 	}
@@ -756,8 +869,15 @@
 {
 	struct msp3400c *msp = i2c_get_clientdata(client);
 
-	if (autodetect_stereo(client))
-		msp3400c_set_audmode(client,best_audio_mode(msp->rxsubchans));
+	if (autodetect_stereo(client)) {
+		if (msp->stereo & V4L2_TUNER_MODE_STEREO)
+			msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
+		else if (msp->stereo & VIDEO_SOUND_LANG1)
+			msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
+		else
+			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+	}
+
 	if (once)
 		msp->watch_stereo = 0;
 }
@@ -769,14 +889,14 @@
 	struct CARRIER_DETECT *cd;
 	int count, max1,max2,val1,val2, val,this;
 
-	printk("msp3400: kthread started\n");
+	msp3400_info("msp3400 daemon started\n");
 	for (;;) {
-		d2printk("msp3400: thread: sleep\n");
+		msp3400_dbg_mediumvol("msp3400 thread: sleep\n");
 		msp34xx_sleep(msp,-1);
-		d2printk("msp3400: thread: wakeup\n");
+		msp3400_dbg_mediumvol("msp3400 thread: wakeup\n");
 
 	restart:
-		dprintk("msp3410: thread: restart scan\n");
+		msp3400_dbg("thread: restart scan\n");
 		msp->restart = 0;
 		if (kthread_should_stop())
 			break;
@@ -784,9 +904,8 @@
 		if (VIDEO_MODE_RADIO == msp->norm ||
 		    MSP_MODE_EXTERN  == msp->mode) {
 			/* no carrier scan, just unmute */
-			printk("msp3400: thread: no carrier scan\n");
-			msp3400c_setvolume(client, msp->muted,
-					   msp->volume, msp->balance);
+			msp3400_info("thread: no carrier scan\n");
+			msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
 			continue;
 		}
 
@@ -802,13 +921,14 @@
 			goto restart;
 
 		/* carrier detect pass #1 -- main carrier */
-		cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main);
+		cd = carrier_detect_main;
+		count = CARRIER_COUNT(carrier_detect_main);
 
 		if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
 			/* autodetect doesn't work well with AM ... */
 			max1 = 3;
 			count = 0;
-			dprintk("msp3400: AM sound override\n");
+			msp3400_dbg("AM sound override\n");
 		}
 
 		for (this = 0; this < count; this++) {
@@ -820,7 +940,7 @@
 				val -= 65536;
 			if (val1 < val)
 				val1 = val, max1 = this;
-			dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name);
+			msp3400_dbg("carrier1 val: %5d / %s\n", val,cd[this].name);
 		}
 
 		/* carrier detect pass #2 -- second (stereo) carrier */
@@ -836,13 +956,16 @@
 		case 0: /* 4.5 */
 		case 2: /* 6.0 */
 		default:
-			cd = NULL; count = 0;
+			cd = NULL;
+			count = 0;
 			break;
 		}
 
 		if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
 			/* autodetect doesn't work well with AM ... */
-			cd = NULL; count = 0; max2 = 0;
+			cd = NULL;
+			count = 0;
+			max2 = 0;
 		}
 		for (this = 0; this < count; this++) {
 			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
@@ -853,7 +976,7 @@
 				val -= 65536;
 			if (val2 < val)
 				val2 = val, max2 = this;
-			dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name);
+			msp3400_dbg("carrier2 val: %5d / %s\n", val,cd[this].name);
 		}
 
 		/* programm the msp3400 according to the results */
@@ -865,7 +988,7 @@
 				msp->second = carrier_detect_55[max2].cdo;
 				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
 				msp->nicam_on = 0;
-				msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
 				msp->watch_stereo = 1;
 			} else if (max2 == 1 && HAVE_NICAM(msp)) {
 				/* B/G NICAM */
@@ -892,7 +1015,7 @@
 				msp->second = carrier_detect_65[max2].cdo;
 				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
 				msp->nicam_on = 0;
-				msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
 				msp->watch_stereo = 1;
 			} else if (max2 == 0 &&
 				   msp->norm == VIDEO_MODE_SECAM) {
@@ -900,7 +1023,7 @@
 				msp->second = carrier_detect_65[max2].cdo;
 				msp3400c_setmode(client, MSP_MODE_AM_NICAM);
 				msp->nicam_on = 0;
-				msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
 				msp3400c_setcarrier(client, msp->second, msp->main);
 				/* volume prescale for SCART (AM mono input) */
 				msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
@@ -924,15 +1047,16 @@
 			msp->nicam_on = 0;
 			msp3400c_setcarrier(client, msp->second, msp->main);
 			msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-			msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
 			break;
 		}
 
 		/* unmute */
-		msp3400c_setvolume(client, msp->muted,
-				   msp->volume, msp->balance);
+		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+		msp3400c_restore_dfp(client);
+
 		if (debug)
-			msp3400c_print_mode(msp);
+			msp3400c_print_mode(client);
 
 		/* monitor tv audio mode */
 		while (msp->watch_stereo) {
@@ -941,7 +1065,7 @@
 			watch_stereo(client);
 		}
 	}
-	dprintk(KERN_DEBUG "msp3400: thread: exit\n");
+	msp3400_dbg("thread: exit\n");
 	return 0;
 }
 
@@ -985,10 +1109,12 @@
 	return "unknown";
 }
 
-static int msp34xx_modus(int norm)
+static int msp34xx_modus(struct i2c_client *client, int norm)
 {
 	switch (norm) {
 	case VIDEO_MODE_PAL:
+		msp3400_dbg("video mode selected to PAL\n");
+
 #if 1
 		/* experimental: not sure this works with all chip versions */
 		return 0x7003;
@@ -997,12 +1123,16 @@
 		return 0x1003;
 #endif
 	case VIDEO_MODE_NTSC:  /* BTSC */
+		msp3400_dbg("video mode selected to NTSC\n");
 		return 0x2003;
 	case VIDEO_MODE_SECAM:
+		msp3400_dbg("video mode selected to SECAM\n");
 		return 0x0003;
 	case VIDEO_MODE_RADIO:
+		msp3400_dbg("video mode selected to Radio\n");
 		return 0x0003;
 	case VIDEO_MODE_AUTO:
+		msp3400_dbg("video mode selected to Auto\n");
 		return 0x2003;
 	default:
 		return 0x0003;
@@ -1031,23 +1161,22 @@
 	struct msp3400c *msp = i2c_get_clientdata(client);
 	int mode,val,i,std;
 
-	printk("msp3410: daemon started\n");
+	msp3400_info("msp3410 daemon started\n");
 	for (;;) {
-		d2printk(KERN_DEBUG "msp3410: thread: sleep\n");
+		msp3400_dbg_mediumvol("msp3410 thread: sleep\n");
 		msp34xx_sleep(msp,-1);
-		d2printk(KERN_DEBUG "msp3410: thread: wakeup\n");
+		msp3400_dbg_mediumvol("msp3410 thread: wakeup\n");
 
 	restart:
-		dprintk("msp3410: thread: restart scan\n");
+		msp3400_dbg("thread: restart scan\n");
 		msp->restart = 0;
 		if (kthread_should_stop())
 			break;
 
 		if (msp->mode == MSP_MODE_EXTERN) {
 			/* no carrier scan needed, just unmute */
-			dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n");
-			msp3400c_setvolume(client, msp->muted,
-					   msp->volume, msp->balance);
+			msp3400_dbg("thread: no carrier scan\n");
+		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
 			continue;
 		}
 
@@ -1059,14 +1188,14 @@
 			goto restart;
 
 		/* start autodetect */
-		mode = msp34xx_modus(msp->norm);
+		mode = msp34xx_modus(client, msp->norm);
 		std  = msp34xx_standard(msp->norm);
 		msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
 		msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);
 		msp->watch_stereo = 0;
 
 		if (debug)
-			printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n",
+			msp3400_dbg("setting mode: %s (0x%04x)\n",
 			       msp34xx_standard_mode_name(std) ,std);
 
 		if (std != 1) {
@@ -1082,13 +1211,13 @@
 				val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
 				if (val < 0x07ff)
 					break;
-				dprintk(KERN_DEBUG "msp3410: detection still in progress\n");
+				msp3400_dbg("detection still in progress\n");
 			}
 		}
 		for (i = 0; modelist[i].name != NULL; i++)
 			if (modelist[i].retval == val)
 				break;
-		dprintk(KERN_DEBUG "msp3410: current mode: %s (0x%04x)\n",
+		msp3400_dbg("current mode: %s (0x%04x)\n",
 			modelist[i].name ? modelist[i].name : "unknown",
 			val);
 		msp->main   = modelist[i].main;
@@ -1096,7 +1225,7 @@
 
 		if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
 			/* autodetection has failed, let backup */
-			dprintk(KERN_DEBUG "msp3410: autodetection failed,"
+			msp3400_dbg("autodetection failed,"
 				" switching to backup mode: %s (0x%04x)\n",
 				modelist[8].name ? modelist[8].name : "unknown",val);
 			val = 0x0009;
@@ -1120,13 +1249,13 @@
 			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
 			msp->nicam_on = 1;
 			msp->watch_stereo = 1;
-			msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);
+			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
 			break;
 		case 0x0009:
 			msp->mode = MSP_MODE_AM_NICAM;
 			msp->rxsubchans = V4L2_TUNER_SUB_MONO;
 			msp->nicam_on = 1;
-			msp3400c_set_audmode(client,V4L2_TUNER_MODE_MONO);
+			msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
 			msp->watch_stereo = 1;
 			break;
 		case 0x0020: /* BTSC */
@@ -1135,7 +1264,7 @@
 			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
 			msp->nicam_on = 0;
 			msp->watch_stereo = 1;
-			msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);
+			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
 			break;
 		case 0x0040: /* FM radio */
 			msp->mode   = MSP_MODE_FM_RADIO;
@@ -1169,9 +1298,10 @@
 		/* unmute, restore misc registers */
 		msp3400c_setbass(client, msp->bass);
 		msp3400c_settreble(client, msp->treble);
-		msp3400c_setvolume(client, msp->muted,
-				    msp->volume, msp->balance);
-		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb);
+		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+		msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb);
+		msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
+		msp3400c_restore_dfp(client);
 
 		/* monitor tv audio mode */
 		while (msp->watch_stereo) {
@@ -1180,7 +1310,7 @@
 			watch_stereo(client);
 		}
 	}
-	dprintk(KERN_DEBUG "msp3410: thread: exit\n");
+	msp3400_dbg("thread: exit\n");
 	return 0;
 }
 
@@ -1195,7 +1325,7 @@
 /* (re-)initialize the msp34xxg, according to the current norm in msp->norm
  * return 0 if it worked, -1 if it failed
  */
-static int msp34xxg_init(struct i2c_client *client)
+static int msp34xxg_reset(struct i2c_client *client)
 {
 	struct msp3400c *msp = i2c_get_clientdata(client);
 	int modus,std;
@@ -1210,8 +1340,10 @@
 			   0x0f20 /* mute DSP input, mute SCART 1 */))
 		return -1;
 
+	msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
+
 	/* step-by-step initialisation, as described in the manual */
-	modus = msp34xx_modus(msp->norm);
+	modus = msp34xx_modus(client, msp->norm);
 	std   = msp34xx_standard(msp->norm);
 	modus &= ~0x03; /* STATUS_CHANGE=0 */
 	modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION=1 */
@@ -1222,7 +1354,7 @@
 		return -1;
 	if (msp3400c_write(client,
 			   I2C_MSP3400C_DEM,
-			   0x20/*stanard*/,
+			   0x20/*standard*/,
 			   std))
 		return -1;
 
@@ -1230,21 +1362,18 @@
 	   standard/audio autodetection right now */
 	msp34xxg_set_source(client, msp->source);
 
-	if (msp3400c_write(client, I2C_MSP3400C_DFP,
-			   0x0e, /* AM/FM Prescale */
-			   0x3000 /* default: [15:8] 75khz deviation */))
+	if (msp3400c_write_dfp_with_default(client, 0x0e,	/* AM/FM Prescale */
+					    0x3000
+					    /* default: [15:8] 75khz deviation */
+	    ))
 		return -1;
 
-	if (msp3400c_write(client, I2C_MSP3400C_DFP,
-			   0x10, /* NICAM Prescale */
-			   0x5a00 /* default: 9db gain (as recommended) */))
+	if (msp3400c_write_dfp_with_default(client, 0x10,	/* NICAM Prescale */
+					    0x5a00
+					    /* default: 9db gain (as recommended) */
+	    ))
 		return -1;
 
-	if (msp3400c_write(client,
-			   I2C_MSP3400C_DEM,
-			   0x20, /* STANDARD SELECT  */
-			   standard /* default: 0x01 for automatic standard select*/))
-		return -1;
 	return 0;
 }
 
@@ -1254,27 +1383,27 @@
 	struct msp3400c *msp = i2c_get_clientdata(client);
 	int val, std, i;
 
-	printk("msp34xxg: daemon started\n");
+	msp3400_info("msp34xxg daemon started\n");
 	msp->source = 1; /* default */
 	for (;;) {
-		d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n");
+		msp3400_dbg_mediumvol("msp34xxg thread: sleep\n");
 		msp34xx_sleep(msp,-1);
-		d2printk(KERN_DEBUG "msp34xxg: thread: wakeup\n");
+		msp3400_dbg_mediumvol("msp34xxg thread: wakeup\n");
 
 	restart:
-		dprintk("msp34xxg: thread: restart scan\n");
+		msp3400_dbg("thread: restart scan\n");
 		msp->restart = 0;
 		if (kthread_should_stop())
 			break;
 
 		/* setup the chip*/
-		msp34xxg_init(client);
+		msp34xxg_reset(client);
 		std = standard;
 		if (std != 0x01)
 			goto unmute;
 
 		/* watch autodetect */
-		dprintk("msp34xxg: triggered autodetect, waiting for result\n");
+		msp3400_dbg("triggered autodetect, waiting for result\n");
 		for (i = 0; i < 10; i++) {
 			if (msp34xx_sleep(msp,100))
 				goto restart;
@@ -1285,23 +1414,23 @@
 				std = val;
 				break;
 			}
-			dprintk("msp34xxg: detection still in progress\n");
+			msp3400_dbg("detection still in progress\n");
 		}
 		if (0x01 == std) {
-			dprintk("msp34xxg: detection still in progress after 10 tries. giving up.\n");
+			msp3400_dbg("detection still in progress after 10 tries. giving up.\n");
 			continue;
 		}
 
 	unmute:
-		dprintk("msp34xxg: current mode: %s (0x%04x)\n",
+		msp3400_dbg("current mode: %s (0x%04x)\n",
 			msp34xx_standard_mode_name(std), std);
 
 		/* unmute: dispatch sound to scart output, set scart volume */
-		dprintk("msp34xxg: unmute\n");
+		msp3400_dbg("unmute\n");
 
 		msp3400c_setbass(client, msp->bass);
 		msp3400c_settreble(client, msp->treble);
-		msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance);
+		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
 
 		/* restore ACB */
 		if (msp3400c_write(client,
@@ -1309,8 +1438,10 @@
 				   0x13, /* ACB */
 				   msp->acb))
 			return -1;
+
+		msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
 	}
-	dprintk(KERN_DEBUG "msp34xxg: thread: exit\n");
+	msp3400_dbg("thread: exit\n");
 	return 0;
 }
 
@@ -1329,7 +1460,7 @@
 	 * for MONO (source==0) downmixing set bit[7:0] to 0x30
 	 */
 	int value = (source&0x07)<<8|(source==0 ? 0x30:0x20);
-	dprintk("msp34xxg: set source to %d (0x%x)\n", source, value);
+	msp3400_dbg("set source to %d (0x%x)\n", source, value);
 	msp3400c_write(client,
 		       I2C_MSP3400C_DFP,
 		       0x08, /* Loudspeaker Output */
@@ -1380,7 +1511,7 @@
 		 * this is a problem, I'll handle SAP just like lang1/lang2.
 		 */
 	}
-	dprintk("msp34xxg: status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+	msp3400_dbg("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
 		status, is_stereo, is_bilingual, msp->rxsubchans);
 }
 
@@ -1427,7 +1558,7 @@
 
 static struct i2c_driver driver = {
 	.owner          = THIS_MODULE,
-	.name           = "i2c msp3400 driver",
+	.name           = "msp3400",
         .id             = I2C_DRIVERID_MSP3400,
         .flags          = I2C_DF_NOTIFY,
         .attach_adapter = msp_probe,
@@ -1449,57 +1580,64 @@
 static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
 {
 	struct msp3400c *msp;
-        struct i2c_client *c;
+	struct i2c_client *client = &client_template;
 	int (*thread_func)(void *data) = NULL;
+	int i;
 
-        client_template.adapter = adap;
-        client_template.addr = addr;
+	client_template.adapter = adap;
+	client_template.addr = addr;
 
-        if (-1 == msp3400c_reset(&client_template)) {
-                dprintk("msp34xx: no chip found\n");
-                return -1;
-        }
+	if (-1 == msp3400c_reset(&client_template)) {
+		msp3400_dbg("no chip found\n");
+		return -1;
+	}
 
-        if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
-                return -ENOMEM;
-        memcpy(c,&client_template,sizeof(struct i2c_client));
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
+		return -ENOMEM;
+	memcpy(client,&client_template,sizeof(struct i2c_client));
 	if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) {
-		kfree(c);
+		kfree(client);
 		return -ENOMEM;
 	}
 
 	memset(msp,0,sizeof(struct msp3400c));
-	msp->volume  = 58880;  /* 0db gain */
-	msp->balance = 32768;
-	msp->bass    = 32768;
-	msp->treble  = 32768;
-	msp->input   = -1;
-	msp->muted   = 1;
+	msp->norm = VIDEO_MODE_NTSC;
+	msp->left = 58880;	/* 0db gain */
+	msp->right = 58880;	/* 0db gain */
+	msp->bass = 32768;
+	msp->treble = 32768;
+	msp->input = -1;
+	msp->muted = 0;
+	msp->i2s_mode = 0;
+	for (i = 0; i < DFP_COUNT; i++)
+		msp->dfp_regs[i] = -1;
 
-	i2c_set_clientdata(c, msp);
+	i2c_set_clientdata(client, msp);
 	init_waitqueue_head(&msp->wq);
 
-	if (-1 == msp3400c_reset(c)) {
+	if (-1 == msp3400c_reset(client)) {
 		kfree(msp);
-		kfree(c);
-		dprintk("msp34xx: no chip found\n");
+		kfree(client);
+		msp3400_dbg("no chip found\n");
 		return -1;
 	}
 
-	msp->rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
+	msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e);
 	if (-1 != msp->rev1)
-		msp->rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
+		msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f);
 	if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
 		kfree(msp);
-		kfree(c);
-		dprintk("msp34xx: error while reading chip version\n");
+		kfree(client);
+		msp3400_dbg("error while reading chip version\n");
 		return -1;
 	}
+	msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2);
 
-	msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance);
+	msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
 
-	snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d",
-		 (msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@',
+	snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",
+		 ((msp->rev1>>4)&0x0f) + '3',
+		 (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@',
 		 ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);
 
 	msp->opmode = opmode;
@@ -1513,7 +1651,7 @@
 	}
 
 	/* hello world :-) */
-	printk(KERN_INFO "msp34xx: init: chip=%s", c->name);
+	msp3400_info("chip=%s", client->name);
 	if (HAVE_NICAM(msp))
 		printk(" +nicam");
 	if (HAVE_SIMPLE(msp))
@@ -1542,29 +1680,49 @@
 
 	/* startup control thread if needed */
 	if (thread_func) {
-		msp->kthread = kthread_run(thread_func, c, "msp34xx");
+		msp->kthread = kthread_run(thread_func, client, "msp34xx");
+
 		if (NULL == msp->kthread)
-			printk(KERN_WARNING "msp34xx: kernel_thread() failed\n");
-		msp_wake_thread(c);
+			msp3400_warn("kernel_thread() failed\n");
+		msp_wake_thread(client);
 	}
 
 	/* done */
-        i2c_attach_client(c);
+	i2c_attach_client(client);
+
+	/* update our own array */
+	for (i = 0; i < MSP3400_MAX; i++) {
+		if (NULL == msps[i]) {
+			msps[i] = client;
+			break;
+		}
+	}
+
 	return 0;
 }
 
 static int msp_detach(struct i2c_client *client)
 {
 	struct msp3400c *msp  = i2c_get_clientdata(client);
+	int i;
 
 	/* shutdown control thread */
-	if (msp->kthread >= 0) {
+	if (msp->kthread) {
 		msp->restart = 1;
 		kthread_stop(msp->kthread);
 	}
-    	msp3400c_reset(client);
+	msp3400c_reset(client);
+
+	/* update our own array */
+	for (i = 0; i < MSP3400_MAX; i++) {
+		if (client == msps[i]) {
+			msps[i] = NULL;
+			break;
+		}
+	}
 
 	i2c_detach_client(client);
+
 	kfree(msp);
 	kfree(client);
 	return 0;
@@ -1640,7 +1798,7 @@
 	case OPMODE_MANUAL:
 	case OPMODE_SIMPLE:
 		msp->watch_stereo = 0;
-		msp3400c_set_audmode(client, audmode);
+		msp3400c_setstereo(client, audmode);
 		break;
 	case OPMODE_SIMPLER:
 		msp34xxg_set_audmode(client, audmode);
@@ -1648,16 +1806,18 @@
 	}
 }
 
+
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct msp3400c *msp  = i2c_get_clientdata(client);
-        __u16           *sarg = arg;
+	__u16           *sarg = arg;
 	int scart = 0;
 
 	switch (cmd) {
 
 	case AUDC_SET_INPUT:
-		dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);
+		msp3400_dbg("AUDC_SET_INPUT(%d)\n",*sarg);
+
 		if (*sarg == msp->input)
 			break;
 		msp->input = *sarg;
@@ -1691,15 +1851,15 @@
 			msp3400c_set_scart(client,scart,0);
 			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
 			if (msp->opmode != OPMODE_SIMPLER)
-				msp3400c_set_audmode(client, msp->audmode);
+				msp3400c_setstereo(client, msp->audmode);
 		}
 		msp_wake_thread(client);
 		break;
 
 	case AUDC_SET_RADIO:
-		dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n");
+		msp3400_dbg("AUDC_SET_RADIO\n");
 		msp->norm = VIDEO_MODE_RADIO;
-		dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n");
+		msp3400_dbg("switching to radio mode\n");
 		msp->watch_stereo = 0;
 		switch (msp->opmode) {
 		case OPMODE_MANUAL:
@@ -1707,8 +1867,7 @@
 			msp3400c_setmode(client,MSP_MODE_FM_RADIO);
 			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
 					    MSP_CARRIER(10.7));
-			msp3400c_setvolume(client, msp->muted,
-					   msp->volume, msp->balance);
+			msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
 			break;
 		case OPMODE_SIMPLE:
 		case OPMODE_SIMPLER:
@@ -1717,6 +1876,30 @@
 			break;
 		}
 		break;
+		/* work-in-progress:  hook to control the DFP registers */
+	case MSP_SET_DFPREG:
+	{
+		struct msp_dfpreg *r = arg;
+		int i;
+
+		if (r->reg < 0 || r->reg >= DFP_COUNT)
+			return -EINVAL;
+		for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++)
+			if (r->reg == bl_dfp[i])
+				return -EINVAL;
+		msp->dfp_regs[r->reg] = r->value;
+		msp3400c_write(client, I2C_MSP3400C_DFP, r->reg, r->value);
+		return 0;
+	}
+	case MSP_GET_DFPREG:
+	{
+		struct msp_dfpreg *r = arg;
+
+		if (r->reg < 0 || r->reg >= DFP_COUNT)
+			return -EINVAL;
+		r->value = msp3400c_read(client, I2C_MSP3400C_DFP, r->reg);
+		return 0;
+	}
 
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
@@ -1725,7 +1908,7 @@
 	{
 		struct video_audio *va = arg;
 
-		dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n");
+		msp3400_dbg("VIDIOCGAUDIO\n");
 		va->flags |= VIDEO_AUDIO_VOLUME |
 			VIDEO_AUDIO_BASS |
 			VIDEO_AUDIO_TREBLE |
@@ -1733,8 +1916,15 @@
 		if (msp->muted)
 			va->flags |= VIDEO_AUDIO_MUTE;
 
-		va->volume = msp->volume;
-		va->balance = (va->volume) ? msp->balance : 32768;
+		if (msp->muted)
+			va->flags |= VIDEO_AUDIO_MUTE;
+		va->volume = MAX(msp->left, msp->right);
+		va->balance = (32768 * MIN(msp->left, msp->right)) /
+		    (va->volume ? va->volume : 1);
+		va->balance = (msp->left < msp->right) ?
+		    (65535 - va->balance) : va->balance;
+		if (0 == va->volume)
+			va->balance = 32768;
 		va->bass = msp->bass;
 		va->treble = msp->treble;
 
@@ -1746,27 +1936,43 @@
 	{
 		struct video_audio *va = arg;
 
-		dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n");
+		msp3400_dbg("VIDIOCSAUDIO\n");
 		msp->muted = (va->flags & VIDEO_AUDIO_MUTE);
-		msp->volume = va->volume;
-		msp->balance = va->balance;
+		msp->left = (MIN(65536 - va->balance, 32768) *
+			     va->volume) / 32768;
+		msp->right = (MIN(va->balance, 32768) * va->volume) / 32768;
 		msp->bass = va->bass;
 		msp->treble = va->treble;
-
-		msp3400c_setvolume(client, msp->muted,
-				   msp->volume, msp->balance);
-		msp3400c_setbass(client,msp->bass);
-		msp3400c_settreble(client,msp->treble);
+		msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n",
+			va->volume);
+		msp3400_dbg("VIDIOCSAUDIO setting va->balance to %d\n",
+			va->balance);
+		msp3400_dbg("VIDIOCSAUDIO setting va->flags to %d\n",
+			va->flags);
+		msp3400_dbg("VIDIOCSAUDIO setting msp->left to %d\n",
+			msp->left);
+		msp3400_dbg("VIDIOCSAUDIO setting msp->right to %d\n",
+			msp->right);
+		msp3400_dbg("VIDIOCSAUDIO setting msp->bass to %d\n",
+			msp->bass);
+		msp3400_dbg("VIDIOCSAUDIO setting msp->treble to %d\n",
+			msp->treble);
+		msp3400_dbg("VIDIOCSAUDIO setting msp->mode to %d\n",
+			msp->mode);
+		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+		msp3400c_setbass(client, msp->bass);
+		msp3400c_settreble(client, msp->treble);
 
 		if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO)
 			msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode));
 		break;
 	}
+
 	case VIDIOCSCHAN:
 	{
 		struct video_channel *vc = arg;
 
-		dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN (norm=%d)\n",vc->norm);
+		msp3400_dbg("VIDIOCSCHAN (norm=%d)\n",vc->norm);
 		msp->norm = vc->norm;
 		msp_wake_thread(client);
 		break;
@@ -1776,12 +1982,135 @@
 	case VIDIOC_S_FREQUENCY:
 	{
 		/* new channel -- kick audio carrier scan */
-		dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n");
+		msp3400_dbg("VIDIOCSFREQ\n");
 		msp_wake_thread(client);
 		break;
 	}
 
+	/* msp34xx specific */
+	case MSP_SET_MATRIX:
+	{
+		struct msp_matrix *mspm = arg;
+
+		msp3400_dbg("MSP_SET_MATRIX\n");
+		msp3400c_set_scart(client, mspm->input, mspm->output);
+		break;
+	}
+
 	/* --- v4l2 ioctls --- */
+	case VIDIOC_S_STD:
+	{
+		v4l2_std_id *id = arg;
+
+		/*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
+		if (*id & V4L2_STD_PAL) {
+			msp->norm=VIDEO_MODE_PAL;
+		} else if (*id & V4L2_STD_SECAM) {
+			msp->norm=VIDEO_MODE_SECAM;
+		} else {
+			msp->norm=VIDEO_MODE_NTSC;
+		}
+
+		msp_wake_thread(client);
+		return 0;
+	}
+
+	case VIDIOC_ENUMINPUT:
+	{
+		struct v4l2_input *i = arg;
+
+		if (i->index != 0)
+			return -EINVAL;
+
+		i->type = V4L2_INPUT_TYPE_TUNER;
+		switch (i->index) {
+		case AUDIO_RADIO:
+			strcpy(i->name,"Radio");
+			break;
+		case AUDIO_EXTERN_1:
+			strcpy(i->name,"Extern 1");
+			break;
+		case AUDIO_EXTERN_2:
+			strcpy(i->name,"Extern 2");
+			break;
+		case AUDIO_TUNER:
+			strcpy(i->name,"Television");
+			break;
+		default:
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	case VIDIOC_G_AUDIO:
+	{
+		struct v4l2_audio *a = arg;
+
+		memset(a,0,sizeof(*a));
+
+		switch (a->index) {
+		case AUDIO_RADIO:
+			strcpy(a->name,"Radio");
+			break;
+		case AUDIO_EXTERN_1:
+			strcpy(a->name,"Extern 1");
+			break;
+		case AUDIO_EXTERN_2:
+			strcpy(a->name,"Extern 2");
+			break;
+		case AUDIO_TUNER:
+			strcpy(a->name,"Television");
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		msp_any_detect_stereo(client);
+		if (msp->audmode == V4L2_TUNER_MODE_STEREO) {
+			a->capability=V4L2_AUDCAP_STEREO;
+		}
+
+		break;
+	}
+	case VIDIOC_S_AUDIO:
+	{
+		struct v4l2_audio *sarg = arg;
+
+		switch (sarg->index) {
+		case AUDIO_RADIO:
+			/* Hauppauge uses IN2 for the radio */
+			msp->mode   = MSP_MODE_FM_RADIO;
+			scart       = SCART_IN2;
+			break;
+		case AUDIO_EXTERN_1:
+			/* IN1 is often used for external input ... */
+			msp->mode   = MSP_MODE_EXTERN;
+			scart       = SCART_IN1;
+			break;
+		case AUDIO_EXTERN_2:
+			/* ... sometimes it is IN2 through ;) */
+			msp->mode   = MSP_MODE_EXTERN;
+			scart       = SCART_IN2;
+			break;
+		case AUDIO_TUNER:
+			msp->mode   = -1;
+			break;
+		}
+		if (scart) {
+			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			msp->audmode = V4L2_TUNER_MODE_STEREO;
+			msp3400c_set_scart(client,scart,0);
+			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
+		}
+		if (sarg->capability==V4L2_AUDCAP_STEREO) {
+			msp->audmode = V4L2_TUNER_MODE_STEREO;
+		} else {
+			msp->audmode &= ~V4L2_TUNER_MODE_STEREO;
+		}
+		msp_any_set_audmode(client, msp->audmode);
+		msp_wake_thread(client);
+		break;
+	}
 	case VIDIOC_G_TUNER:
 	{
 		struct v4l2_tuner *vt = arg;
@@ -1804,13 +2133,46 @@
 		break;
 	}
 
-	/* msp34xx specific */
-	case MSP_SET_MATRIX:
+	case VIDIOC_G_AUDOUT:
 	{
-		struct msp_matrix *mspm = arg;
+		struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
+		int idx=a->index;
 
-		dprintk(KERN_DEBUG "msp34xx: MSP_SET_MATRIX\n");
-		msp3400c_set_scart(client, mspm->input, mspm->output);
+		memset(a,0,sizeof(*a));
+
+		switch (idx) {
+		case 0:
+			strcpy(a->name,"Scart1 Out");
+			break;
+		case 1:
+			strcpy(a->name,"Scart2 Out");
+			break;
+		case 2:
+			strcpy(a->name,"I2S Out");
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	}
+	case VIDIOC_S_AUDOUT:
+	{
+		struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
+
+		if (a->index<0||a->index>2)
+			return -EINVAL;
+
+		if (a->index==2) {
+			if (a->mode == V4L2_AUDMODE_32BITS)
+				msp->i2s_mode=1;
+			else
+				msp->i2s_mode=0;
+		}
+		msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",
+						a->index,msp->i2s_mode);
+		msp3400c_set_scart(client,msp->in_scart,a->index+1);
+
 		break;
 	}
 
@@ -1823,19 +2185,19 @@
 
 static int msp_suspend(struct device * dev, pm_message_t state)
 {
-	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 
-	dprintk("msp34xx: suspend\n");
-	msp3400c_reset(c);
+	msp3400_dbg("msp34xx: suspend\n");
+	msp3400c_reset(client);
 	return 0;
 }
 
 static int msp_resume(struct device * dev)
 {
-	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 
-	dprintk("msp34xx: resume\n");
-	msp_wake_thread(c);
+	msp3400_dbg("msp34xx: resume\n");
+	msp_wake_thread(client);
 	return 0;
 }
 
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 972aa5e..2180018 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -76,17 +76,17 @@
 			       unsigned int xogc) //all in Hz
 {
 	struct tuner *t = i2c_get_clientdata(c);
-        unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+	unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
 		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
 
-        fref= 5250 *1000; //5.25MHz
+	fref= 5250 *1000; //5.25MHz
 	desired_lo1=rfin+if1;
 
 	lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
-        lo1n=lo1/8;
-        lo1a=lo1-(lo1n*8);
+	lo1n=lo1/8;
+	lo1a=lo1-(lo1n*8);
 
-        s=rfin/1000/1000+1090;
+	s=rfin/1000/1000+1090;
 
 	if(optimize_vco) {
 		if(s>1890) sel=0;
@@ -96,34 +96,34 @@
 		else sel=4; // >1090
 	}
 	else {
-        	if(s>1790) sel=0; // <1958
-        	else if(s>1617) sel=1;
-        	else if(s>1449) sel=2;
-        	else if(s>1291) sel=3;
-        	else sel=4; // >1090
+		if(s>1790) sel=0; // <1958
+		else if(s>1617) sel=1;
+		else if(s>1449) sel=2;
+		else if(s>1291) sel=3;
+		else sel=4; // >1090
 	}
 	*ret_sel=sel;
 
-        lo1freq=(lo1a+8*lo1n)*fref;
+	lo1freq=(lo1a+8*lo1n)*fref;
 
 	tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
 		  rfin,lo1,lo1n,lo1a,sel,lo1freq);
 
-        desired_lo2=lo1freq-rfin-if2;
-        lo2=(desired_lo2)/fref;
-        lo2n=lo2/8;
-        lo2a=lo2-(lo2n*8);
-        lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
-        lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
+	desired_lo2=lo1freq-rfin-if2;
+	lo2=(desired_lo2)/fref;
+	lo2n=lo2/8;
+	lo2a=lo2-(lo2n*8);
+	lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
+	lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
 
 	tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
 		  rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
 
-        if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
+	if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
 		tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
 			   lo1a, lo1n, lo2a,lo2n);
-                return(-1);
-        }
+		return(-1);
+	}
 
 	mt2032_spurcheck(c, lo1freq, desired_lo2,  spectrum_from, spectrum_to);
 	// should recalculate lo1 (one step up/down)
@@ -135,10 +135,10 @@
 	buf[3]=0x0f; //reserved
 	buf[4]=0x1f;
 	buf[5]=(lo2n-1) | (lo2a<<5);
- 	if(rfin >400*1000*1000)
-                buf[6]=0xe4;
-        else
-                buf[6]=0xf4; // set PKEN per rev 1.2
+	if(rfin >400*1000*1000)
+		buf[6]=0xe4;
+	else
+		buf[6]=0xf4; // set PKEN per rev 1.2
 	buf[7]=8+xogc;
 	buf[8]=0xc3; //reserved
 	buf[9]=0x4e; //reserved
@@ -168,7 +168,7 @@
 		tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
 		udelay(1000);
 	}
-        return lock;
+	return lock;
 }
 
 static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
@@ -202,7 +202,7 @@
 
 	buf[0]=0x0f;
 	buf[1]=sel;
-        i2c_master_send(c,buf,2);
+	i2c_master_send(c,buf,2);
 	lock=mt2032_check_lo_lock(c);
 	return lock;
 }
@@ -219,23 +219,23 @@
 	tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
 		  rfin,if1,if2,from,to);
 
-        buf[0]=0;
-        ret=i2c_master_send(c,buf,1);
-        i2c_master_recv(c,buf,21);
+	buf[0]=0;
+	ret=i2c_master_send(c,buf,1);
+	i2c_master_recv(c,buf,21);
 
 	buf[0]=0;
 	ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
 	if (ret<0)
 		return;
 
-        // send only the relevant registers per Rev. 1.2
-        buf[0]=0;
-        ret=i2c_master_send(c,buf,4);
-        buf[5]=5;
-        ret=i2c_master_send(c,buf+5,4);
-        buf[11]=11;
-        ret=i2c_master_send(c,buf+11,3);
-        if(ret!=3)
+	// send only the relevant registers per Rev. 1.2
+	buf[0]=0;
+	ret=i2c_master_send(c,buf,4);
+	buf[5]=5;
+	ret=i2c_master_send(c,buf+5,4);
+	buf[11]=11;
+	ret=i2c_master_send(c,buf+11,3);
+	if(ret!=3)
 		tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
 
 	// wait for PLLs to lock (per manual), retry LINT if not.
@@ -253,7 +253,7 @@
 		mdelay(10);
 		buf[1]=8+t->xogc;
 		i2c_master_send(c,buf,2);
-        }
+	}
 
 	if (lock!=6)
 		tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n");
@@ -284,7 +284,7 @@
 		if2  = 38900*1000;
 	}
 
-        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+	mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
 			   1090*1000*1000, if2, from, to);
 }
 
@@ -294,7 +294,7 @@
 	int if2 = t->radio_if2;
 
 	// per Manual for FM tuning: first if center freq. 1085 MHz
-        mt2032_set_if_freq(c, freq * 1000 / 16,
+	mt2032_set_if_freq(c, freq * 1000 / 16,
 			      1085*1000*1000,if2,if2,if2);
 }
 
@@ -302,57 +302,57 @@
 static int mt2032_init(struct i2c_client *c)
 {
 	struct tuner *t = i2c_get_clientdata(c);
-        unsigned char buf[21];
-        int ret,xogc,xok=0;
+	unsigned char buf[21];
+	int ret,xogc,xok=0;
 
 	// Initialize Registers per spec.
-        buf[1]=2; // Index to register 2
-        buf[2]=0xff;
-        buf[3]=0x0f;
-        buf[4]=0x1f;
-        ret=i2c_master_send(c,buf+1,4);
+	buf[1]=2; // Index to register 2
+	buf[2]=0xff;
+	buf[3]=0x0f;
+	buf[4]=0x1f;
+	ret=i2c_master_send(c,buf+1,4);
 
-        buf[5]=6; // Index register 6
-        buf[6]=0xe4;
-        buf[7]=0x8f;
-        buf[8]=0xc3;
-        buf[9]=0x4e;
-        buf[10]=0xec;
-        ret=i2c_master_send(c,buf+5,6);
+	buf[5]=6; // Index register 6
+	buf[6]=0xe4;
+	buf[7]=0x8f;
+	buf[8]=0xc3;
+	buf[9]=0x4e;
+	buf[10]=0xec;
+	ret=i2c_master_send(c,buf+5,6);
 
-        buf[12]=13;  // Index register 13
-        buf[13]=0x32;
-        ret=i2c_master_send(c,buf+12,2);
+	buf[12]=13;  // Index register 13
+	buf[13]=0x32;
+	ret=i2c_master_send(c,buf+12,2);
 
-        // Adjust XOGC (register 7), wait for XOK
-        xogc=7;
-        do {
+	// Adjust XOGC (register 7), wait for XOK
+	xogc=7;
+	do {
 		tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
-                mdelay(10);
-                buf[0]=0x0e;
-                i2c_master_send(c,buf,1);
-                i2c_master_recv(c,buf,1);
-                xok=buf[0]&0x01;
-                tuner_dbg("mt2032: xok = 0x%02x\n",xok);
-                if (xok == 1) break;
+		mdelay(10);
+		buf[0]=0x0e;
+		i2c_master_send(c,buf,1);
+		i2c_master_recv(c,buf,1);
+		xok=buf[0]&0x01;
+		tuner_dbg("mt2032: xok = 0x%02x\n",xok);
+		if (xok == 1) break;
 
-                xogc--;
-                tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
-                if (xogc == 3) {
-                        xogc=4; // min. 4 per spec
-                        break;
-                }
-                buf[0]=0x07;
-                buf[1]=0x88 + xogc;
-                ret=i2c_master_send(c,buf,2);
-                if (ret!=2)
+		xogc--;
+		tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+		if (xogc == 3) {
+			xogc=4; // min. 4 per spec
+			break;
+		}
+		buf[0]=0x07;
+		buf[1]=0x88 + xogc;
+		ret=i2c_master_send(c,buf,2);
+		if (ret!=2)
 			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
-        } while (xok != 1 );
+	} while (xok != 1 );
 	t->xogc=xogc;
 
 	t->tv_freq    = mt2032_set_tv_freq;
 	t->radio_freq = mt2032_set_radio_freq;
-        return(1);
+	return(1);
 }
 
 static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
@@ -426,7 +426,7 @@
 	}
 
 	ret=i2c_master_send(c,buf,6);
-        if (ret!=6)
+	if (ret!=6)
 		tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
 }
 
@@ -437,11 +437,11 @@
 
 	if (t->std & V4L2_STD_525_60) {
 		// NTSC
-                if2 = 45750*1000;
-        } else {
-                // PAL
-                if2 = 38900*1000;
-        }
+		if2 = 45750*1000;
+	} else {
+		// PAL
+		if2 = 38900*1000;
+	}
 	if (V4L2_TUNER_DIGITAL_TV == t->mode) {
 		// DVB (pinnacle 300i)
 		if2 = 36150*1000;
@@ -455,7 +455,7 @@
 	struct tuner *t = i2c_get_clientdata(c);
 	int if2 = t->radio_if2;
 
-	mt2050_set_if_freq(c, freq*62500, if2);
+	mt2050_set_if_freq(c, freq * 1000 / 16, if2);
 	mt2050_set_antenna(c, radio_antenna);
 }
 
@@ -487,7 +487,7 @@
 {
 	struct tuner *t = i2c_get_clientdata(c);
 	char *name;
-        unsigned char buf[21];
+	unsigned char buf[21];
 	int company_code;
 
 	memset(buf,0,sizeof(buf));
@@ -496,17 +496,17 @@
 	t->standby    = NULL;
 	name = "unknown";
 
-        i2c_master_send(c,buf,1);
-        i2c_master_recv(c,buf,21);
-        if (tuner_debug) {
-                int i;
+	i2c_master_send(c,buf,1);
+	i2c_master_recv(c,buf,21);
+	if (tuner_debug) {
+		int i;
 		tuner_dbg("MT20xx hexdump:");
-                for(i=0;i<21;i++) {
-                        printk(" %02x",buf[i]);
-                        if(((i+1)%8)==0) printk(" ");
-                }
-                printk("\n");
-        }
+		for(i=0;i<21;i++) {
+			printk(" %02x",buf[i]);
+			if(((i+1)%8)==0) printk(" ");
+		}
+		printk("\n");
+	}
 	company_code = buf[0x11] << 8 | buf[0x12];
 	tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
 		   company_code,buf[0x13],buf[0x14]);
@@ -525,8 +525,8 @@
 	default:
 		tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
 			   name);
-                return 0;
-        }
+		return 0;
+	}
 
 	strlcpy(c->name, name, sizeof(c->name));
 	tuner_info("microtune %s found, OK\n",name);
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 72b70eb..dca3ddf 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -31,7 +31,6 @@
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 
-#include <media/id.h>
 
 #include "rds.h"
 
@@ -246,7 +245,7 @@
 		s->wr_index = 0;
 
 	if (s->wr_index == s->rd_index) {
-		s->rd_index++;
+		s->rd_index += 3;
 		if (s->rd_index >= s->buf_size)
 			s->rd_index = 0;
 	} else
@@ -328,7 +327,7 @@
 	struct saa6588 *s = (struct saa6588 *)data;
 
 	saa6588_i2c_poll(s);
-	mod_timer(&s->timer, jiffies + HZ / 50);	/* 20 msec */
+	mod_timer(&s->timer, jiffies + msecs_to_jiffies(20));
 }
 
 static int saa6588_configure(struct saa6588 *s)
@@ -434,9 +433,9 @@
 		return i2c_probe(adap, &addr_data, saa6588_attach);
 #else
 	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-	case I2C_ALGO_SAA7134:
+	case I2C_HW_B_BT848:
+	case I2C_HW_B_RIVA:
+	case I2C_HW_SAA7134:
 		return i2c_probe(adap, &addr_data, saa6588_attach);
 		break;
 	}
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
new file mode 100644
index 0000000..9aa8827
--- /dev/null
+++ b/drivers/media/video/saa711x.c
@@ -0,0 +1,593 @@
+/*
+ * saa711x - Philips SAA711x video decoder driver version 0.0.1
+ *
+ * To do: Now, it handles only saa7113/7114. Should be improved to
+ * handle all Philips saa711x devices.
+ *
+ * Based on saa7113 driver from Dave Perks <dperks@ibm.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+
+MODULE_DESCRIPTION("Philips SAA711x video decoder driver");
+MODULE_AUTHOR("Dave Perks, Jose Ignacio Gijon, Joerg Heckenbach, Mark McClelland, Dwaine Garden");
+MODULE_LICENSE("GPL");
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(s) (s)->name
+
+#include <linux/video_decoder.h>
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, " Set the default Debug level.  Default: 0 (Off) - (0-1)");
+
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (debug >= num) \
+			printk(format , ##args); \
+	} while (0)
+
+/* ----------------------------------------------------------------------- */
+
+struct saa711x {
+	unsigned char reg[32];
+
+	int norm;
+	int input;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+};
+
+#define   I2C_SAA7113        0x4A
+#define   I2C_SAA7114        0x42
+
+/* ----------------------------------------------------------------------- */
+
+static inline int
+saa711x_write (struct i2c_client *client,
+	       u8                 reg,
+	       u8                 value)
+{
+	struct saa711x *decoder = i2c_get_clientdata(client);
+
+	decoder->reg[reg] = value;
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int
+saa711x_write_block (struct i2c_client *client,
+		     const u8          *data,
+		     unsigned int       len)
+{
+	int ret = -1;
+	u8 reg;
+
+	/* the saa711x has an autoincrement function, use it if
+	 * the adapter understands raw I2C */
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		/* do raw I2C, not smbus compatible */
+		struct saa711x *decoder = i2c_get_clientdata(client);
+		struct i2c_msg msg;
+		u8 block_data[32];
+
+		msg.addr = client->addr;
+		msg.flags = 0;
+		while (len >= 2) {
+			msg.buf = (char *) block_data;
+			msg.len = 0;
+			block_data[msg.len++] = reg = data[0];
+			do {
+				block_data[msg.len++] =
+				    decoder->reg[reg++] = data[1];
+				len -= 2;
+				data += 2;
+			} while (len >= 2 && data[0] == reg &&
+				 msg.len < 32);
+			if ((ret = i2c_transfer(client->adapter,
+						&msg, 1)) < 0)
+				break;
+		}
+	} else {
+		/* do some slow I2C emulation kind of thing */
+		while (len >= 2) {
+			reg = *data++;
+			if ((ret = saa711x_write(client, reg,
+						 *data++)) < 0)
+				break;
+			len -= 2;
+		}
+	}
+
+	return ret;
+}
+
+static int
+saa711x_init_decoder (struct i2c_client *client,
+	      struct video_decoder_init *init)
+{
+	return saa711x_write_block(client, init->data, init->len);
+}
+
+static inline int
+saa711x_read (struct i2c_client *client,
+	      u8                 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const unsigned char saa711x_i2c_init[] = {
+	0x00, 0x00,	/* PH711x_CHIP_VERSION 00 - ID byte */
+	0x01, 0x08,	/* PH711x_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
+	0x02, 0xc0,	/* PH711x_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
+	0x03, 0x23,	/* PH711x_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
+	0x04, 0x00,	/* PH711x_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
+	0x05, 0x00,	/* PH711x_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
+	0x06, 0xeb,	/* PH711x_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
+	0x07, 0xe0,	/* PH711x_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
+	0x08, 0x88,	/* PH711x_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
+	0x09, 0x00,	/* PH711x_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
+	0x0a, 0x80,	/* PH711x_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
+	0x0b, 0x47,	/* PH711x_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
+	0x0c, 0x40,	/* PH711x_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
+	0x0d, 0x00,	/* PH711x_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
+	0x0e, 0x01,	/* PH711x_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
+	0x0f, 0xaa,	/* PH711x_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
+	0x10, 0x00,	/* PH711x_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
+	0x11, 0x1C,	/* PH711x_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
+	0x12, 0x01,	/* PH711x_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
+	0x13, 0x00,	/* PH711x_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
+	0x14, 0x00,	/* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
+	0x15, 0x00,	/* PH711x_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
+	0x16, 0x00,	/* PH711x_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
+	0x17, 0x00,	/* PH711x_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
+};
+
+static int
+saa711x_command (struct i2c_client *client,
+		 unsigned int       cmd,
+		 void              *arg)
+{
+	struct saa711x *decoder = i2c_get_clientdata(client);
+
+	switch (cmd) {
+
+	case 0:
+	case DECODER_INIT:
+	{
+		struct video_decoder_init *init = arg;
+		if (NULL != init)
+			return saa711x_init_decoder(client, init);
+		else {
+			struct video_decoder_init vdi;
+			vdi.data = saa711x_i2c_init;
+			vdi.len = sizeof(saa711x_i2c_init);
+			return saa711x_init_decoder(client, &vdi);
+		}
+	}
+
+	case DECODER_DUMP:
+	{
+		int i;
+
+		for (i = 0; i < 32; i += 16) {
+			int j;
+
+			printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+			for (j = 0; j < 16; ++j) {
+				printk(" %02x",
+				       saa711x_read(client, i + j));
+			}
+			printk("\n");
+		}
+	}
+		break;
+
+	case DECODER_GET_CAPABILITIES:
+	{
+		struct video_decoder_capability *cap = arg;
+
+		cap->flags = VIDEO_DECODER_PAL |
+			     VIDEO_DECODER_NTSC |
+			     VIDEO_DECODER_SECAM |
+			     VIDEO_DECODER_AUTO |
+			     VIDEO_DECODER_CCIR;
+		cap->inputs = 8;
+		cap->outputs = 1;
+	}
+		break;
+
+	case DECODER_GET_STATUS:
+	{
+		int *iarg = arg;
+		int status;
+		int res;
+
+		status = saa711x_read(client, 0x1f);
+		dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
+			status);
+		res = 0;
+		if ((status & (1 << 6)) == 0) {
+			res |= DECODER_STATUS_GOOD;
+		}
+		switch (decoder->norm) {
+		case VIDEO_MODE_NTSC:
+			res |= DECODER_STATUS_NTSC;
+			break;
+		case VIDEO_MODE_PAL:
+			res |= DECODER_STATUS_PAL;
+			break;
+		case VIDEO_MODE_SECAM:
+			res |= DECODER_STATUS_SECAM;
+			break;
+		default:
+		case VIDEO_MODE_AUTO:
+			if ((status & (1 << 5)) != 0) {
+				res |= DECODER_STATUS_NTSC;
+			} else {
+				res |= DECODER_STATUS_PAL;
+			}
+			break;
+		}
+		if ((status & (1 << 0)) != 0) {
+			res |= DECODER_STATUS_COLOR;
+		}
+		*iarg = res;
+	}
+		break;
+
+	case DECODER_SET_GPIO:
+	{
+		int *iarg = arg;
+		if (0 != *iarg) {
+			saa711x_write(client, 0x11,
+				(decoder->reg[0x11] | 0x80));
+		} else {
+			saa711x_write(client, 0x11,
+				(decoder->reg[0x11] & 0x7f));
+		}
+		break;
+	}
+
+	case DECODER_SET_VBI_BYPASS:
+	{
+		int *iarg = arg;
+		if (0 != *iarg) {
+			saa711x_write(client, 0x13,
+				(decoder->reg[0x13] & 0xf0) | 0x0a);
+		} else {
+			saa711x_write(client, 0x13,
+				(decoder->reg[0x13] & 0xf0));
+		}
+		break;
+	}
+
+	case DECODER_SET_NORM:
+	{
+		int *iarg = arg;
+
+		switch (*iarg) {
+
+		case VIDEO_MODE_NTSC:
+			saa711x_write(client, 0x08,
+				      (decoder->reg[0x08] & 0x3f) | 0x40);
+			saa711x_write(client, 0x0e,
+				      (decoder->reg[0x0e] & 0x8f));
+			break;
+
+		case VIDEO_MODE_PAL:
+			saa711x_write(client, 0x08,
+				      (decoder->reg[0x08] & 0x3f) | 0x00);
+			saa711x_write(client, 0x0e,
+				      (decoder->reg[0x0e] & 0x8f));
+			break;
+
+		case VIDEO_MODE_SECAM:
+			saa711x_write(client, 0x08,
+				      (decoder->reg[0x0e] & 0x3f) | 0x00);
+			saa711x_write(client, 0x0e,
+				      (decoder->reg[0x0e] & 0x8f) | 0x50);
+			break;
+
+		case VIDEO_MODE_AUTO:
+			saa711x_write(client, 0x08,
+				      (decoder->reg[0x08] & 0x3f) | 0x80);
+			saa711x_write(client, 0x0e,
+				      (decoder->reg[0x0e] & 0x8f));
+			break;
+
+		default:
+			return -EINVAL;
+
+		}
+		decoder->norm = *iarg;
+	}
+		break;
+
+	case DECODER_SET_INPUT:
+	{
+		int *iarg = arg;
+		if (*iarg < 0 || *iarg > 9) {
+			return -EINVAL;
+		}
+		if (decoder->input != *iarg) {
+			decoder->input = *iarg;
+			/* select mode */
+			saa711x_write(client, 0x02,
+				      (decoder->reg[0x02] & 0xf0) | decoder->input);
+			/* bypass chrominance trap for modes 4..7 */
+			saa711x_write(client, 0x09,
+				      (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));
+		}
+	}
+		break;
+
+	case DECODER_SET_OUTPUT:
+	{
+		int *iarg = arg;
+
+		/* not much choice of outputs */
+		if (*iarg != 0) {
+			return -EINVAL;
+		}
+	}
+		break;
+
+	case DECODER_ENABLE_OUTPUT:
+	{
+		int *iarg = arg;
+		int enable = (*iarg != 0);
+
+		if (decoder->enable != enable) {
+			decoder->enable = enable;
+
+			/* RJ: If output should be disabled (for
+			 * playing videos), we also need a open PLL.
+			 * The input is set to 0 (where no input
+			 * source is connected), although this
+			 * is not necessary.
+			 *
+			 * If output should be enabled, we have to
+			 * reverse the above.
+			 */
+
+			if (decoder->enable) {
+				saa711x_write(client, 0x02,
+					      (decoder->
+					       reg[0x02] & 0xf8) |
+					      decoder->input);
+				saa711x_write(client, 0x08,
+					      (decoder->reg[0x08] & 0xfb));
+				saa711x_write(client, 0x11,
+					      (decoder->
+					       reg[0x11] & 0xf3) | 0x0c);
+			} else {
+				saa711x_write(client, 0x02,
+					      (decoder->reg[0x02] & 0xf8));
+				saa711x_write(client, 0x08,
+					      (decoder->
+					       reg[0x08] & 0xfb) | 0x04);
+				saa711x_write(client, 0x11,
+					      (decoder->reg[0x11] & 0xf3));
+			}
+		}
+	}
+		break;
+
+	case DECODER_SET_PICTURE:
+	{
+		struct video_picture *pic = arg;
+
+		if (decoder->bright != pic->brightness) {
+			/* We want 0 to 255 we get 0-65535 */
+			decoder->bright = pic->brightness;
+			saa711x_write(client, 0x0a, decoder->bright >> 8);
+		}
+		if (decoder->contrast != pic->contrast) {
+			/* We want 0 to 127 we get 0-65535 */
+			decoder->contrast = pic->contrast;
+			saa711x_write(client, 0x0b,
+				      decoder->contrast >> 9);
+		}
+		if (decoder->sat != pic->colour) {
+			/* We want 0 to 127 we get 0-65535 */
+			decoder->sat = pic->colour;
+			saa711x_write(client, 0x0c, decoder->sat >> 9);
+		}
+		if (decoder->hue != pic->hue) {
+			/* We want -128 to 127 we get 0-65535 */
+			decoder->hue = pic->hue;
+			saa711x_write(client, 0x0d,
+				      (decoder->hue - 32768) >> 8);
+		}
+	}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+/* standard i2c insmod options */
+static unsigned short normal_i2c[] = {
+	I2C_SAA7113>>1,         /* saa7113 */
+	I2C_SAA7114>>1,         /* saa7114 */
+	I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
+
+static struct i2c_driver i2c_driver_saa711x;
+
+static int
+saa711x_detect_client (struct i2c_adapter *adapter,
+		       int                 address,
+		       int                 kind)
+{
+	int i;
+	struct i2c_client *client;
+	struct saa711x *decoder;
+	struct video_decoder_init vdi;
+
+	dprintk(1,
+		KERN_INFO
+		"saa711x.c: detecting saa711x client on address 0x%x\n",
+		address << 1);
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return 0;
+
+	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+	memset(client, 0, sizeof(struct i2c_client));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver_saa711x;
+	client->flags = I2C_CLIENT_ALLOW_USE;
+	strlcpy(I2C_NAME(client), "saa711x", sizeof(I2C_NAME(client)));
+	decoder = kmalloc(sizeof(struct saa711x), GFP_KERNEL);
+	if (decoder == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	memset(decoder, 0, sizeof(struct saa711x));
+	decoder->norm = VIDEO_MODE_NTSC;
+	decoder->input = 0;
+	decoder->enable = 1;
+	decoder->bright = 32768;
+	decoder->contrast = 32768;
+	decoder->hue = 32768;
+	decoder->sat = 32768;
+	i2c_set_clientdata(client, decoder);
+
+	i = i2c_attach_client(client);
+	if (i) {
+		kfree(client);
+		kfree(decoder);
+		return i;
+	}
+
+	vdi.data = saa711x_i2c_init;
+	vdi.len = sizeof(saa711x_i2c_init);
+	i = saa711x_init_decoder(client, &vdi);
+	if (i < 0) {
+		dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
+			I2C_NAME(client), i);
+	} else {
+		dprintk(1,
+			KERN_INFO
+			"%s_attach: chip version %x at address 0x%x\n",
+			I2C_NAME(client), saa711x_read(client, 0x00) >> 4,
+			client->addr << 1);
+	}
+
+	return 0;
+}
+
+static int
+saa711x_attach_adapter (struct i2c_adapter *adapter)
+{
+	dprintk(1,
+		KERN_INFO
+		"saa711x.c: starting probe for adapter %s (0x%x)\n",
+		I2C_NAME(adapter), adapter->id);
+	return i2c_probe(adapter, &addr_data, &saa711x_detect_client);
+}
+
+static int
+saa711x_detach_client (struct i2c_client *client)
+{
+	struct saa711x *decoder = i2c_get_clientdata(client);
+	int err;
+
+	err = i2c_detach_client(client);
+	if (err) {
+		return err;
+	}
+
+	kfree(decoder);
+	kfree(client);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa711x = {
+	.owner = THIS_MODULE,
+	.name = "saa711x",
+
+	.id = I2C_DRIVERID_SAA711X,
+	.flags = I2C_DF_NOTIFY,
+
+	.attach_adapter = saa711x_attach_adapter,
+	.detach_client = saa711x_detach_client,
+	.command = saa711x_command,
+};
+
+static int __init
+saa711x_init (void)
+{
+	return i2c_add_driver(&i2c_driver_saa711x);
+}
+
+static void __exit
+saa711x_exit (void)
+{
+	i2c_del_driver(&i2c_driver_saa711x);
+}
+
+module_init(saa711x_init);
+module_exit(saa711x_exit);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
new file mode 100644
index 0000000..624e880
--- /dev/null
+++ b/drivers/media/video/saa7134/Kconfig
@@ -0,0 +1,68 @@
+config VIDEO_SAA7134
+	tristate "Philips SAA7134 support"
+	depends on VIDEO_DEV && PCI && I2C && SOUND
+	select VIDEO_BUF
+	select VIDEO_IR
+	select VIDEO_TUNER
+	select CRC32
+	---help---
+	  This is a video4linux driver for Philips SAA713x based
+	  TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7134.
+
+config VIDEO_SAA7134_DVB
+	tristate "DVB/ATSC Support for saa7134 based TV cards"
+	depends on VIDEO_SAA7134 && DVB_CORE
+	select VIDEO_BUF_DVB
+	---help---
+	  This adds support for DVB cards based on the
+	  Philips saa7134 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7134-dvb.
+
+	  You must also select one or more DVB demodulators.
+	  If you are unsure which you need, choose all of them.
+
+config VIDEO_SAA7134_DVB_ALL_FRONTENDS
+	bool "Build all supported frontends for saa7134 based TV cards"
+	default y
+	depends on VIDEO_SAA7134_DVB
+	select DVB_MT352
+	select DVB_TDA1004X
+	select DVB_NXT200X
+	---help---
+	  This builds saa7134-dvb with all currently supported frontend
+	  demodulators.  If you wish to tweak your configuration, and
+	  only include support for the hardware that you need, choose N here.
+
+	  If you are unsure, choose Y.
+
+config VIDEO_SAA7134_DVB_MT352
+	tristate "Zarlink MT352 DVB-T Support"
+	default m
+	depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+	select DVB_MT352
+	---help---
+	  This adds DVB-T support for cards based on the
+	  Philips saa7134 chip and the MT352 demodulator.
+
+config VIDEO_SAA7134_DVB_TDA1004X
+	tristate "Phillips TDA10045H/TDA10046H DVB-T Support"
+	default m
+	depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+	select DVB_TDA1004X
+	---help---
+	  This adds DVB-T support for cards based on the
+	  Philips saa7134 chip and the TDA10045H/TDA10046H demodulator.
+
+config VIDEO_SAA7134_DVB_NXT200X
+	tristate "NXT2002/NXT2004 ATSC Support"
+	default m
+	depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+	select DVB_NXT200X
+	---help---
+	  This adds ATSC 8VSB and QAM64/256 support for cards based on the
+	  Philips saa7134 chip and the NXT2002/NXT2004 demodulator.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index b778ffd..e0b28f0 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -3,15 +3,22 @@
 		saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o	\
 		saa7134-vbi.o saa7134-video.o saa7134-input.o
 
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
+				saa6752hs.o saa7134-alsa.o
 obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
 EXTRA_CFLAGS += -I$(src)/..
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+ifneq ($(CONFIG_VIDEO_BUF_DVB),n)
+ EXTRA_CFLAGS += -DHAVE_VIDEO_BUF_DVB=1
+endif
 ifneq ($(CONFIG_DVB_MT352),n)
  EXTRA_CFLAGS += -DHAVE_MT352=1
 endif
 ifneq ($(CONFIG_DVB_TDA1004X),n)
  EXTRA_CFLAGS += -DHAVE_TDA1004X=1
 endif
+ifneq ($(CONFIG_DVB_NXT200X),n)
+ EXTRA_CFLAGS += -DHAVE_NXT200X=1
+endif
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 382911c..cdd1ed9 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/crc32.h>
 
-#include <media/id.h>
 
 #define MPEG_VIDEO_TARGET_BITRATE_MAX  27000
 #define MPEG_VIDEO_MAX_BITRATE_MAX     27000
@@ -57,6 +56,7 @@
 	struct i2c_client             client;
 	struct v4l2_mpeg_compression  params;
 	enum saa6752hs_videoformat    video_format;
+	v4l2_std_id                   standard;
 };
 
 enum saa6752hs_command {
@@ -74,58 +74,58 @@
 /* ---------------------------------------------------------------------- */
 
 static u8 PAT[] = {
-	0xc2, // i2c register
-	0x00, // table number for encoder
+	0xc2, /* i2c register */
+	0x00, /* table number for encoder */
 
-	0x47, // sync
-	0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0)
-	0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+	0x47, /* sync */
+	0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */
+	0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
 
-	0x00, // PSI pointer to start of table
+	0x00, /* PSI pointer to start of table */
 
-	0x00, // tid(0)
-	0xb0, 0x0d, // section_syntax_indicator(1), section_length(13)
+	0x00, /* tid(0) */
+	0xb0, 0x0d, /* section_syntax_indicator(1), section_length(13) */
 
-	0x00, 0x01, // transport_stream_id(1)
+	0x00, 0x01, /* transport_stream_id(1) */
 
-	0xc1, // version_number(0), current_next_indicator(1)
+	0xc1, /* version_number(0), current_next_indicator(1) */
 
-	0x00, 0x00, // section_number(0), last_section_number(0)
+	0x00, 0x00, /* section_number(0), last_section_number(0) */
 
-	0x00, 0x01, // program_number(1)
+	0x00, 0x01, /* program_number(1) */
 
-	0xe0, 0x00, // PMT PID
+	0xe0, 0x00, /* PMT PID */
 
-	0x00, 0x00, 0x00, 0x00 // CRC32
+	0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
 static u8 PMT[] = {
-	0xc2, // i2c register
-	0x01, // table number for encoder
+	0xc2, /* i2c register */
+	0x01, /* table number for encoder */
 
-	0x47, // sync
-	0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid
-	0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+	0x47, /* sync */
+	0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */
+	0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
 
-	0x00, // PSI pointer to start of table
+	0x00, /* PSI pointer to start of table */
 
-	0x02, // tid(2)
-	0xb0, 0x17, // section_syntax_indicator(1), section_length(23)
+	0x02, /* tid(2) */
+	0xb0, 0x17, /* section_syntax_indicator(1), section_length(23) */
 
-	0x00, 0x01, // program_number(1)
+	0x00, 0x01, /* program_number(1) */
 
-	0xc1, // version_number(0), current_next_indicator(1)
+	0xc1, /* version_number(0), current_next_indicator(1) */
 
-	0x00, 0x00, // section_number(0), last_section_number(0)
+	0x00, 0x00, /* section_number(0), last_section_number(0) */
 
-	0xe0, 0x00, // PCR_PID
+	0xe0, 0x00, /* PCR_PID */
 
-	0xf0, 0x00, // program_info_length(0)
+	0xf0, 0x00, /* program_info_length(0) */
 
-	0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid
-	0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid
+	0x02, 0xe0, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+	0x04, 0xe0, 0x00, 0xf0, 0x00, /* audio stream type(4), pid */
 
-	0x00, 0x00, 0x00, 0x00 // CRC32
+	0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
 static struct v4l2_mpeg_compression param_defaults =
@@ -166,33 +166,33 @@
 	unsigned long timeout;
 	int status = 0;
 
-	// execute the command
+	/* execute the command */
 	switch(command) {
-  	case SAA6752HS_COMMAND_RESET:
-  		buf[0] = 0x00;
+	case SAA6752HS_COMMAND_RESET:
+		buf[0] = 0x00;
 		break;
 
 	case SAA6752HS_COMMAND_STOP:
-	  	buf[0] = 0x03;
+		buf[0] = 0x03;
 		break;
 
 	case SAA6752HS_COMMAND_START:
-  		buf[0] = 0x02;
+		buf[0] = 0x02;
 		break;
 
 	case SAA6752HS_COMMAND_PAUSE:
-  		buf[0] = 0x04;
+		buf[0] = 0x04;
 		break;
 
 	case SAA6752HS_COMMAND_RECONFIGURE:
 		buf[0] = 0x05;
 		break;
 
-  	case SAA6752HS_COMMAND_SLEEP:
-  		buf[0] = 0x06;
+	case SAA6752HS_COMMAND_SLEEP:
+		buf[0] = 0x06;
 		break;
 
-  	case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
+	case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
 		buf[0] = 0x07;
 		break;
 
@@ -200,13 +200,13 @@
 		return -EINVAL;
 	}
 
-  	// set it and wait for it to be so
+	/* set it and wait for it to be so */
 	i2c_master_send(client, buf, 1);
 	timeout = jiffies + HZ * 3;
 	for (;;) {
-		// get the current status
+		/* get the current status */
 		buf[0] = 0x10;
-	  	i2c_master_send(client, buf, 1);
+		i2c_master_send(client, buf, 1);
 		i2c_master_recv(client, buf, 1);
 
 		if (!(buf[0] & 0x20))
@@ -216,61 +216,58 @@
 			break;
 		}
 
-		// wait a bit
 		msleep(10);
 	}
 
-	// delay a bit to let encoder settle
+	/* delay a bit to let encoder settle */
 	msleep(50);
 
-	// done
-  	return status;
+	return status;
 }
 
 
 static int saa6752hs_set_bitrate(struct i2c_client* client,
 				 struct v4l2_mpeg_compression* params)
 {
-  	u8 buf[3];
+	u8 buf[3];
 
-	// set the bitrate mode
+	/* set the bitrate mode */
 	buf[0] = 0x71;
 	buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
 	i2c_master_send(client, buf, 2);
 
-	// set the video bitrate
+	/* set the video bitrate */
 	if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
-		// set the target bitrate
+		/* set the target bitrate */
 		buf[0] = 0x80;
 	    	buf[1] = params->vi_bitrate.target >> 8;
-	  	buf[2] = params->vi_bitrate.target & 0xff;
+		buf[2] = params->vi_bitrate.target & 0xff;
 		i2c_master_send(client, buf, 3);
 
-		// set the max bitrate
+		/* set the max bitrate */
 		buf[0] = 0x81;
 	    	buf[1] = params->vi_bitrate.max >> 8;
-	  	buf[2] = params->vi_bitrate.max & 0xff;
+		buf[2] = params->vi_bitrate.max & 0xff;
 		i2c_master_send(client, buf, 3);
 	} else {
-		// set the target bitrate (no max bitrate for CBR)
-  		buf[0] = 0x81;
+		/* set the target bitrate (no max bitrate for CBR) */
+		buf[0] = 0x81;
 	    	buf[1] = params->vi_bitrate.target >> 8;
-	  	buf[2] = params->vi_bitrate.target & 0xff;
+		buf[2] = params->vi_bitrate.target & 0xff;
 		i2c_master_send(client, buf, 3);
 	}
 
-	// set the audio bitrate
- 	buf[0] = 0x94;
+	/* set the audio bitrate */
+	buf[0] = 0x94;
 	buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
 	i2c_master_send(client, buf, 2);
 
-	// set the total bitrate
+	/* set the total bitrate */
 	buf[0] = 0xb1;
-  	buf[1] = params->st_bitrate.target >> 8;
-  	buf[2] = params->st_bitrate.target & 0xff;
+	buf[1] = params->st_bitrate.target >> 8;
+	buf[2] = params->st_bitrate.target & 0xff;
 	i2c_master_send(client, buf, 3);
 
-	// return success
 	return 0;
 }
 
@@ -376,36 +373,43 @@
 
 	h = i2c_get_clientdata(client);
 
-	// Set video format - must be done first as it resets other settings
+	/* Set video format - must be done first as it resets other settings */
 	buf[0] = 0x41;
 	buf[1] = h->video_format;
 	i2c_master_send(client, buf, 2);
 
-        // set bitrate
-        saa6752hs_set_bitrate(client, &h->params);
+	/* Set number of lines in input signal */
+	buf[0] = 0x40;
+	buf[1] = 0x00;
+	if (h->standard & V4L2_STD_525_60)
+		buf[1] = 0x01;
+	i2c_master_send(client, buf, 2);
 
-	// Set GOP structure {3, 13}
+	/* set bitrate */
+	saa6752hs_set_bitrate(client, &h->params);
+
+	/* Set GOP structure {3, 13} */
 	buf[0] = 0x72;
 	buf[1] = 0x03;
 	buf[2] = 0x0D;
 	i2c_master_send(client,buf,3);
 
-    	// Set minimum Q-scale {4}
+    	/* Set minimum Q-scale {4} */
 	buf[0] = 0x82;
 	buf[1] = 0x04;
 	i2c_master_send(client,buf,2);
 
-    	// Set maximum Q-scale {12}
+    	/* Set maximum Q-scale {12} */
 	buf[0] = 0x83;
 	buf[1] = 0x0C;
 	i2c_master_send(client,buf,2);
 
-    	// Set Output Protocol
+    	/* Set Output Protocol */
 	buf[0] = 0xD0;
 	buf[1] = 0x81;
 	i2c_master_send(client,buf,2);
 
-    	// Set video output stream format {TS}
+    	/* Set video output stream format {TS} */
 	buf[0] = 0xB0;
 	buf[1] = 0x05;
 	i2c_master_send(client,buf,2);
@@ -421,9 +425,9 @@
 	localPAT[sizeof(PAT) - 1] = crc & 0xFF;
 
 	/* compute PMT */
-      	memcpy(localPMT, PMT, sizeof(PMT));
-   	localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
-   	localPMT[4] = h->params.ts_pid_pmt & 0xff;
+	memcpy(localPMT, PMT, sizeof(PMT));
+	localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+	localPMT[4] = h->params.ts_pid_pmt & 0xff;
 	localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
 	localPMT[16] = h->params.ts_pid_pcr & 0xFF;
 	localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F);
@@ -436,39 +440,39 @@
 	localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
 	localPMT[sizeof(PMT) - 1] = crc & 0xFF;
 
-    	// Set Audio PID
+    	/* Set Audio PID */
 	buf[0] = 0xC1;
 	buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
 	buf[2] = h->params.ts_pid_audio & 0xFF;
 	i2c_master_send(client,buf,3);
 
-	// Set Video PID
+	/* Set Video PID */
 	buf[0] = 0xC0;
 	buf[1] = (h->params.ts_pid_video >> 8) & 0xFF;
 	buf[2] = h->params.ts_pid_video & 0xFF;
 	i2c_master_send(client,buf,3);
 
- 	// Set PCR PID
+	/* Set PCR PID */
 	buf[0] = 0xC4;
 	buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF;
 	buf[2] = h->params.ts_pid_pcr & 0xFF;
 	i2c_master_send(client,buf,3);
 
-	// Send SI tables
+	/* Send SI tables */
 	i2c_master_send(client,localPAT,sizeof(PAT));
 	i2c_master_send(client,localPMT,sizeof(PMT));
 
-	// mute then unmute audio. This removes buzzing artefacts
+	/* mute then unmute audio. This removes buzzing artefacts */
 	buf[0] = 0xa4;
 	buf[1] = 1;
 	i2c_master_send(client, buf, 2);
-  	buf[1] = 0;
+	buf[1] = 0;
 	i2c_master_send(client, buf, 2);
 
-	// start it going
+	/* start it going */
 	saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
 
-	// readout current state
+	/* readout current state */
 	buf[0] = 0xE1;
 	buf[1] = 0xA7;
 	buf[2] = 0xFE;
@@ -477,7 +481,7 @@
 	i2c_master_send(client, buf, 5);
 	i2c_master_recv(client, buf2, 4);
 
-	// change aspect ratio
+	/* change aspect ratio */
 	buf[0] = 0xE0;
 	buf[1] = 0xA7;
 	buf[2] = 0xFE;
@@ -498,7 +502,6 @@
 	buf[8] = buf2[3];
 	i2c_master_send(client, buf, 9);
 
-   	// return success
 	return 0;
 }
 
@@ -506,16 +509,19 @@
 {
 	struct saa6752hs_state *h;
 
-        printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
+	printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
 
-        if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
-                return -ENOMEM;
+	if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
+		return -ENOMEM;
 	memset(h,0,sizeof(*h));
 	h->client = client_template;
 	h->params = param_defaults;
 	h->client.adapter = adap;
 	h->client.addr = addr;
 
+	/* Assume 625 input lines */
+	h->standard = 0;
+
 	i2c_set_clientdata(&h->client, h);
         i2c_attach_client(&h->client);
 	return 0;
@@ -545,7 +551,7 @@
 	struct v4l2_mpeg_compression *params = arg;
 	int err = 0;
 
-        switch (cmd) {
+	switch (cmd) {
 	case VIDIOC_S_MPEGCOMP:
 		if (NULL == params) {
 			/* apply settings and start encoder */
@@ -559,7 +565,7 @@
 		break;
 	case VIDIOC_G_FMT:
 	{
-           struct v4l2_format *f = arg;
+	   struct v4l2_format *f = arg;
 
 	   if (h->video_format == SAA6752HS_VF_UNKNOWN)
 		   h->video_format = SAA6752HS_VF_D1;
@@ -576,6 +582,9 @@
 		saa6752hs_set_subsampling(client, f);
 		break;
 	}
+	case VIDIOC_S_STD:
+		h->standard = *((v4l2_std_id *) arg);
+		break;
 	default:
 		/* nothing */
 		break;
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
new file mode 100644
index 0000000..4f3c423
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -0,0 +1,1047 @@
+/*
+ *   SAA713x ALSA support for V4L
+ *
+ *
+ *   Caveats:
+ *        - Volume doesn't work (it's always at max)
+ *
+ *   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
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+static unsigned int debug  = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
+
+/*
+ * Configuration macros
+ */
+
+/* defaults */
+#define MIXER_ADDR_TVTUNER	0
+#define MIXER_ADDR_LINE1	1
+#define MIXER_ADDR_LINE2	2
+#define MIXER_ADDR_LAST		2
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s).");
+
+#define dprintk(fmt, arg...)    if (debug) \
+        printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg)
+
+/*
+ * Main chip structure
+ */
+typedef struct snd_card_saa7134 {
+	snd_card_t *card;
+	spinlock_t mixer_lock;
+	int mixer_volume[MIXER_ADDR_LAST+1][2];
+	int capture_source[MIXER_ADDR_LAST+1][2];
+	struct pci_dev *pci;
+	struct saa7134_dev *saadev;
+
+	unsigned long iobase;
+	int irq;
+
+	spinlock_t lock;
+} snd_card_saa7134_t;
+
+
+
+/*
+ * PCM structure
+ */
+
+typedef struct snd_card_saa7134_pcm {
+	struct saa7134_dev *saadev;
+
+	spinlock_t lock;
+	unsigned int pcm_size;		/* buffer size */
+	unsigned int pcm_count;		/* bytes per period */
+	unsigned int pcm_bps;		/* bytes per second */
+	snd_pcm_substream_t *substream;
+} snd_card_saa7134_pcm_t;
+
+static snd_card_t *snd_saa7134_cards[SNDRV_CARDS];
+
+
+/*
+ * saa7134 DMA audio stop
+ *
+ *   Called when the capture device is released or the buffer overflows
+ *
+ *   - Copied verbatim from saa7134-oss's dsp_dma_stop. Can be dropped
+ *     if we just share dsp_dma_stop and use it here
+ *
+ */
+
+static void saa7134_dma_stop(struct saa7134_dev *dev)
+
+{
+	dev->dmasound.dma_blk     = -1;
+	dev->dmasound.dma_running = 0;
+	saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 DMA audio start
+ *
+ *   Called when preparing the capture device for use
+ *
+ *   - Copied verbatim from saa7134-oss's dsp_dma_start. Can be dropped
+ *     if we just share dsp_dma_start and use it here
+ *
+ */
+
+static void saa7134_dma_start(struct saa7134_dev *dev)
+{
+	dev->dmasound.dma_blk     = 0;
+	dev->dmasound.dma_running = 1;
+	saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 audio DMA IRQ handler
+ *
+ *   Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt
+ *   Handles shifting between the 2 buffers, manages the read counters,
+ *  and notifies ALSA when periods elapse
+ *
+ *   - Mostly copied from saa7134-oss's saa7134_irq_oss_done.
+ *
+ */
+
+void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status)
+{
+	int next_blk, reg = 0;
+
+	spin_lock(&dev->slock);
+	if (UNSET == dev->dmasound.dma_blk) {
+		dprintk("irq: recording stopped\n");
+		goto done;
+	}
+	if (0 != (status & 0x0f000000))
+		dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
+	if (0 == (status & 0x10000000)) {
+		/* odd */
+		if (0 == (dev->dmasound.dma_blk & 0x01))
+			reg = SAA7134_RS_BA1(6);
+	} else {
+		/* even */
+		if (1 == (dev->dmasound.dma_blk & 0x01))
+			reg = SAA7134_RS_BA2(6);
+	}
+	if (0 == reg) {
+		dprintk("irq: field oops [%s]\n",
+			(status & 0x10000000) ? "even" : "odd");
+		goto done;
+	}
+
+	if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+		dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count,
+			dev->dmasound.bufsize, dev->dmasound.blocks);
+		snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN);
+		saa7134_dma_stop(dev);
+		goto done;
+	}
+
+	/* next block addr */
+	next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+	saa_writel(reg,next_blk * dev->dmasound.blksize);
+	if (debug > 2)
+		dprintk("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n",
+			(status & 0x10000000) ? "even" : "odd ", next_blk,
+			next_blk * dev->dmasound.blksize, dev->dmasound.blocks, dev->dmasound.blksize, dev->dmasound.read_count);
+
+	/* update status & wake waiting readers */
+	dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+	dev->dmasound.read_count += dev->dmasound.blksize;
+
+	dev->dmasound.recording_on = reg;
+
+	if (dev->dmasound.read_count >= snd_pcm_lib_period_bytes(dev->dmasound.substream)) {
+		spin_unlock(&dev->slock);
+		snd_pcm_period_elapsed(dev->dmasound.substream);
+		spin_lock(&dev->slock);
+	}
+ done:
+	spin_unlock(&dev->slock);
+
+}
+
+/*
+ * IRQ request handler
+ *
+ *   Runs along with saa7134's IRQ handler, discards anything that isn't
+ *   DMA sound
+ *
+ */
+
+static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
+	unsigned long report, status;
+	int loop, handled = 0;
+
+	for (loop = 0; loop < 10; loop++) {
+		report = saa_readl(SAA7134_IRQ_REPORT);
+		status = saa_readl(SAA7134_IRQ_STATUS);
+
+		if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
+			handled = 1;
+			saa_writel(SAA7134_IRQ_REPORT,report);
+			saa7134_irq_alsa_done(dev, status);
+		} else {
+			goto out;
+		}
+	}
+
+	if (loop == 10) {
+		dprintk("error! looping IRQ!");
+	}
+
+out:
+	return IRQ_RETVAL(handled);
+}
+
+/*
+ * ALSA capture trigger
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called whenever a capture is started or stopped. Must be defined,
+ *   but there's nothing we want to do here
+ *
+ */
+
+static int snd_card_saa7134_capture_trigger(snd_pcm_substream_t * substream,
+					  int cmd)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+	struct saa7134_dev *dev=saapcm->saadev;
+	int err = 0;
+
+	spin_lock_irq(&dev->slock);
+        if (cmd == SNDRV_PCM_TRIGGER_START) {
+		/* start dma */
+		saa7134_dma_start(dev);
+        } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+		/* stop dma */
+		saa7134_dma_stop(dev);
+        } else {
+                err = -EINVAL;
+        }
+	spin_unlock_irq(&dev->slock);
+
+        return err;
+}
+
+/*
+ * DMA buffer config
+ *
+ *   Sets the values that will later be used as the size of the buffer,
+ *  size of the fragments, and total number of fragments.
+ *   Must be called during the preparation stage, before memory is
+ *  allocated
+ *
+ *   - Copied verbatim from saa7134-oss. Can be dropped
+ *     if we just share dsp_buffer_conf from OSS.
+ */
+
+static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
+{
+	if (blksize < 0x100)
+		blksize = 0x100;
+	if (blksize > 0x10000)
+		blksize = 0x10000;
+
+	if (blocks < 2)
+		blocks = 2;
+	if ((blksize * blocks) > 1024*1024)
+		blocks = 1024*1024 / blksize;
+
+	dev->dmasound.blocks  = blocks;
+	dev->dmasound.blksize = blksize;
+	dev->dmasound.bufsize = blksize * blocks;
+
+	dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
+		blocks,blksize,blksize * blocks / 1024);
+	return 0;
+}
+
+/*
+ * DMA buffer initialization
+ *
+ *   Uses V4L functions to initialize the DMA. Shouldn't be necessary in
+ *  ALSA, but I was unable to use ALSA's own DMA, and had to force the
+ *  usage of V4L's
+ *
+ *   - Copied verbatim from saa7134-oss. Can be dropped
+ *     if we just share dsp_buffer_init from OSS.
+ */
+
+static int dsp_buffer_init(struct saa7134_dev *dev)
+{
+	int err;
+
+	if (!dev->dmasound.bufsize)
+		BUG();
+	videobuf_dma_init(&dev->dmasound.dma);
+	err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+				       (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+	if (0 != err)
+		return err;
+	return 0;
+}
+
+/*
+ * ALSA PCM preparation
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called right after the capture device is opened, this function configures
+ *  the buffer using the previously defined functions, allocates the memory,
+ *  sets up the hardware registers, and then starts the DMA. When this function
+ *  returns, the audio should be flowing.
+ *
+ */
+
+static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int err, bswap, sign;
+	u32 fmt, control;
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev;
+	snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+	unsigned int bps;
+	unsigned long size;
+	unsigned count;
+
+	size = snd_pcm_lib_buffer_bytes(substream);
+	count = snd_pcm_lib_period_bytes(substream);
+
+	saapcm->saadev->dmasound.substream = substream;
+	bps = runtime->rate * runtime->channels;
+	bps *= snd_pcm_format_width(runtime->format);
+	bps /= 8;
+	if (bps <= 0)
+		return -EINVAL;
+	saapcm->pcm_bps = bps;
+	saapcm->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	saapcm->pcm_count = snd_pcm_lib_period_bytes(substream);
+
+
+	dev=saa7134->saadev;
+
+	dsp_buffer_conf(dev,saapcm->pcm_count,(saapcm->pcm_size/saapcm->pcm_count));
+
+	err = dsp_buffer_init(dev);
+	if (0 != err)
+		goto fail2;
+
+	/* prepare buffer */
+	if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma)))
+		return err;
+	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
+		goto fail1;
+	if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+					      dev->dmasound.dma.sglist,
+					      dev->dmasound.dma.sglen,
+					      0)))
+		goto fail2;
+
+
+
+	switch (runtime->format) {
+	  case SNDRV_PCM_FORMAT_U8:
+	  case SNDRV_PCM_FORMAT_S8:
+		fmt = 0x00;
+		break;
+	  case SNDRV_PCM_FORMAT_U16_LE:
+	  case SNDRV_PCM_FORMAT_U16_BE:
+	  case SNDRV_PCM_FORMAT_S16_LE:
+	  case SNDRV_PCM_FORMAT_S16_BE:
+		fmt = 0x01;
+		break;
+	  default:
+		err = -EINVAL;
+		return 1;
+	}
+
+	switch (runtime->format) {
+	  case SNDRV_PCM_FORMAT_S8:
+	  case SNDRV_PCM_FORMAT_S16_LE:
+	  case SNDRV_PCM_FORMAT_S16_BE:
+		sign = 1;
+		break;
+	  default:
+		sign = 0;
+		break;
+	}
+
+	switch (runtime->format) {
+	  case SNDRV_PCM_FORMAT_U16_BE:
+	  case SNDRV_PCM_FORMAT_S16_BE:
+		bswap = 1; break;
+	  default:
+		bswap = 0; break;
+	}
+
+	switch (dev->pci->device) {
+	  case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		if (1 == runtime->channels)
+			fmt |= (1 << 3);
+		if (2 == runtime->channels)
+			fmt |= (3 << 3);
+		if (sign)
+			fmt |= 0x04;
+
+		fmt |= (MIXER_ADDR_TVTUNER == dev->dmasound.input) ? 0xc0 : 0x80;
+		saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+		saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >>  8);
+		saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
+		saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+
+		break;
+	  case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	  case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (1 == runtime->channels)
+			fmt |= (1 << 4);
+		if (2 == runtime->channels)
+			fmt |= (2 << 4);
+		if (!sign)
+			fmt |= 0x04;
+		saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1);
+		saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
+		//saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210);
+		break;
+	}
+
+	dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
+		runtime->format, runtime->channels, fmt,
+		bswap ? 'b' : '-');
+	/* dma: setup channel 6 (= AUDIO) */
+	control = SAA7134_RS_CONTROL_BURST_16 |
+		SAA7134_RS_CONTROL_ME |
+		(dev->dmasound.pt.dma >> 12);
+	if (bswap)
+		control |= SAA7134_RS_CONTROL_BSWAP;
+
+	/* I should be able to use runtime->dma_addr in the control
+	   byte, but it doesn't work. So I allocate the DMA using the
+	   V4L functions, and force ALSA to use that as the DMA area */
+
+	runtime->dma_area = dev->dmasound.dma.vmalloc;
+
+	saa_writel(SAA7134_RS_BA1(6),0);
+	saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
+	saa_writel(SAA7134_RS_PITCH(6),0);
+	saa_writel(SAA7134_RS_CONTROL(6),control);
+
+	dev->dmasound.rate = runtime->rate;
+
+	return 0;
+ fail2:
+	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+ fail1:
+	videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
+	return err;
+
+
+}
+
+/*
+ * ALSA pointer fetching
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called whenever a period elapses, it must return the current hardware
+ *  position of the buffer.
+ *   Also resets the read counter used to prevent overruns
+ *
+ */
+
+static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+	struct saa7134_dev *dev=saapcm->saadev;
+
+
+
+	if (dev->dmasound.read_count) {
+		dev->dmasound.read_count  -= snd_pcm_lib_period_bytes(substream);
+		dev->dmasound.read_offset += snd_pcm_lib_period_bytes(substream);
+		if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+			dev->dmasound.read_offset = 0;
+	}
+
+	return bytes_to_frames(runtime, dev->dmasound.read_offset);
+}
+
+/*
+ * ALSA hardware capabilities definition
+ */
+
+static snd_pcm_hardware_t snd_card_saa7134_capture =
+{
+	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE | \
+				SNDRV_PCM_FMTBIT_S16_BE | \
+				SNDRV_PCM_FMTBIT_S8 | \
+				SNDRV_PCM_FMTBIT_U8 | \
+				SNDRV_PCM_FMTBIT_U16_LE | \
+				SNDRV_PCM_FMTBIT_U16_BE,
+	.rates =		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+	.rate_min =		32000,
+	.rate_max =		48000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	(256*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(256*1024),
+	.periods_min =		2,
+	.periods_max =		1024,
+};
+
+static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime)
+{
+	snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+
+	kfree(saapcm);
+}
+
+
+/*
+ * ALSA hardware params
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called on initialization, right before the PCM preparation
+ *   Usually used in ALSA to allocate the DMA, but since we don't use the
+ *  ALSA DMA it does nothing
+ *
+ */
+
+static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream,
+				    snd_pcm_hw_params_t * hw_params)
+{
+
+	return 0;
+
+
+}
+
+/*
+ * ALSA hardware release
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called after closing the device, but before snd_card_saa7134_capture_close
+ *   Usually used in ALSA to free the DMA, but since we don't use the
+ *  ALSA DMA I'm almost sure this isn't necessary.
+ *
+ */
+
+static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream)
+{
+	return 0;
+}
+
+/*
+ * DMA buffer release
+ *
+ *   Called after closing the device, during snd_card_saa7134_capture_close
+ *
+ */
+
+static int dsp_buffer_free(struct saa7134_dev *dev)
+{
+	if (!dev->dmasound.blksize)
+		BUG();
+
+	videobuf_dma_free(&dev->dmasound.dma);
+
+	dev->dmasound.blocks  = 0;
+	dev->dmasound.blksize = 0;
+	dev->dmasound.bufsize = 0;
+
+	return 0;
+}
+
+/*
+ * ALSA capture finish
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called after closing the device. It stops the DMA audio and releases
+ *  the buffers
+ *
+ */
+
+static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream)
+{
+	snd_card_saa7134_t *chip = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev = chip->saadev;
+
+	/* unlock buffer */
+	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+	videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
+
+	dsp_buffer_free(dev);
+	return 0;
+}
+
+/*
+ * ALSA capture start
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called when opening the device. It creates and populates the PCM
+ *  structure
+ *
+ */
+
+static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_card_saa7134_pcm_t *saapcm;
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev = saa7134->saadev;
+	int err;
+
+	down(&dev->dmasound.lock);
+
+	dev->dmasound.afmt        = SNDRV_PCM_FORMAT_U8;
+	dev->dmasound.channels    = 2;
+	dev->dmasound.read_count  = 0;
+	dev->dmasound.read_offset = 0;
+
+	up(&dev->dmasound.lock);
+
+	saapcm = kzalloc(sizeof(*saapcm), GFP_KERNEL);
+	if (saapcm == NULL)
+		return -ENOMEM;
+	saapcm->saadev=saa7134->saadev;
+
+	spin_lock_init(&saapcm->lock);
+
+	saapcm->substream = substream;
+	runtime->private_data = saapcm;
+	runtime->private_free = snd_card_saa7134_runtime_free;
+	runtime->hw = snd_card_saa7134_capture;
+
+	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+		return err;
+
+	return 0;
+}
+
+/*
+ * ALSA capture callbacks definition
+ */
+
+static snd_pcm_ops_t snd_card_saa7134_capture_ops = {
+	.open =			snd_card_saa7134_capture_open,
+	.close =		snd_card_saa7134_capture_close,
+	.ioctl =		snd_pcm_lib_ioctl,
+	.hw_params =		snd_card_saa7134_hw_params,
+	.hw_free =		snd_card_saa7134_hw_free,
+	.prepare =		snd_card_saa7134_capture_prepare,
+	.trigger =		snd_card_saa7134_capture_trigger,
+	.pointer =		snd_card_saa7134_capture_pointer,
+};
+
+/*
+ * ALSA PCM setup
+ *
+ *   Called when initializing the board. Sets up the name and hooks up
+ *  the callbacks
+ *
+ */
+
+static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0)
+		return err;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_saa7134_capture_ops);
+	pcm->private_data = saa7134;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "SAA7134 PCM");
+	return 0;
+}
+
+#define SAA713x_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_saa7134_volume_info, \
+  .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \
+  .private_value = addr }
+
+static int snd_saa7134_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 20;
+	return 0;
+}
+
+static int snd_saa7134_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+	int addr = kcontrol->private_value;
+
+	ucontrol->value.integer.value[0] = chip->mixer_volume[addr][0];
+	ucontrol->value.integer.value[1] = chip->mixer_volume[addr][1];
+	return 0;
+}
+
+static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int change, addr = kcontrol->private_value;
+	int left, right;
+
+	left = ucontrol->value.integer.value[0];
+	if (left < 0)
+		left = 0;
+	if (left > 20)
+		left = 20;
+	right = ucontrol->value.integer.value[1];
+	if (right < 0)
+		right = 0;
+	if (right > 20)
+		right = 20;
+	spin_lock_irqsave(&chip->mixer_lock, flags);
+	change = chip->mixer_volume[addr][0] != left ||
+		 chip->mixer_volume[addr][1] != right;
+	chip->mixer_volume[addr][0] = left;
+	chip->mixer_volume[addr][1] = right;
+	spin_unlock_irqrestore(&chip->mixer_lock, flags);
+	return change;
+}
+
+#define SAA713x_CAPSRC(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_saa7134_capsrc_info, \
+  .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \
+  .private_value = addr }
+
+static int snd_saa7134_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * 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 snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int addr = kcontrol->private_value;
+
+	spin_lock_irqsave(&chip->mixer_lock, flags);
+	ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
+	ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
+	spin_unlock_irqrestore(&chip->mixer_lock, flags);
+	return 0;
+}
+
+static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int change, addr = kcontrol->private_value;
+	int left, right;
+	u32 anabar, xbarin;
+	int analog_io, rate;
+	struct saa7134_dev *dev;
+
+	dev = chip->saadev;
+
+	left = ucontrol->value.integer.value[0] & 1;
+	right = ucontrol->value.integer.value[1] & 1;
+	spin_lock_irqsave(&chip->mixer_lock, flags);
+
+	change = chip->capture_source[addr][0] != left ||
+		 chip->capture_source[addr][1] != right;
+	chip->capture_source[addr][0] = left;
+	chip->capture_source[addr][1] = right;
+	dev->dmasound.input=addr;
+	spin_unlock_irqrestore(&chip->mixer_lock, flags);
+
+
+	if (change) {
+	  switch (dev->pci->device) {
+
+	   case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		switch (addr) {
+			case MIXER_ADDR_TVTUNER:
+				saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
+				saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
+				break;
+			case MIXER_ADDR_LINE1:
+			case MIXER_ADDR_LINE2:
+				analog_io = (MIXER_ADDR_LINE1 == addr) ? 0x00 : 0x08;
+				rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
+				saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
+				saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
+				saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
+				break;
+		}
+
+		break;
+	   case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	   case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		xbarin = 0x03; // adc
+		anabar = 0;
+		switch (addr) {
+			case MIXER_ADDR_TVTUNER:
+				xbarin = 0; // Demodulator
+				anabar = 2; // DACs
+				break;
+			case MIXER_ADDR_LINE1:
+				anabar = 0;  // aux1, aux1
+				break;
+			case MIXER_ADDR_LINE2:
+				anabar = 9;  // aux2, aux2
+				break;
+		}
+
+	    	/* output xbar always main channel */
+		saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
+
+		if (left || right) { // We've got data, turn the input on
+		  saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, xbarin);
+		  saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
+		} else {
+		  saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, 0);
+		  saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
+		}
+		break;
+	  }
+	}
+
+	return change;
+}
+
+static snd_kcontrol_new_t snd_saa7134_controls[] = {
+SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
+SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2),
+SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
+};
+
+/*
+ * ALSA mixer setup
+ *
+ *   Called when initializing the board. Sets up the name and hooks up
+ *  the callbacks
+ *
+ */
+
+static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
+{
+	snd_card_t *card = chip->card;
+	unsigned int idx;
+	int err;
+
+	snd_assert(chip != NULL, return -EINVAL);
+	strcpy(card->mixername, "SAA7134 Mixer");
+
+	for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) {
+		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_saa7134_controls[idx], chip))) < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int snd_saa7134_free(snd_card_saa7134_t *chip)
+{
+	return 0;
+}
+
+static int snd_saa7134_dev_free(snd_device_t *device)
+{
+	snd_card_saa7134_t *chip = device->device_data;
+	return snd_saa7134_free(chip);
+}
+
+/*
+ * ALSA initialization
+ *
+ *   Called by saa7134-core, it creates the basic structures and registers
+ *  the ALSA devices
+ *
+ */
+
+int alsa_card_saa7134_create (struct saa7134_dev *saadev)
+{
+	static int dev;
+
+	snd_card_t *card;
+	snd_card_saa7134_t *chip;
+	int err;
+	static snd_device_ops_t ops = {
+		.dev_free =     snd_saa7134_dev_free,
+	};
+
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev])
+		return -ENODEV;
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+
+	if (card == NULL)
+		return -ENOMEM;
+
+	strcpy(card->driver, "SAA7134");
+
+	/* Card "creation" */
+
+	chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL) {
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&chip->lock);
+	spin_lock_init(&chip->mixer_lock);
+
+	chip->saadev = saadev;
+
+	chip->card = card;
+
+	chip->pci = saadev->pci;
+	chip->irq = saadev->pci->irq;
+	chip->iobase = pci_resource_start(saadev->pci, 0);
+
+	err = request_irq(saadev->pci->irq, saa7134_alsa_irq,
+				SA_SHIRQ | SA_INTERRUPT, saadev->name, saadev);
+
+	if (err < 0) {
+		printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n",
+			saadev->name, saadev->pci->irq);
+		goto __nodev;
+	}
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		goto __nodev;
+	}
+
+	if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
+		goto __nodev;
+
+	if ((err = snd_card_saa7134_pcm(chip, 0)) < 0)
+		goto __nodev;
+
+	snd_card_set_dev(card, &chip->pci->dev);
+
+	/* End of "creation" */
+
+	strcpy(card->shortname, "SAA7134");
+	sprintf(card->longname, "%s at 0x%lx irq %d",
+		chip->saadev->name, chip->iobase, chip->irq);
+
+	if ((err = snd_card_register(card)) == 0) {
+		snd_saa7134_cards[dev] = card;
+		return 0;
+	}
+
+__nodev:
+	snd_card_free(card);
+	kfree(chip);
+	return err;
+}
+
+/*
+ * Module initializer
+ *
+ * Loops through present saa7134 cards, and assigns an ALSA device
+ * to each one
+ *
+ */
+
+static int saa7134_alsa_init(void)
+{
+        struct saa7134_dev *saadev = NULL;
+        struct list_head *list;
+
+	printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
+
+        list_for_each(list,&saa7134_devlist) {
+                saadev = list_entry(list, struct saa7134_dev, devlist);
+		alsa_card_saa7134_create(saadev);
+        }
+
+	if (saadev == NULL)
+		printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n");
+
+	return 0;
+
+}
+
+/*
+ * Module destructor
+ */
+
+void saa7134_alsa_exit(void)
+{
+	int idx;
+
+	for (idx = 0; idx < SNDRV_CARDS; idx++) {
+		snd_card_free(snd_saa7134_cards[idx]);
+	}
+
+	printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n");
+
+	return;
+}
+
+module_init(saa7134_alsa_init);
+module_exit(saa7134_alsa_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ricardo Cerqueira");
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index acc7a43..663d03e 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -191,10 +191,14 @@
 			.amux = TV,
 			.tv   = 1,
 		},{
-			.name = name_comp1,
+			.name = name_comp1,     /* Composite signal on S-Video input */
 			.vmux = 0,
 			.amux = LINE2,
 		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		},{
 			.name = name_svideo,
 			.vmux = 8,
 			.amux = LINE2,
@@ -2109,8 +2113,423 @@
 			.gpio = 0x01,
 		},
 	},
-};
+	[SAA7134_BOARD_BEHOLD_409FM] = {
+		/* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */
+		.name           = "Beholder BeholdTV 409 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			  .name = name_tv,
+			  .vmux = 3,
+			  .amux = TV,
+			  .tv   = 1,
+		},{
+			  .name = name_comp1,
+			  .vmux = 1,
+			  .amux = LINE1,
+		},{
+			  .name = name_svideo,
+			  .vmux = 8,
+			  .amux = LINE1,
+		}},
+		.radio = {
+			  .name = name_radio,
+			  .amux = LINE2,
+    		},
+	},
+	[SAA7134_BOARD_GOTVIEW_7135] = {
+		/* Mike Baikov <mike@baikov.com> */
+		/* Andrey Cvetcov <ays14@yandex.ru> */
+		.name            = "GoTView 7135 PCI",
+		.audio_clock     = 0x00187de7,
+		.tuner_type      = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type      = UNSET,
+		.tuner_addr      = ADDR_UNSET,
+		.radio_addr      = ADDR_UNSET,
+		.tda9887_conf    = TDA9887_PRESENT,
+		.gpiomask        = 0x00200003,
+		.inputs          = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x00200003,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x00200003,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x00200003,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x00200003,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x00200003,
+		},
+		.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x00200003,
+		},
+	},
+	[SAA7134_BOARD_PHILIPS_EUROPA] = {
+		.name           = "Philips EUROPA V3 reference design",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TD1316,
+		.radio_type     = UNSET,
+		.tuner_addr	= 0x61,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_VIDEOMATE_DVBT_300] = {
+		.name           = "Compro Videomate DVB-T300",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TD1316,
+		.radio_type     = UNSET,
+		.tuner_addr	= 0x61,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 3,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_VIDEOMATE_DVBT_200] = {
+		.name           = "Compro Videomate DVB-T200",
+		.tuner_type	= TUNER_ABSENT,
+		.audio_clock    = 0x00187de7,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_RTD_VFG7350] = {
+		.name		= "RTD Embedded Technologies VFG7350",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs		= {{
+			.name   = "Composite 0",
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = "Composite 1",
+			.vmux   = 1,
+			.amux   = LINE2,
+		},{
+			.name   = "Composite 2",
+			.vmux   = 2,
+			.amux   = LINE1,
+		},{
+			.name   = "Composite 3",
+			.vmux   = 3,
+			.amux   = LINE2,
+		},{
+			.name   = "S-Video 0",
+			.vmux   = 8,
+			.amux   = LINE1,
+		},{
+			.name   = "S-Video 1",
+			.vmux   = 9,
+			.amux   = LINE2,
+		}},
+		.mpeg           = SAA7134_MPEG_EMPRESS,
+		.video_out      = CCIR656,
+		.vid_port_opts  = ( SET_T_CODE_POLARITY_NON_INVERTED |
+				    SET_CLOCK_NOT_DELAYED |
+				    SET_CLOCK_INVERTED |
+				    SET_VSYNC_OFF ),
+	},
+	[SAA7134_BOARD_RTD_VFG7330] = {
+		.name		= "RTD Embedded Technologies VFG7330",
+		.audio_clock	= 0x00200000,
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs		= {{
+			.name   = "Composite 0",
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name   = "Composite 1",
+			.vmux   = 1,
+			.amux   = LINE2,
+		},{
+			.name   = "Composite 2",
+			.vmux   = 2,
+			.amux   = LINE1,
+		},{
+			.name   = "Composite 3",
+			.vmux   = 3,
+			.amux   = LINE2,
+		},{
+			.name   = "S-Video 0",
+			.vmux   = 8,
+			.amux   = LINE1,
+		},{
+			.name   = "S-Video 1",
+			.vmux   = 9,
+			.amux   = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_FLYTVPLATINUM_MINI2] = {
+		.name           = "LifeView FlyTV Platinum Mini2",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
 
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,     /* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180] = {
+		/* Michael Krufky <mkrufky@m1k.net>
+		 * Uses Alps Electric TDHU2, containing NXT2004 ATSC Decoder
+		 * AFAIK, there is no analog demod, thus,
+		 * no support for analog television.
+		 */
+		.name           = "AVerMedia AVerTVHD MCE A180",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_MONSTERTV_MOBILE] = {
+		.name           = "SKNet MonsterTV Mobile",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+
+		.inputs         = {{
+			  .name = name_tv,
+			  .vmux = 1,
+			  .amux = TV,
+			  .tv   = 1,
+		},{
+			  .name = name_comp1,
+			  .vmux = 3,
+			  .amux = LINE1,
+		},{
+			  .name = name_svideo,
+			  .vmux = 6,
+			  .amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_PINNACLE_PCTV_110i] = {
+		.name           = "Pinnacle PCTV 110i (saa7133)",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0x080200000,
+		.inputs         = {{
+			  .name = name_tv,
+			  .vmux = 4,
+			  .amux = TV,
+			  .tv   = 1,
+		},{
+			  .name = name_comp1,
+			  .vmux = 1,
+			  .amux = LINE2,
+		},{
+			  .name = name_svideo,
+			  .vmux = 8,
+			  .amux = LINE2,
+		}},
+		.radio = {
+			  .name = name_radio,
+			  .amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_ASUSTeK_P7131_DUAL] = {
+		.name           = "ASUSTeK P7131 Dual",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 1 << 21,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_SEDNA_PC_TV_CARDBUS] = {
+		/* Paul Tom Zalac <pzalac@gmail.com> */
+		/* Pavel Mihaylov <bin@bash.info> */
+		.name           = "Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)",
+				/* Sedna/MuchTV (OEM) Cardbus TV Tuner */
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0xe880c0,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV] = {
+		/* "Cyril Lacoux (Yack)" <clacoux@ifeelgood.org> */
+		.name           = "ASUS Digimatrix TV",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_PHILIPS_TIGER] = {
+		.name           = "Philips Tiger reference design",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+	},
+};
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
 
@@ -2145,19 +2564,19 @@
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-		.subvendor    = 0x153B,
+		.subvendor    = 0x153b,
 		.subdevice    = 0x1142,
 		.driver_data  = SAA7134_BOARD_CINERGY400,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-		.subvendor    = 0x153B,
+		.subvendor    = 0x153b,
 		.subdevice    = 0x1143,
 		.driver_data  = SAA7134_BOARD_CINERGY600,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-		.subvendor    = 0x153B,
+		.subvendor    = 0x153b,
 		.subdevice    = 0x1158,
 		.driver_data  = SAA7134_BOARD_CINERGY600_MK3,
 	},{
@@ -2193,6 +2612,18 @@
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x14c0,
+		.subdevice    = 0x1212, /* minipci, LR1212 */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI2,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x4e42,
+		.subdevice    = 0x0212, /* OEM minipci, LR212 */
+		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x5168,	/* Animation Technologies (LifeView) */
 		.subdevice    = 0x0214, /* Standard PCI, LR214WF */
 		.driver_data  = SAA7134_BOARD_FLYTVPLATINUM_FM,
@@ -2369,7 +2800,7 @@
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-		.subvendor    = 0x153B,
+		.subvendor    = 0x153b,
 		.subdevice    = 0x1152,
 		.driver_data  = SAA7134_BOARD_CINERGY200,
 	},{
@@ -2434,13 +2865,18 @@
 		.subvendor    = 0x1421,
 		.subdevice    = 0x0350,		/* PCI version */
 		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
-
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x1421,
 		.subdevice    = 0x0370,		/* cardbus version */
 		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1421,
+		.subdevice    = 0x1370,        /* cardbus version */
+		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
 
 	},{     /* Typhoon DVB-T Duo Digital/Analog Cardbus */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -2459,9 +2895,81 @@
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor    = 0x1043,
 		.subdevice    = 0x0210,		/* mini pci PAL/SECAM version */
-		.driver_data  = SAA7134_BOARD_FLYTV_DIGIMATRIX,
+		.driver_data  = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV,
 
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */
+		.subdevice    = 0x4091,
+		.driver_data  = SAA7134_BOARD_BEHOLD_409FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5456, /* GoTView */
+		.subdevice    = 0x7135,
+		.driver_data  = SAA7134_BOARD_GOTVIEW_7135,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2004,
+		.driver_data  = SAA7134_BOARD_PHILIPS_EUROPA,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc900,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_DVBT_300,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x185b,
+		.subdevice    = 0xc901,
+		.driver_data  = SAA7134_BOARD_VIDEOMATE_DVBT_200,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1435,
+		.subdevice    = 0x7350,
+		.driver_data  = SAA7134_BOARD_RTD_VFG7350,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1435,
+		.subdevice    = 0x7330,
+		.driver_data  = SAA7134_BOARD_RTD_VFG7330,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x1044,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1131,
+		.subdevice    = 0x4ee9,
+		.driver_data  = SAA7134_BOARD_MONSTERTV_MOBILE,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x11bd,
+		.subdevice    = 0x002e,
+		.driver_data  = SAA7134_BOARD_PINNACLE_PCTV_110i,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4862,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2018,
+		.driver_data  = SAA7134_BOARD_PHILIPS_TIGER,
+	},{
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -2530,9 +3038,10 @@
 	switch (dev->board) {
 	case SAA7134_BOARD_FLYVIDEO2000:
 	case SAA7134_BOARD_FLYVIDEO3000:
-		dev->has_remote = 1;
+		dev->has_remote = SAA7134_REMOTE_GPIO;
 		board_flyvideo(dev);
 		break;
+	case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
 	case SAA7134_BOARD_FLYTVPLATINUM_FM:
 	case SAA7134_BOARD_CINERGY400:
 	case SAA7134_BOARD_CINERGY600:
@@ -2550,10 +3059,16 @@
 /*      case SAA7134_BOARD_SABRENT_SBTTVFM:  */ /* not finished yet */
 	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
 	case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
 	case SAA7134_BOARD_MANLI_MTV001:
 	case SAA7134_BOARD_MANLI_MTV002:
+	case SAA7134_BOARD_BEHOLD_409FM:
 	case SAA7134_BOARD_AVACSSMARTTV:
-		dev->has_remote = 1;
+	case SAA7134_BOARD_GOTVIEW_7135:
+	case SAA7134_BOARD_KWORLD_TERMINATOR:
+	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+		dev->has_remote = SAA7134_REMOTE_GPIO;
 		break;
 	case SAA7134_BOARD_MD5044:
 		printk("%s: seems there are two different versions of the MD5044\n"
@@ -2565,11 +3080,14 @@
 		/* power-up tuner chip */
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00040000, 0x00040000);
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
-		msleep(1);
+	case SAA7134_BOARD_MONSTERTV_MOBILE:
+		/* power-up tuner chip */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00040000, 0x00040000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000004);
 		break;
 	case SAA7134_BOARD_FLYDVBTDUO:
 	case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS:
-	/* turn the fan on Hac: static for the time being */
+		/* turn the fan on */
 		saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
 		saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
 		break;
@@ -2579,6 +3097,22 @@
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
 		msleep(1);
 		break;
+	case SAA7134_BOARD_RTD_VFG7350:
+
+		/*
+		 * Make sure Production Test Register at offset 0x1D1 is cleared
+		 * to take chip out of test mode.  Clearing bit 4 (TST_EN_AOUT)
+		 * prevents pin 105 from remaining low; keeping pin 105 low
+		 * continually resets the SAA6752 chip.
+		 */
+
+		saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
+		break;
+	/* i2c remotes */
+	case SAA7134_BOARD_PINNACLE_PCTV_110i:
+	case SAA7134_BOARD_UPMOST_PURPLE_TV:
+		dev->has_remote = SAA7134_REMOTE_I2C;
+		break;
 	}
 	return 0;
 }
@@ -2613,7 +3147,7 @@
 				saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
 		break;
-case SAA7134_BOARD_MD7134:
+	case SAA7134_BOARD_MD7134:
 		{
 		struct tuner_setup tun_setup;
 		u8 subaddr;
@@ -2680,6 +3214,33 @@
 		saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
 		}
 		break;
+	case SAA7134_BOARD_PHILIPS_EUROPA:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+		/* The Philips EUROPA based hybrid boards have the tuner connected through
+		 * the channel decoder. We have to make it transparent to find it
+		 */
+		{
+		struct tuner_setup tun_setup;
+		u8 data[] = { 0x07, 0x02};
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+		tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+		tun_setup.type = dev->tuner_type;
+		tun_setup.addr = dev->tuner_addr;
+
+		saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+		}
+		break;
+	case SAA7134_BOARD_PHILIPS_TIGER:
+	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+		/* this is a hybrid board, initialize to analog mode */
+		{
+		u8 data[] = { 0x3c, 0x33, 0x68};
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		}
+		break;
 	}
 	return 0;
 }
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index e5e36f3..19b8874 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -57,6 +57,10 @@
 module_param(oss, int, 0444);
 MODULE_PARM_DESC(oss,"register oss devices (default: no)");
 
+static unsigned int alsa = 0;
+module_param(alsa, int, 0444);
+MODULE_PARM_DESC(alsa,"register alsa devices (default: no)");
+
 static unsigned int latency = UNSET;
 module_param(latency, int, 0444);
 MODULE_PARM_DESC(latency,"pci latency timer");
@@ -190,6 +194,7 @@
 
 static int need_empress;
 static int need_dvb;
+static int need_alsa;
 
 static int pending_call(struct notifier_block *self, unsigned long state,
 			void *module)
@@ -197,10 +202,12 @@
 	if (module != THIS_MODULE || state != MODULE_STATE_LIVE)
 		return NOTIFY_DONE;
 
-        if (need_empress)
-                request_module("saa7134-empress");
-        if (need_dvb)
-                request_module("saa7134-dvb");
+	if (need_empress)
+		request_module("saa7134-empress");
+	if (need_dvb)
+		request_module("saa7134-dvb");
+	if (need_alsa)
+		request_module("saa7134-alsa");
 	return NOTIFY_DONE;
 }
 
@@ -275,8 +282,8 @@
 
 int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
 {
-        __le32       *cpu;
-        dma_addr_t   dma_addr;
+	__le32       *cpu;
+	dma_addr_t   dma_addr;
 
 	cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
 	if (NULL == cpu)
@@ -436,7 +443,7 @@
 		ctrl |= SAA7134_MAIN_CTRL_TE0;
 		irq  |= SAA7134_IRQ1_INTE_RA0_1 |
 			SAA7134_IRQ1_INTE_RA0_0;
-	        cap = dev->video_q.curr->vb.field;
+		cap = dev->video_q.curr->vb.field;
 	}
 
 	/* video capture -- dma 1+2 (planar modes) */
@@ -465,7 +472,7 @@
 	}
 
 	/* audio capture -- dma 3 */
-	if (dev->oss.dma_running) {
+	if (dev->dmasound.dma_running) {
 		ctrl |= SAA7134_MAIN_CTRL_TE6;
 		irq  |= SAA7134_IRQ1_INTE_RA3_1 |
 			SAA7134_IRQ1_INTE_RA3_0;
@@ -570,6 +577,17 @@
 				       dev->name);
 			goto out;
 		}
+
+		/* If alsa support is active and we get a sound report, exit
+		   and let the saa7134-alsa module deal with it */
+
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && alsa)  {
+			if (irq_debug > 1)
+				printk(KERN_DEBUG "%s/irq: ignoring interrupt for ALSA\n",
+				       dev->name);
+			goto out;
+		}
+
 		handled = 1;
 		saa_writel(SAA7134_IRQ_REPORT,report);
 		if (irq_debug)
@@ -591,13 +609,17 @@
 		    card_has_mpeg(dev))
 			saa7134_irq_ts_done(dev,status);
 
-		if ((report & SAA7134_IRQ_REPORT_DONE_RA3))
-			saa7134_irq_oss_done(dev,status);
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA3))  {
+			if (oss) {
+				saa7134_irq_oss_done(dev,status);
+			}
+		}
 
 		if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
 			       SAA7134_IRQ_REPORT_GPIO18)) &&
 		    dev->remote)
 			saa7134_input_irq(dev);
+
 	}
 
 	if (10 == loop) {
@@ -636,7 +658,7 @@
 
 	saa_writel(SAA7134_IRQ1, 0);
 	saa_writel(SAA7134_IRQ2, 0);
-        init_MUTEX(&dev->lock);
+	init_MUTEX(&dev->lock);
 	spin_lock_init(&dev->slock);
 
 	saa7134_track_gpio(dev,"pre-init");
@@ -646,14 +668,6 @@
 		saa7134_ts_init1(dev);
 	saa7134_input_init1(dev);
 
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		saa7134_oss_init1(dev);
-		break;
-	}
-
 	/* RAM FIFO config */
 	saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
 	saa_writel(SAA7134_THRESHOULD,0x02020202);
@@ -668,6 +682,21 @@
 		   SAA7134_MAIN_CTRL_ESFE  |
 		   SAA7134_MAIN_CTRL_EBDAC);
 
+	/*
+	 * Initialize OSS _after_ enabling audio clock PLL and audio processing.
+	 * OSS initialization writes to registers via the audio DSP; these
+	 * writes will fail unless the audio clock has been started.  At worst,
+	 * audio will not work.
+	 */
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		saa7134_oss_init1(dev);
+		break;
+	}
+
 	/* enable peripheral devices */
 	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
 
@@ -687,7 +716,7 @@
 	saa7134_tvaudio_init2(dev);
 
 	/* enable IRQ's */
-   	irq2_mask =
+	irq2_mask =
 		SAA7134_IRQ2_INTE_DEC3    |
 		SAA7134_IRQ2_INTE_DEC2    |
 		SAA7134_IRQ2_INTE_DEC1    |
@@ -695,10 +724,12 @@
 		SAA7134_IRQ2_INTE_PE      |
 		SAA7134_IRQ2_INTE_AR;
 
-	if (dev->has_remote)
+	if (dev->has_remote == SAA7134_REMOTE_GPIO)
 		irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18  |
 			      SAA7134_IRQ2_INTE_GPIO18A |
 			      SAA7134_IRQ2_INTE_GPIO16  );
+	else if (dev->has_remote == SAA7134_REMOTE_I2C)
+		request_module("ir-kbd-i2c");
 
 	saa_writel(SAA7134_IRQ1, 0);
 	saa_writel(SAA7134_IRQ2, irq2_mask);
@@ -872,8 +903,8 @@
 
 	/* print pci info */
 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
-        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
-        printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
 	       "latency: %d, mmio: 0x%lx\n", dev->name,
 	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
 	       dev->pci_lat,pci_resource_start(pci_dev,0));
@@ -897,7 +928,7 @@
 	dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
 	if (UNSET != tuner[dev->nr])
 		dev->tuner_type = tuner[dev->nr];
-        printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+	printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
 	       dev->name,pci_dev->subsystem_vendor,
 	       pci_dev->subsystem_device,saa7134_boards[dev->board].name,
 	       dev->board, card[dev->nr] == dev->board ?
@@ -947,14 +978,20 @@
 		request_module("tuner");
 	if (dev->tda9887_conf)
 		request_module("tda9887");
-  	if (card_is_empress(dev)) {
+	if (card_is_empress(dev)) {
 		request_module("saa6752hs");
 		request_module_depend("saa7134-empress",&need_empress);
 	}
 
-  	if (card_is_dvb(dev))
+	if (card_is_dvb(dev))
 		request_module_depend("saa7134-dvb",&need_dvb);
 
+	if (!oss && alsa) {
+		dprintk("Requesting ALSA module\n");
+		request_module_depend("saa7134-alsa",&need_alsa);
+	}
+
+
 	v4l2_prio_init(&dev->prio);
 
 	/* register v4l devices */
@@ -993,22 +1030,22 @@
 	case PCI_DEVICE_ID_PHILIPS_SAA7133:
 	case PCI_DEVICE_ID_PHILIPS_SAA7135:
 		if (oss) {
-			err = dev->oss.minor_dsp =
+			err = dev->dmasound.minor_dsp =
 				register_sound_dsp(&saa7134_dsp_fops,
 						   dsp_nr[dev->nr]);
 			if (err < 0) {
 				goto fail4;
 			}
 			printk(KERN_INFO "%s: registered device dsp%d\n",
-			       dev->name,dev->oss.minor_dsp >> 4);
+			       dev->name,dev->dmasound.minor_dsp >> 4);
 
-			err = dev->oss.minor_mixer =
+			err = dev->dmasound.minor_mixer =
 				register_sound_mixer(&saa7134_mixer_fops,
 						     mixer_nr[dev->nr]);
 			if (err < 0)
 				goto fail5;
 			printk(KERN_INFO "%s: registered device mixer%d\n",
-			       dev->name,dev->oss.minor_mixer >> 4);
+			       dev->name,dev->dmasound.minor_mixer >> 4);
 		}
 		break;
 	}
@@ -1035,7 +1072,7 @@
 	case PCI_DEVICE_ID_PHILIPS_SAA7133:
 	case PCI_DEVICE_ID_PHILIPS_SAA7135:
 		if (oss)
-			unregister_sound_dsp(dev->oss.minor_dsp);
+			unregister_sound_dsp(dev->dmasound.minor_dsp);
 		break;
 	}
  fail4:
@@ -1055,7 +1092,7 @@
 
 static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
 {
-        struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+	struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
 	struct list_head *item;
 	struct saa7134_mpeg_ops *mops;
 
@@ -1093,8 +1130,8 @@
 	case PCI_DEVICE_ID_PHILIPS_SAA7133:
 	case PCI_DEVICE_ID_PHILIPS_SAA7135:
 		if (oss) {
-			unregister_sound_mixer(dev->oss.minor_mixer);
-			unregister_sound_dsp(dev->oss.minor_dsp);
+			unregister_sound_mixer(dev->dmasound.minor_mixer);
+			unregister_sound_dsp(dev->dmasound.minor_dsp);
 		}
 		break;
 	}
@@ -1149,10 +1186,10 @@
 /* ----------------------------------------------------------- */
 
 static struct pci_driver saa7134_pci_driver = {
-        .name     = "saa7134",
-        .id_table = saa7134_pci_tbl,
-        .probe    = saa7134_initdev,
-        .remove   = __devexit_p(saa7134_finidev),
+	.name     = "saa7134",
+	.id_table = saa7134_pci_tbl,
+	.probe    = saa7134_initdev,
+	.remove   = __devexit_p(saa7134_finidev),
 };
 
 static int saa7134_init(void)
@@ -1188,6 +1225,13 @@
 EXPORT_SYMBOL(saa7134_devlist);
 EXPORT_SYMBOL(saa7134_boards);
 
+/* ----------------- For ALSA -------------------------------- */
+
+EXPORT_SYMBOL(saa7134_pgtable_free);
+EXPORT_SYMBOL(saa7134_pgtable_build);
+EXPORT_SYMBOL(saa7134_pgtable_alloc);
+EXPORT_SYMBOL(saa7134_set_dmabits);
+
 /* ----------------------------------------------------------- */
 /*
  * Local variables:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 639ae51..e016480 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -29,7 +29,6 @@
 #include <linux/kthread.h>
 #include <linux/suspend.h>
 
-
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
@@ -40,6 +39,10 @@
 #ifdef HAVE_TDA1004X
 # include "tda1004x.h"
 #endif
+#ifdef HAVE_NXT200X
+# include "nxt200x.h"
+# include "dvb-pll.h"
+#endif
 
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
@@ -151,25 +154,12 @@
 /* ------------------------------------------------------------------ */
 
 #ifdef HAVE_TDA1004X
-static int philips_tu1216_pll_init(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
-	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
 
-	/* setup PLL configuration */
-	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-	msleep(1);
-
-	return 0;
-}
-
-static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	u8 tuner_buf[4];
-	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
 			sizeof(tuner_buf) };
 	int tuner_frequency = 0;
 	u8 band, cp, filter;
@@ -242,11 +232,36 @@
 
 	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
-
 	msleep(1);
 	return 0;
 }
 
+static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+	/* setup PLL configuration */
+	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+		return -EIO;
+	msleep(1);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tu1216_pll_60_init(struct dvb_frontend *fe)
+{
+	return philips_tda6651_pll_init(0x60, fe);
+}
+
+static int philips_tu1216_pll_60_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	return philips_tda6651_pll_set(0x60, fe, params);
+}
+
 static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
 					   const struct firmware **fw, char *name)
 {
@@ -254,22 +269,108 @@
 	return request_firmware(fw, name, &dev->pci->dev);
 }
 
-static struct tda1004x_config philips_tu1216_config = {
+static struct tda1004x_config philips_tu1216_60_config = {
 
 	.demod_address = 0x8,
 	.invert        = 1,
-	.invert_oclk   = 1,
+	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_4M,
 	.agc_config    = TDA10046_AGC_DEFAULT,
 	.if_freq       = TDA10046_FREQ_3617,
-	.pll_init      = philips_tu1216_pll_init,
-	.pll_set       = philips_tu1216_pll_set,
+	.pll_init      = philips_tu1216_pll_60_init,
+	.pll_set       = philips_tu1216_pll_60_set,
 	.pll_sleep     = NULL,
 	.request_firmware = philips_tu1216_request_firmware,
 };
 
 /* ------------------------------------------------------------------ */
 
+static int philips_tu1216_pll_61_init(struct dvb_frontend *fe)
+{
+	return philips_tda6651_pll_init(0x61, fe);
+}
+
+static int philips_tu1216_pll_61_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	return philips_tda6651_pll_set(0x61, fe, params);
+}
+
+static struct tda1004x_config philips_tu1216_61_config = {
+
+	.demod_address = 0x8,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_4M,
+	.agc_config    = TDA10046_AGC_DEFAULT,
+	.if_freq       = TDA10046_FREQ_3617,
+	.pll_init      = philips_tu1216_pll_61_init,
+	.pll_set       = philips_tu1216_pll_61_set,
+	.pll_sleep     = NULL,
+	.request_firmware = philips_tu1216_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int philips_europa_pll_init(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
+	struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+	/* setup PLL configuration */
+	if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+		return -EIO;
+	msleep(1);
+
+	/* switch the board to dvb mode */
+	init_msg.addr = 0x43;
+	init_msg.len  = 0x02;
+	msg[0] = 0x00;
+	msg[1] = 0x40;
+	if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
+static int philips_td1316_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	return philips_tda6651_pll_set(0x61, fe, params);
+}
+
+static void philips_europa_analog(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	/* this message actually turns the tuner back to analog mode */
+	static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
+	struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+	i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+	msleep(1);
+
+	/* switch the board to analog mode */
+	analog_msg.addr = 0x43;
+	analog_msg.len  = 0x02;
+	msg[0] = 0x00;
+	msg[1] = 0x14;
+	i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+}
+
+static struct tda1004x_config philips_europa_config = {
+
+	.demod_address = 0x8,
+	.invert        = 0,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_4M,
+	.agc_config    = TDA10046_AGC_IFO_AUTO_POS,
+	.if_freq       = TDA10046_FREQ_052,
+	.pll_init      = philips_europa_pll_init,
+	.pll_set       = philips_td1316_pll_set,
+	.pll_sleep     = philips_europa_analog,
+	.request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
 
 static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
 {
@@ -382,7 +483,6 @@
 	return 0;
 }
 
-#ifdef HAVE_TDA1004X
 static struct tda1004x_config medion_cardbus = {
 	.demod_address = 0x08,
 	.invert        = 1,
@@ -395,7 +495,6 @@
 	.pll_sleep	   = philips_fmd1216_analog,
 	.request_firmware = NULL,
 };
-#endif
 
 /* ------------------------------------------------------------------ */
 
@@ -452,7 +551,7 @@
 	u8 tuner_buf[14];
 
 	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,
-		                        .len = sizeof(tuner_buf) };
+					.len = sizeof(tuner_buf) };
 	int i, tuner_freq, if_freq;
 	u32 N;
 	switch (params->u.ofdm.bandwidth) {
@@ -511,7 +610,7 @@
 	struct saa7134_dev *dev = fe->dvb->priv;
 	static u8 tda827x_sleep[] = { 0x30, 0xd0};
 	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
-	                            .len = sizeof(tda827x_sleep) };
+				    .len = sizeof(tda827x_sleep) };
 	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
 }
 
@@ -527,6 +626,202 @@
 	.pll_sleep	   = philips_tda827x_pll_sleep,
 	.request_firmware = NULL,
 };
+
+/* ------------------------------------------------------------------ */
+
+struct tda827xa_data {
+	u32 lomax;
+	u8  svco;
+	u8  spd;
+	u8  scr;
+	u8  sbs;
+	u8  gc3;
+};
+
+static struct tda827xa_data tda827xa_dvbt[] = {
+	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+	{ .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}};
+
+
+static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	u8 tuner_buf[14];
+	unsigned char reg2[2];
+
+	struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf};
+	int i, tuner_freq, if_freq;
+	u32 N;
+
+	switch (params->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		if_freq = 4000000;
+		break;
+	case BANDWIDTH_7_MHZ:
+		if_freq = 4500000;
+		break;
+	default:		   /* 8 MHz or Auto */
+		if_freq = 5000000;
+		break;
+	}
+	tuner_freq = params->frequency + if_freq;
+
+	i = 0;
+	while (tda827xa_dvbt[i].lomax < tuner_freq) {
+		if(tda827xa_dvbt[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
+	tuner_buf[0] = 0;            // subaddress
+	tuner_buf[1] = N >> 8;
+	tuner_buf[2] = N & 0xff;
+	tuner_buf[3] = 0;
+	tuner_buf[4] = 0x16;
+	tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
+			tda827xa_dvbt[i].sbs;
+	tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
+	tuner_buf[7] = 0x0c;
+	tuner_buf[8] = 0x06;
+	tuner_buf[9] = 0x24;
+	tuner_buf[10] = 0xff;
+	tuner_buf[11] = 0x60;
+	tuner_buf[12] = 0x00;
+	tuner_buf[13] = 0x39;  // lpsel
+	msg.len = 14;
+	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+
+	msg.buf= reg2;
+	msg.len = 2;
+	reg2[0] = 0x60;
+	reg2[1] = 0x3c;
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+	reg2[0] = 0xa0;
+	reg2[1] = 0x40;
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+	msleep(2);
+	/* correct CP value */
+	reg2[0] = 0x30;
+	reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
+	msg.len = 2;
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+	msleep(550);
+	reg2[0] = 0x50;
+	reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+	return 0;
+
+}
+
+static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	static u8 tda827xa_sleep[] = { 0x30, 0x90};
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
+				    .len = sizeof(tda827xa_sleep) };
+	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	int ret;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	static u8 tda8290_close[] = { 0x21, 0xc0};
+	static u8 tda8290_open[]  = { 0x21, 0x80};
+	struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+	/* close tda8290 i2c bridge */
+	tda8290_msg.buf = tda8290_close;
+	ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+	if (ret != 1)
+		return -EIO;
+	msleep(20);
+	ret = philips_tda827xa_pll_set(0x61, fe, params);
+	if (ret != 0)
+		return ret;
+	/* open tda8290 i2c bridge */
+	tda8290_msg.buf = tda8290_open;
+	i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+	return ret;
+};
+
+static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	static u8 data[] = { 0x3c, 0x33, 0x6a};
+	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static void philips_tiger_analog_mode(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	static u8 data[] = { 0x3c, 0x33, 0x68};
+	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+	philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config philips_tiger_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.if_freq       = TDA10046_FREQ_045,
+	.pll_init      = philips_tiger_dvb_mode,
+	.pll_set       = philips_tiger_pll_set,
+	.pll_sleep     = philips_tiger_analog_mode,
+	.request_firmware = NULL,
+};
+
+#endif
+
+/* ------------------------------------------------------------------ */
+
+#ifdef HAVE_NXT200X
+static struct nxt200x_config avertvhda180 = {
+	.demod_address    = 0x0a,
+	.pll_address      = 0x61,
+	.pll_desc         = &dvb_pll_tdhu2,
+};
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -558,7 +853,7 @@
 						    &dev->i2c_adap);
 		break;
 	case SAA7134_BOARD_PHILIPS_TOUGH:
-		dev->dvb.frontend = tda10046_attach(&philips_tu1216_config,
+		dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
 						    &dev->i2c_adap);
 		break;
 	case SAA7134_BOARD_FLYDVBTDUO:
@@ -569,6 +864,31 @@
 		dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
 						    &dev->i2c_adap);
 		break;
+	case SAA7134_BOARD_PHILIPS_EUROPA:
+		dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+						    &dev->i2c_adap);
+		break;
+	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+		dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+						    &dev->i2c_adap);
+		break;
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+		dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
+						    &dev->i2c_adap);
+		break;
+	case SAA7134_BOARD_PHILIPS_TIGER:
+		dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+						    &dev->i2c_adap);
+		break;
+	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+		dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+						    &dev->i2c_adap);
+		break;
+#endif
+#ifdef HAVE_NXT200X
+	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
+		dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+		break;
 #endif
 	default:
 		printk("%s: Huh? unknown DVB card?\n",dev->name);
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 77b627e..e9ec69e 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -55,7 +55,7 @@
 
 	saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
 	msleep(10);
-   	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
 	msleep(100);
 	dev->empress_started = 0;
 }
@@ -65,7 +65,7 @@
 	ts_reset_encoder(dev);
 	saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
 	dev->empress_started = 1;
- 	return 0;
+	return 0;
 }
 
 /* ------------------------------------------------------------------ */
@@ -169,7 +169,7 @@
 		struct v4l2_capability *cap = arg;
 
 		memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
+		strcpy(cap->driver, "saa7134");
 		strlcpy(cap->card, saa7134_boards[dev->board].name,
 			sizeof(cap->card));
 		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 711aa8e..7575043 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -239,7 +239,7 @@
 	unsigned char data;
 	int addr,rc,i,byte;
 
-  	status = i2c_get_status(dev);
+	status = i2c_get_status(dev);
 	if (!i2c_is_idle(status))
 		if (!i2c_reset(dev))
 			return -EIO;
@@ -296,7 +296,7 @@
 	rc = -EIO;
 	if (!i2c_is_busy_wait(dev))
 		goto err;
-  	status = i2c_get_status(dev);
+	status = i2c_get_status(dev);
 	if (i2c_is_error(status))
 		goto err;
 	/* ensure that the bus is idle for at least one bit slot */
@@ -335,6 +335,20 @@
 	d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
 		 client->driver->name, client->addr, client->name);
 
+	/* Am I an i2c remote control? */
+
+	switch (client->addr) {
+		case 0x7a:
+		case 0x47:
+		{
+			struct IR_i2c *ir = i2c_get_clientdata(client);
+			d1printk("%s i2c IR detected (%s).\n",
+				 client->driver->name,ir->phys);
+			saa7134_set_i2c_ir(dev,ir);
+			break;
+		}
+	}
+
 	if (!client->driver->command)
 		return 0;
 
@@ -348,12 +362,12 @@
 
 			client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
-        }
+	}
 
 	if (tuner != UNSET) {
 
-	        tun_setup.type = tuner;
-	        tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
+		tun_setup.type = tuner;
+		tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
 
 		if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
 
@@ -361,11 +375,11 @@
 
 			client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
-        }
+	}
 
 	client->driver->command(client, TDA9887_SET_CONFIG, &conf);
 
-        return 0;
+	return 0;
 }
 
 static struct i2c_algorithm saa7134_algo = {
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 242cb23..329accd 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -39,6 +39,8 @@
 
 #define dprintk(fmt, arg...)	if (ir_debug) \
 	printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
+#define i2cdprintk(fmt, arg...)    if (ir_debug) \
+	printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
 
 /* ---------------------------------------------------------------------- */
 
@@ -114,24 +116,24 @@
 /* Alfons Geser <a.geser@cox.net>
  * updates from Job D. R. Borges <jobdrb@ig.com.br> */
 static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
-        [ 18 ] = KEY_POWER,
-        [  1 ] = KEY_TV,             // DVR
-        [ 21 ] = KEY_DVD,            // DVD
-        [ 23 ] = KEY_AUDIO,          // music
-                                     // DVR mode / DVD mode / music mode
+	[ 18 ] = KEY_POWER,
+	[  1 ] = KEY_TV,             // DVR
+	[ 21 ] = KEY_DVD,            // DVD
+	[ 23 ] = KEY_AUDIO,          // music
+				     // DVR mode / DVD mode / music mode
 
-        [ 27 ] = KEY_MUTE,           // mute
-        [  2 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
-        [ 30 ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
-        [ 22 ] = KEY_ZOOM,           // full screen
-        [ 28 ] = KEY_VIDEO,          // video source / eject / delall
-        [ 29 ] = KEY_RESTART,        // playback / angle / del
-        [ 47 ] = KEY_SEARCH,         // scan / menu / playlist
-        [ 48 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
+	[ 27 ] = KEY_MUTE,           // mute
+	[  2 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
+	[ 30 ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
+	[ 22 ] = KEY_ZOOM,           // full screen
+	[ 28 ] = KEY_VIDEO,          // video source / eject / delall
+	[ 29 ] = KEY_RESTART,        // playback / angle / del
+	[ 47 ] = KEY_SEARCH,         // scan / menu / playlist
+	[ 48 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
 
-        [ 49 ] = KEY_HELP,           // help
-        [ 50 ] = KEY_MODE,           // num/memo
-        [ 51 ] = KEY_ESC,            // cancel
+	[ 49 ] = KEY_HELP,           // help
+	[ 50 ] = KEY_MODE,           // num/memo
+	[ 51 ] = KEY_ESC,            // cancel
 
 	[ 12 ] = KEY_UP,             // up
 	[ 16 ] = KEY_DOWN,           // down
@@ -148,24 +150,24 @@
 	[ 45 ] = KEY_PLAY,           // play
 	[ 46 ] = KEY_SHUFFLE,        // snapshot / shuffle
 
-        [  0 ] = KEY_KP0,
-        [  5 ] = KEY_KP1,
-        [  6 ] = KEY_KP2,
-        [  7 ] = KEY_KP3,
-        [  9 ] = KEY_KP4,
-        [ 10 ] = KEY_KP5,
-        [ 11 ] = KEY_KP6,
-        [ 13 ] = KEY_KP7,
-        [ 14 ] = KEY_KP8,
-        [ 15 ] = KEY_KP9,
+	[  0 ] = KEY_KP0,
+	[  5 ] = KEY_KP1,
+	[  6 ] = KEY_KP2,
+	[  7 ] = KEY_KP3,
+	[  9 ] = KEY_KP4,
+	[ 10 ] = KEY_KP5,
+	[ 11 ] = KEY_KP6,
+	[ 13 ] = KEY_KP7,
+	[ 14 ] = KEY_KP8,
+	[ 15 ] = KEY_KP9,
 
-        [ 42 ] = KEY_VOLUMEUP,
-        [ 17 ] = KEY_VOLUMEDOWN,
-        [ 24 ] = KEY_CHANNELUP,      // CH.tracking up
-        [ 25 ] = KEY_CHANNELDOWN,    // CH.tracking down
+	[ 42 ] = KEY_VOLUMEUP,
+	[ 17 ] = KEY_VOLUMEDOWN,
+	[ 24 ] = KEY_CHANNELUP,      // CH.tracking up
+	[ 25 ] = KEY_CHANNELDOWN,    // CH.tracking down
 
-        [ 19 ] = KEY_KPENTER,        // enter
-        [ 33 ] = KEY_KPDOT,          // . (decimal dot)
+	[ 19 ] = KEY_KPENTER,        // enter
+	[ 33 ] = KEY_KPDOT,          // . (decimal dot)
 };
 
 static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
@@ -401,7 +403,183 @@
 
 	// 0x1d unused ?
 };
-/* ---------------------------------------------------------------------- */
+
+
+/* Mike Baikov <mike@baikov.com> */
+static IR_KEYTAB_TYPE gotview7135_codes[IR_KEYTAB_SIZE] = {
+
+	[ 33 ] = KEY_POWER,
+	[ 105] = KEY_TV,
+	[ 51 ] = KEY_KP0,
+	[ 81 ] = KEY_KP1,
+	[ 49 ] = KEY_KP2,
+	[ 113] = KEY_KP3,
+	[ 59 ] = KEY_KP4,
+	[ 88 ] = KEY_KP5,
+	[ 65 ] = KEY_KP6,
+	[ 72 ] = KEY_KP7,
+	[ 48 ] = KEY_KP8,
+	[ 83 ] = KEY_KP9,
+	[ 115] = KEY_AGAIN, /* LOOP */
+	[ 10 ] = KEY_AUDIO,
+	[ 97 ] = KEY_PRINT, /* PREVIEW */
+	[ 122] = KEY_VIDEO,
+	[ 32 ] = KEY_CHANNELUP,
+	[ 64 ] = KEY_CHANNELDOWN,
+	[ 24 ] = KEY_VOLUMEDOWN,
+	[ 80 ] = KEY_VOLUMEUP,
+	[ 16 ] = KEY_MUTE,
+	[ 74 ] = KEY_SEARCH,
+	[ 123] = KEY_SHUFFLE, /* SNAPSHOT */
+	[ 34 ] = KEY_RECORD,
+	[ 98 ] = KEY_STOP,
+	[ 120] = KEY_PLAY,
+	[ 57 ] = KEY_REWIND,
+	[ 89 ] = KEY_PAUSE,
+	[ 25 ] = KEY_FORWARD,
+	[  9 ] = KEY_ZOOM,
+
+	[ 82 ] = KEY_F21, /* LIVE TIMESHIFT */
+	[ 26 ] = KEY_F22, /* MIN TIMESHIFT */
+	[ 58 ] = KEY_F23, /* TIMESHIFT */
+	[ 112] = KEY_F24, /* NORMAL TIMESHIFT */
+};
+
+static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
+	[ 0x3  ] = KEY_POWER,
+	[ 0x6f ] = KEY_MUTE,
+	[ 0x10 ] = KEY_BACKSPACE,       /* Recall */
+
+	[ 0x11 ] = KEY_KP0,
+	[ 0x4  ] = KEY_KP1,
+	[ 0x5  ] = KEY_KP2,
+	[ 0x6  ] = KEY_KP3,
+	[ 0x8  ] = KEY_KP4,
+	[ 0x9  ] = KEY_KP5,
+	[ 0xa  ] = KEY_KP6,
+	[ 0xc  ] = KEY_KP7,
+	[ 0xd  ] = KEY_KP8,
+	[ 0xe  ] = KEY_KP9,
+	[ 0x12 ] = KEY_KPDOT,           /* 100+ */
+
+	[ 0x7  ] = KEY_VOLUMEUP,
+	[ 0xb  ] = KEY_VOLUMEDOWN,
+	[ 0x1a ] = KEY_KPPLUS,
+	[ 0x18 ] = KEY_KPMINUS,
+	[ 0x15 ] = KEY_UP,
+	[ 0x1d ] = KEY_DOWN,
+	[ 0xf  ] = KEY_CHANNELUP,
+	[ 0x13 ] = KEY_CHANNELDOWN,
+	[ 0x48 ] = KEY_ZOOM,
+
+	[ 0x1b ] = KEY_VIDEO,           /* Video source */
+	[ 0x49 ] = KEY_LANGUAGE,        /* MTS Select */
+	[ 0x19 ] = KEY_SEARCH,          /* Auto Scan */
+
+	[ 0x4b ] = KEY_RECORD,
+	[ 0x46 ] = KEY_PLAY,
+	[ 0x45 ] = KEY_PAUSE,           /* Pause */
+	[ 0x44 ] = KEY_STOP,
+	[ 0x40 ] = KEY_FORWARD,         /* Forward ? */
+	[ 0x42 ] = KEY_REWIND,          /* Backward ? */
+
+};
+
+static IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+	[ 0x59 ] = KEY_MUTE,
+	[ 0x4a ] = KEY_POWER,
+
+	[ 0x18 ] = KEY_TEXT,
+	[ 0x26 ] = KEY_TV,
+	[ 0x3d ] = KEY_PRINT,
+
+	[ 0x48 ] = KEY_RED,
+	[ 0x04 ] = KEY_GREEN,
+	[ 0x11 ] = KEY_YELLOW,
+	[ 0x00 ] = KEY_BLUE,
+
+	[ 0x2d ] = KEY_VOLUMEUP,
+	[ 0x1e ] = KEY_VOLUMEDOWN,
+
+	[ 0x49 ] = KEY_MENU,
+
+	[ 0x16 ] = KEY_CHANNELUP,
+	[ 0x17 ] = KEY_CHANNELDOWN,
+
+	[ 0x20 ] = KEY_UP,
+	[ 0x21 ] = KEY_DOWN,
+	[ 0x22 ] = KEY_LEFT,
+	[ 0x23 ] = KEY_RIGHT,
+	[ 0x0d ] = KEY_SELECT,
+
+
+
+	[ 0x08 ] = KEY_BACK,
+	[ 0x07 ] = KEY_REFRESH,
+
+	[ 0x2f ] = KEY_ZOOM,
+	[ 0x29 ] = KEY_RECORD,
+
+	[ 0x4b ] = KEY_PAUSE,
+	[ 0x4d ] = KEY_REWIND,
+	[ 0x2e ] = KEY_PLAY,
+	[ 0x4e ] = KEY_FORWARD,
+	[ 0x53 ] = KEY_PREVIOUS,
+	[ 0x4c ] = KEY_STOP,
+	[ 0x54 ] = KEY_NEXT,
+
+	[ 0x69 ] = KEY_KP0,
+	[ 0x6a ] = KEY_KP1,
+	[ 0x6b ] = KEY_KP2,
+	[ 0x6c ] = KEY_KP3,
+	[ 0x6d ] = KEY_KP4,
+	[ 0x6e ] = KEY_KP5,
+	[ 0x6f ] = KEY_KP6,
+	[ 0x70 ] = KEY_KP7,
+	[ 0x71 ] = KEY_KP8,
+	[ 0x72 ] = KEY_KP9,
+
+	[ 0x74 ] = KEY_CHANNEL,
+	[ 0x0a ] = KEY_BACKSPACE,
+};
+
+/* Mapping for the 28 key remote control as seen at
+   http://www.sednacomputer.com/photo/cardbus-tv.jpg
+   Pavel Mihaylov <bin@bash.info> */
+static IR_KEYTAB_TYPE pctv_sedna_codes[IR_KEYTAB_SIZE] = {
+	[    0 ] = KEY_KP0,
+	[    1 ] = KEY_KP1,
+	[    2 ] = KEY_KP2,
+	[    3 ] = KEY_KP3,
+	[    4 ] = KEY_KP4,
+	[    5 ] = KEY_KP5,
+	[    6 ] = KEY_KP6,
+	[    7 ] = KEY_KP7,
+	[    8 ] = KEY_KP8,
+	[    9 ] = KEY_KP9,
+
+	[ 0x0a ] = KEY_AGAIN,          /* Recall */
+	[ 0x0b ] = KEY_CHANNELUP,
+	[ 0x0c ] = KEY_VOLUMEUP,
+	[ 0x0d ] = KEY_MODE,           /* Stereo */
+	[ 0x0e ] = KEY_STOP,
+	[ 0x0f ] = KEY_PREVIOUSSONG,
+	[ 0x10 ] = KEY_ZOOM,
+	[ 0x11 ] = KEY_TUNER,          /* Source */
+	[ 0x12 ] = KEY_POWER,
+	[ 0x13 ] = KEY_MUTE,
+	[ 0x15 ] = KEY_CHANNELDOWN,
+	[ 0x18 ] = KEY_VOLUMEDOWN,
+	[ 0x19 ] = KEY_SHUFFLE,        /* Snapshot */
+	[ 0x1a ] = KEY_NEXTSONG,
+	[ 0x1b ] = KEY_TEXT,           /* Time Shift */
+	[ 0x1c ] = KEY_RADIO,          /* FM Radio */
+	[ 0x1d ] = KEY_RECORD,
+	[ 0x1e ] = KEY_PAUSE,
+};
+
+
+/* -------------------- GPIO generic keycode builder -------------------- */
 
 static int build_key(struct saa7134_dev *dev)
 {
@@ -413,13 +591,13 @@
 	saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
 
 	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
-        if (ir->polling) {
-                if (ir->last_gpio == gpio)
-                        return 0;
-                ir->last_gpio = gpio;
-        }
+	if (ir->polling) {
+		if (ir->last_gpio == gpio)
+			return 0;
+		ir->last_gpio = gpio;
+	}
 
- 	data = ir_extract_bits(gpio, ir->mask_keycode);
+	data = ir_extract_bits(gpio, ir->mask_keycode);
 	dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
 		gpio, ir->mask_keycode, data);
 
@@ -432,13 +610,87 @@
 	return 0;
 }
 
-/* ---------------------------------------------------------------------- */
+/* --------------------- Chip specific I2C key builders ----------------- */
+
+static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char b;
+
+	/* poll IR chip */
+	if (1 != i2c_master_recv(&ir->c,&b,1)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	/* no button press */
+	if (b==0)
+		return 0;
+
+	/* repeating */
+	if (b & 0x80)
+		return 1;
+
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char b[4];
+	unsigned int start = 0,parity = 0,code = 0;
+
+	/* poll IR chip */
+	if (4 != i2c_master_recv(&ir->c,b,4)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+
+	for (start = 0; start<4; start++) {
+		if (b[start] == 0x80) {
+			code=b[(start+3)%4];
+			parity=b[(start+2)%4];
+		}
+	}
+
+	/* Empty Request */
+	if (parity==0)
+		return 0;
+
+	/* Repeating... */
+	if (ir->old == parity)
+		return 0;
+
+
+	ir->old = parity;
+
+	/* Reduce code value to fit inside IR_KEYTAB_SIZE
+	 *
+	 * this is the only value that results in 42 unique
+	 * codes < 128
+	 */
+
+	code %= 0x88;
+
+	*ir_raw = code;
+	*ir_key = code;
+
+	i2cdprintk("Pinnacle PCTV key %02x\n", code);
+
+	return 1;
+}
+
 
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
-        struct saa7134_ir *ir = dev->remote;
+	struct saa7134_ir *ir = dev->remote;
 
-        if (!ir->polling)
+	if (!ir->polling)
 		build_key(dev);
 }
 
@@ -464,7 +716,7 @@
 	int polling      = 0;
 	int ir_type      = IR_TYPE_OTHER;
 
-	if (!dev->has_remote)
+	if (dev->has_remote != SAA7134_REMOTE_GPIO)
 		return -ENODEV;
 	if (disable_ir)
 		return -ENODEV;
@@ -473,7 +725,8 @@
 	switch (dev->board) {
 	case SAA7134_BOARD_FLYVIDEO2000:
 	case SAA7134_BOARD_FLYVIDEO3000:
-        case SAA7134_BOARD_FLYTVPLATINUM_FM:
+	case SAA7134_BOARD_FLYTVPLATINUM_FM:
+	case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
 		ir_codes     = flyvideo_codes;
 		mask_keycode = 0xEC00000;
 		mask_keydown = 0x0040000;
@@ -514,14 +767,33 @@
 		saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
 		saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
 		break;
+	case SAA7134_BOARD_KWORLD_TERMINATOR:
+		ir_codes     = avacssmart_codes;
+		mask_keycode = 0x00001f;
+		mask_keyup   = 0x000060;
+		polling      = 50; // ms
+		break;
 	case SAA7134_BOARD_MANLI_MTV001:
 	case SAA7134_BOARD_MANLI_MTV002:
+	case SAA7134_BOARD_BEHOLD_409FM:
 		ir_codes     = manli_codes;
 		mask_keycode = 0x001f00;
 		mask_keyup   = 0x004000;
-		mask_keydown = 0x002000;
 		polling      = 50; // ms
 		break;
+	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+		ir_codes     = pctv_sedna_codes;
+		mask_keycode = 0x001f00;
+		mask_keyup   = 0x004000;
+		polling      = 50; // ms
+		break;
+	case SAA7134_BOARD_GOTVIEW_7135:
+		ir_codes     = gotview7135_codes;
+		mask_keycode = 0x0003EC;
+		mask_keyup   = 0x008000;
+		mask_keydown = 0x000010;
+		polling	     = 50; // ms
+		break;
 	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
 	case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
 		ir_codes     = videomate_tv_pvr_codes;
@@ -529,6 +801,12 @@
 		mask_keyup   = 0x400000;
 		polling      = 50; // ms
 		break;
+	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+		ir_codes     = videomate_tv_pvr_codes;
+		mask_keycode = 0x003F00;
+		mask_keyup   = 0x040000;
+		break;
 	}
 	if (NULL == ir_codes) {
 		printk("%s: Oops: IR config error [card=%d]\n",
@@ -548,7 +826,7 @@
 	ir->mask_keycode = mask_keycode;
 	ir->mask_keydown = mask_keydown;
 	ir->mask_keyup   = mask_keyup;
-        ir->polling      = polling;
+	ir->polling      = polling;
 
 	/* init input device */
 	snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -596,6 +874,31 @@
 	dev->remote = NULL;
 }
 
+void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+{
+	if (disable_ir) {
+		dprintk("Found supported i2c remote, but IR has been disabled\n");
+		ir->get_key=NULL;
+		return;
+	}
+
+	switch (dev->board) {
+	case SAA7134_BOARD_PINNACLE_PCTV_110i:
+		snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
+		ir->get_key   = get_key_pinnacle;
+		ir->ir_codes  = ir_codes_pinnacle;
+		break;
+	case SAA7134_BOARD_UPMOST_PURPLE_TV:
+		snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
+		ir->get_key   = get_key_purpletv;
+		ir->ir_codes  = ir_codes_purpletv;
+		break;
+	default:
+		dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
+		break;
+	}
+
+}
 /* ----------------------------------------------------------------------
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index c20630c..fd53dfc 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -44,6 +44,7 @@
 #define dprintk(fmt, arg...)	if (oss_debug) \
 	printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
 
+
 /* ------------------------------------------------------------------ */
 
 static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
@@ -58,12 +59,12 @@
 	if ((blksize * blocks) > 1024*1024)
 		blocks = 1024*1024 / blksize;
 
-	dev->oss.blocks  = blocks;
-	dev->oss.blksize = blksize;
-	dev->oss.bufsize = blksize * blocks;
+	dev->dmasound.blocks  = blocks;
+	dev->dmasound.blksize = blksize;
+	dev->dmasound.bufsize = blksize * blocks;
 
 	dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
- 		blocks,blksize,blksize * blocks / 1024);
+		blocks,blksize,blksize * blocks / 1024);
 	return 0;
 }
 
@@ -71,11 +72,11 @@
 {
 	int err;
 
-	if (!dev->oss.bufsize)
+	if (!dev->dmasound.bufsize)
 		BUG();
-	videobuf_dma_init(&dev->oss.dma);
-	err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE,
-				       (dev->oss.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+	videobuf_dma_init(&dev->dmasound.dma);
+	err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+				       (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
 	if (0 != err)
 		return err;
 	return 0;
@@ -83,26 +84,26 @@
 
 static int dsp_buffer_free(struct saa7134_dev *dev)
 {
-	if (!dev->oss.blksize)
+	if (!dev->dmasound.blksize)
 		BUG();
-	videobuf_dma_free(&dev->oss.dma);
-	dev->oss.blocks  = 0;
-	dev->oss.blksize = 0;
-	dev->oss.bufsize = 0;
+	videobuf_dma_free(&dev->dmasound.dma);
+	dev->dmasound.blocks  = 0;
+	dev->dmasound.blksize = 0;
+	dev->dmasound.bufsize = 0;
 	return 0;
 }
 
 static void dsp_dma_start(struct saa7134_dev *dev)
 {
-	dev->oss.dma_blk     = 0;
-	dev->oss.dma_running = 1;
+	dev->dmasound.dma_blk     = 0;
+	dev->dmasound.dma_running = 1;
 	saa7134_set_dmabits(dev);
 }
 
 static void dsp_dma_stop(struct saa7134_dev *dev)
 {
-	dev->oss.dma_blk     = -1;
-	dev->oss.dma_running = 0;
+	dev->dmasound.dma_blk     = -1;
+	dev->dmasound.dma_running = 0;
 	saa7134_set_dmabits(dev);
 }
 
@@ -113,18 +114,18 @@
 	unsigned long flags;
 
 	/* prepare buffer */
-	if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma)))
+	if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma)))
 		return err;
-	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->oss.pt)))
+	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
 		goto fail1;
-	if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt,
-					      dev->oss.dma.sglist,
-					      dev->oss.dma.sglen,
+	if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+					      dev->dmasound.dma.sglist,
+					      dev->dmasound.dma.sglen,
 					      0)))
 		goto fail2;
 
 	/* sample format */
-	switch (dev->oss.afmt) {
+	switch (dev->dmasound.afmt) {
 	case AFMT_U8:
 	case AFMT_S8:     fmt = 0x00;  break;
 	case AFMT_U16_LE:
@@ -136,14 +137,14 @@
 		goto fail2;
 	}
 
-	switch (dev->oss.afmt) {
+	switch (dev->dmasound.afmt) {
 	case AFMT_S8:
 	case AFMT_S16_LE:
 	case AFMT_S16_BE: sign = 1; break;
 	default:          sign = 0; break;
 	}
 
-	switch (dev->oss.afmt) {
+	switch (dev->dmasound.afmt) {
 	case AFMT_U16_BE:
 	case AFMT_S16_BE: bswap = 1; break;
 	default:          bswap = 0; break;
@@ -151,58 +152,58 @@
 
 	switch (dev->pci->device) {
 	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-		if (1 == dev->oss.channels)
+		if (1 == dev->dmasound.channels)
 			fmt |= (1 << 3);
-		if (2 == dev->oss.channels)
+		if (2 == dev->dmasound.channels)
 			fmt |= (3 << 3);
 		if (sign)
 			fmt |= 0x04;
-		fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
+		fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80;
 
-		saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->oss.blksize - 1) & 0x0000ff));
-		saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->oss.blksize - 1) & 0x00ff00) >>  8);
-		saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->oss.blksize - 1) & 0xff0000) >> 16);
+		saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+		saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >>  8);
+		saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
 		saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
 
 		break;
 	case PCI_DEVICE_ID_PHILIPS_SAA7133:
 	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		if (1 == dev->oss.channels)
+		if (1 == dev->dmasound.channels)
 			fmt |= (1 << 4);
-		if (2 == dev->oss.channels)
+		if (2 == dev->dmasound.channels)
 			fmt |= (2 << 4);
 		if (!sign)
 			fmt |= 0x04;
-		saa_writel(0x588 >> 2, dev->oss.blksize -4);
-		saa_writel(0x58c >> 2, 0x543210 | (fmt << 24));
+		saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4);
+		saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
 		break;
 	}
 	dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
-		dev->oss.afmt, dev->oss.channels, fmt,
+		dev->dmasound.afmt, dev->dmasound.channels, fmt,
 		bswap ? 'b' : '-');
 
 	/* dma: setup channel 6 (= AUDIO) */
 	control = SAA7134_RS_CONTROL_BURST_16 |
 		SAA7134_RS_CONTROL_ME |
-		(dev->oss.pt.dma >> 12);
+		(dev->dmasound.pt.dma >> 12);
 	if (bswap)
 		control |= SAA7134_RS_CONTROL_BSWAP;
 	saa_writel(SAA7134_RS_BA1(6),0);
-	saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize);
+	saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
 	saa_writel(SAA7134_RS_PITCH(6),0);
 	saa_writel(SAA7134_RS_CONTROL(6),control);
 
 	/* start dma */
-	dev->oss.recording_on = 1;
+	dev->dmasound.recording_on = 1;
 	spin_lock_irqsave(&dev->slock,flags);
 	dsp_dma_start(dev);
 	spin_unlock_irqrestore(&dev->slock,flags);
 	return 0;
 
  fail2:
-	saa7134_pgtable_free(dev->pci,&dev->oss.pt);
+	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
  fail1:
-	videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+	videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
 	return err;
 }
 
@@ -210,17 +211,17 @@
 {
 	unsigned long flags;
 
-	dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk);
+	dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk);
 
 	/* stop dma */
-	dev->oss.recording_on = 0;
+	dev->dmasound.recording_on = 0;
 	spin_lock_irqsave(&dev->slock,flags);
 	dsp_dma_stop(dev);
 	spin_unlock_irqrestore(&dev->slock,flags);
 
 	/* unlock buffer */
-	saa7134_pgtable_free(dev->pci,&dev->oss.pt);
-	videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+	videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
 	return 0;
 }
 
@@ -235,35 +236,35 @@
 
 	list_for_each(list,&saa7134_devlist) {
 		h = list_entry(list, struct saa7134_dev, devlist);
-		if (h->oss.minor_dsp == minor)
+		if (h->dmasound.minor_dsp == minor)
 			dev = h;
 	}
 	if (NULL == dev)
 		return -ENODEV;
 
-	down(&dev->oss.lock);
+	down(&dev->dmasound.lock);
 	err = -EBUSY;
-	if (dev->oss.users_dsp)
+	if (dev->dmasound.users_dsp)
 		goto fail1;
-	dev->oss.users_dsp++;
+	dev->dmasound.users_dsp++;
 	file->private_data = dev;
 
-	dev->oss.afmt        = AFMT_U8;
-	dev->oss.channels    = 1;
-	dev->oss.read_count  = 0;
-	dev->oss.read_offset = 0;
+	dev->dmasound.afmt        = AFMT_U8;
+	dev->dmasound.channels    = 1;
+	dev->dmasound.read_count  = 0;
+	dev->dmasound.read_offset = 0;
 	dsp_buffer_conf(dev,PAGE_SIZE,64);
 	err = dsp_buffer_init(dev);
 	if (0 != err)
 		goto fail2;
 
-	up(&dev->oss.lock);
+	up(&dev->dmasound.lock);
 	return 0;
 
  fail2:
-	dev->oss.users_dsp--;
+	dev->dmasound.users_dsp--;
  fail1:
-	up(&dev->oss.lock);
+	up(&dev->dmasound.lock);
 	return err;
 }
 
@@ -271,13 +272,13 @@
 {
 	struct saa7134_dev *dev = file->private_data;
 
-	down(&dev->oss.lock);
-	if (dev->oss.recording_on)
+	down(&dev->dmasound.lock);
+	if (dev->dmasound.recording_on)
 		dsp_rec_stop(dev);
 	dsp_buffer_free(dev);
-	dev->oss.users_dsp--;
+	dev->dmasound.users_dsp--;
 	file->private_data = NULL;
-	up(&dev->oss.lock);
+	up(&dev->dmasound.lock);
 	return 0;
 }
 
@@ -290,12 +291,12 @@
 	unsigned long flags;
 	int err,ret = 0;
 
-	add_wait_queue(&dev->oss.wq, &wait);
-	down(&dev->oss.lock);
+	add_wait_queue(&dev->dmasound.wq, &wait);
+	down(&dev->dmasound.lock);
 	while (count > 0) {
 		/* wait for data if needed */
-		if (0 == dev->oss.read_count) {
-			if (!dev->oss.recording_on) {
+		if (0 == dev->dmasound.read_count) {
+			if (!dev->dmasound.recording_on) {
 				err = dsp_rec_start(dev);
 				if (err < 0) {
 					if (0 == ret)
@@ -303,8 +304,8 @@
 					break;
 				}
 			}
-			if (dev->oss.recording_on &&
-			    !dev->oss.dma_running) {
+			if (dev->dmasound.recording_on &&
+			    !dev->dmasound.dma_running) {
 				/* recover from overruns */
 				spin_lock_irqsave(&dev->slock,flags);
 				dsp_dma_start(dev);
@@ -315,12 +316,12 @@
 					ret = -EAGAIN;
 				break;
 			}
-			up(&dev->oss.lock);
+			up(&dev->dmasound.lock);
 			set_current_state(TASK_INTERRUPTIBLE);
-			if (0 == dev->oss.read_count)
+			if (0 == dev->dmasound.read_count)
 				schedule();
 			set_current_state(TASK_RUNNING);
-			down(&dev->oss.lock);
+			down(&dev->dmasound.lock);
 			if (signal_pending(current)) {
 				if (0 == ret)
 					ret = -EINTR;
@@ -330,12 +331,12 @@
 
 		/* copy data to userspace */
 		bytes = count;
-		if (bytes > dev->oss.read_count)
-			bytes = dev->oss.read_count;
-		if (bytes > dev->oss.bufsize - dev->oss.read_offset)
-			bytes = dev->oss.bufsize - dev->oss.read_offset;
+		if (bytes > dev->dmasound.read_count)
+			bytes = dev->dmasound.read_count;
+		if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset)
+			bytes = dev->dmasound.bufsize - dev->dmasound.read_offset;
 		if (copy_to_user(buffer + ret,
-				 dev->oss.dma.vmalloc + dev->oss.read_offset,
+				 dev->dmasound.dma.vmalloc + dev->dmasound.read_offset,
 				 bytes)) {
 			if (0 == ret)
 				ret = -EFAULT;
@@ -344,13 +345,13 @@
 
 		ret   += bytes;
 		count -= bytes;
-		dev->oss.read_count  -= bytes;
-		dev->oss.read_offset += bytes;
-		if (dev->oss.read_offset == dev->oss.bufsize)
-			dev->oss.read_offset = 0;
+		dev->dmasound.read_count  -= bytes;
+		dev->dmasound.read_offset += bytes;
+		if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+			dev->dmasound.read_offset = 0;
 	}
-	up(&dev->oss.lock);
-	remove_wait_queue(&dev->oss.wq, &wait);
+	up(&dev->dmasound.lock);
+	remove_wait_queue(&dev->dmasound.wq, &wait);
 	return ret;
 }
 
@@ -370,53 +371,53 @@
 
 	if (oss_debug > 1)
 		saa7134_print_ioctl(dev->name,cmd);
-        switch (cmd) {
-        case OSS_GETVERSION:
-                return put_user(SOUND_VERSION, p);
-        case SNDCTL_DSP_GETCAPS:
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, p);
+	case SNDCTL_DSP_GETCAPS:
 		return 0;
 
-        case SNDCTL_DSP_SPEED:
+	case SNDCTL_DSP_SPEED:
 		if (get_user(val, p))
 			return -EFAULT;
 		/* fall through */
-        case SOUND_PCM_READ_RATE:
-		return put_user(dev->oss.rate, p);
+	case SOUND_PCM_READ_RATE:
+		return put_user(dev->dmasound.rate, p);
 
-        case SNDCTL_DSP_STEREO:
+	case SNDCTL_DSP_STEREO:
 		if (get_user(val, p))
 			return -EFAULT;
-		down(&dev->oss.lock);
-		dev->oss.channels = val ? 2 : 1;
-		if (dev->oss.recording_on) {
+		down(&dev->dmasound.lock);
+		dev->dmasound.channels = val ? 2 : 1;
+		if (dev->dmasound.recording_on) {
 			dsp_rec_stop(dev);
 			dsp_rec_start(dev);
 		}
-		up(&dev->oss.lock);
-		return put_user(dev->oss.channels-1, p);
+		up(&dev->dmasound.lock);
+		return put_user(dev->dmasound.channels-1, p);
 
-        case SNDCTL_DSP_CHANNELS:
+	case SNDCTL_DSP_CHANNELS:
 		if (get_user(val, p))
 			return -EFAULT;
 		if (val != 1 && val != 2)
 			return -EINVAL;
-		down(&dev->oss.lock);
-		dev->oss.channels = val;
-		if (dev->oss.recording_on) {
+		down(&dev->dmasound.lock);
+		dev->dmasound.channels = val;
+		if (dev->dmasound.recording_on) {
 			dsp_rec_stop(dev);
 			dsp_rec_start(dev);
 		}
-		up(&dev->oss.lock);
+		up(&dev->dmasound.lock);
 		/* fall through */
-        case SOUND_PCM_READ_CHANNELS:
-		return put_user(dev->oss.channels, p);
+	case SOUND_PCM_READ_CHANNELS:
+		return put_user(dev->dmasound.channels, p);
 
-        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
 		return put_user(AFMT_U8     | AFMT_S8     |
 				AFMT_U16_LE | AFMT_U16_BE |
 				AFMT_S16_LE | AFMT_S16_BE, p);
 
-        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
+	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
 		if (get_user(val, p))
 			return -EFAULT;
 		switch (val) {
@@ -429,20 +430,20 @@
 		case AFMT_U16_BE:
 		case AFMT_S16_LE:
 		case AFMT_S16_BE:
-			down(&dev->oss.lock);
-			dev->oss.afmt = val;
-			if (dev->oss.recording_on) {
+			down(&dev->dmasound.lock);
+			dev->dmasound.afmt = val;
+			if (dev->dmasound.recording_on) {
 				dsp_rec_stop(dev);
 				dsp_rec_start(dev);
 			}
-			up(&dev->oss.lock);
-			return put_user(dev->oss.afmt, p);
+			up(&dev->dmasound.lock);
+			return put_user(dev->dmasound.afmt, p);
 		default:
 			return -EINVAL;
 		}
 
-        case SOUND_PCM_READ_BITS:
-		switch (dev->oss.afmt) {
+	case SOUND_PCM_READ_BITS:
+		switch (dev->dmasound.afmt) {
 		case AFMT_U8:
 		case AFMT_S8:
 			return put_user(8, p);
@@ -455,23 +456,23 @@
 			return -EINVAL;
 		}
 
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_RESET:
-		down(&dev->oss.lock);
-		if (dev->oss.recording_on)
-			dsp_rec_stop(dev);
-		up(&dev->oss.lock);
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
 		return 0;
-        case SNDCTL_DSP_GETBLKSIZE:
-		return put_user(dev->oss.blksize, p);
 
-        case SNDCTL_DSP_SETFRAGMENT:
+	case SNDCTL_DSP_RESET:
+		down(&dev->dmasound.lock);
+		if (dev->dmasound.recording_on)
+			dsp_rec_stop(dev);
+		up(&dev->dmasound.lock);
+		return 0;
+	case SNDCTL_DSP_GETBLKSIZE:
+		return put_user(dev->dmasound.blksize, p);
+
+	case SNDCTL_DSP_SETFRAGMENT:
 		if (get_user(val, p))
 			return -EFAULT;
-		if (dev->oss.recording_on)
+		if (dev->dmasound.recording_on)
 			return -EBUSY;
 		dsp_buffer_free(dev);
 		/* used to be arg >> 16 instead of val >> 16; fixed */
@@ -479,16 +480,16 @@
 		dsp_buffer_init(dev);
 		return 0;
 
-        case SNDCTL_DSP_SYNC:
+	case SNDCTL_DSP_SYNC:
 		/* NOP */
 		return 0;
 
 	case SNDCTL_DSP_GETISPACE:
 	{
 		audio_buf_info info;
-		info.fragsize   = dev->oss.blksize;
-		info.fragstotal = dev->oss.blocks;
-		info.bytes      = dev->oss.read_count;
+		info.fragsize   = dev->dmasound.blksize;
+		info.fragstotal = dev->dmasound.blocks;
+		info.bytes      = dev->dmasound.read_count;
 		info.fragments  = info.bytes / info.fragsize;
 		if (copy_to_user(argp, &info, sizeof(info)))
 			return -EFAULT;
@@ -504,13 +505,13 @@
 	struct saa7134_dev *dev = file->private_data;
 	unsigned int mask = 0;
 
-	poll_wait(file, &dev->oss.wq, wait);
+	poll_wait(file, &dev->dmasound.wq, wait);
 
-	if (0 == dev->oss.read_count) {
-		down(&dev->oss.lock);
-		if (!dev->oss.recording_on)
+	if (0 == dev->dmasound.read_count) {
+		down(&dev->dmasound.lock);
+		if (!dev->dmasound.recording_on)
 			dsp_rec_start(dev);
-		up(&dev->oss.lock);
+		up(&dev->dmasound.lock);
 	} else
 		mask |= (POLLIN | POLLRDNORM);
 	return mask;
@@ -534,7 +535,7 @@
 {
 	int analog_io,rate;
 
-	switch (dev->oss.input) {
+	switch (dev->dmasound.input) {
 	case TV:
 		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
 		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
@@ -542,8 +543,8 @@
 	case LINE1:
 	case LINE2:
 	case LINE2_LEFT:
-		analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08;
-		rate = (32000 == dev->oss.rate) ? 0x01 : 0x03;
+		analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08;
+		rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
 		saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
 		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
 		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
@@ -559,10 +560,10 @@
 
 	xbarin = 0x03; // adc
     anabar = 0;
-	switch (dev->oss.input) {
+	switch (dev->dmasound.input) {
 	case TV:
 		xbarin = 0; // Demodulator
-        anabar = 2; // DACs
+	anabar = 2; // DACs
 		break;
 	case LINE1:
 		anabar = 0;  // aux1, aux1
@@ -585,9 +586,9 @@
 {
 	static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
 
-	dev->oss.count++;
-	dev->oss.input = src;
-	dprintk("mixer input = %s\n",iname[dev->oss.input]);
+	dev->dmasound.count++;
+	dev->dmasound.input = src;
+	dprintk("mixer input = %s\n",iname[dev->dmasound.input]);
 
 	switch (dev->pci->device) {
 	case PCI_DEVICE_ID_PHILIPS_SAA7134:
@@ -639,7 +640,7 @@
 
 	list_for_each(list,&saa7134_devlist) {
 		h = list_entry(list, struct saa7134_dev, devlist);
-		if (h->oss.minor_mixer == minor)
+		if (h->dmasound.minor_mixer == minor)
 			dev = h;
 	}
 	if (NULL == dev)
@@ -666,28 +667,28 @@
 
 	if (oss_debug > 1)
 		saa7134_print_ioctl(dev->name,cmd);
-        switch (cmd) {
-        case OSS_GETVERSION:
-                return put_user(SOUND_VERSION, p);
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, p);
 	case SOUND_MIXER_INFO:
 	{
 		mixer_info info;
 		memset(&info,0,sizeof(info));
-                strlcpy(info.id,   "TV audio", sizeof(info.id));
-                strlcpy(info.name, dev->name,  sizeof(info.name));
-                info.modify_counter = dev->oss.count;
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
+		strlcpy(info.id,   "TV audio", sizeof(info.id));
+		strlcpy(info.name, dev->name,  sizeof(info.name));
+		info.modify_counter = dev->dmasound.count;
+		if (copy_to_user(argp, &info, sizeof(info)))
+			return -EFAULT;
 		return 0;
 	}
 	case SOUND_OLD_MIXER_INFO:
 	{
 		_old_mixer_info info;
 		memset(&info,0,sizeof(info));
-                strlcpy(info.id,   "TV audio", sizeof(info.id));
-                strlcpy(info.name, dev->name,  sizeof(info.name));
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
+		strlcpy(info.id,   "TV audio", sizeof(info.id));
+		strlcpy(info.name, dev->name,  sizeof(info.name));
+		if (copy_to_user(argp, &info, sizeof(info)))
+			return -EFAULT;
 		return 0;
 	}
 	case MIXER_READ(SOUND_MIXER_CAPS):
@@ -697,26 +698,26 @@
 	case MIXER_READ(SOUND_MIXER_RECMASK):
 	case MIXER_READ(SOUND_MIXER_DEVMASK):
 		val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
-		if (32000 == dev->oss.rate)
+		if (32000 == dev->dmasound.rate)
 			val |= SOUND_MASK_VIDEO;
 		return put_user(val, p);
 
 	case MIXER_WRITE(SOUND_MIXER_RECSRC):
 		if (get_user(val, p))
 			return -EFAULT;
-		input = dev->oss.input;
-		if (32000 == dev->oss.rate  &&
-		    val & SOUND_MASK_VIDEO  &&  dev->oss.input != TV)
+		input = dev->dmasound.input;
+		if (32000 == dev->dmasound.rate  &&
+		    val & SOUND_MASK_VIDEO  &&  dev->dmasound.input != TV)
 			input = TV;
-		if (val & SOUND_MASK_LINE1  &&  dev->oss.input != LINE1)
+		if (val & SOUND_MASK_LINE1  &&  dev->dmasound.input != LINE1)
 			input = LINE1;
-		if (val & SOUND_MASK_LINE2  &&  dev->oss.input != LINE2)
+		if (val & SOUND_MASK_LINE2  &&  dev->dmasound.input != LINE2)
 			input = LINE2;
-		if (input != dev->oss.input)
+		if (input != dev->dmasound.input)
 			mixer_recsrc(dev,input);
 		/* fall throuth */
 	case MIXER_READ(SOUND_MIXER_RECSRC):
-		switch (dev->oss.input) {
+		switch (dev->dmasound.input) {
 		case TV:    ret = SOUND_MASK_VIDEO; break;
 		case LINE1: ret = SOUND_MASK_LINE1; break;
 		case LINE2: ret = SOUND_MASK_LINE2; break;
@@ -726,7 +727,7 @@
 
 	case MIXER_WRITE(SOUND_MIXER_VIDEO):
 	case MIXER_READ(SOUND_MIXER_VIDEO):
-		if (32000 != dev->oss.rate)
+		if (32000 != dev->dmasound.rate)
 			return -EINVAL;
 		return put_user(100 | 100 << 8, p);
 
@@ -735,22 +736,22 @@
 			return -EFAULT;
 		val &= 0xff;
 		val = (val <= 50) ? 50 : 100;
-		dev->oss.line1 = val;
-		mixer_level(dev,LINE1,dev->oss.line1);
+		dev->dmasound.line1 = val;
+		mixer_level(dev,LINE1,dev->dmasound.line1);
 		/* fall throuth */
 	case MIXER_READ(SOUND_MIXER_LINE1):
-		return put_user(dev->oss.line1 | dev->oss.line1 << 8, p);
+		return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p);
 
 	case MIXER_WRITE(SOUND_MIXER_LINE2):
 		if (get_user(val, p))
 			return -EFAULT;
 		val &= 0xff;
 		val = (val <= 50) ? 50 : 100;
-		dev->oss.line2 = val;
-		mixer_level(dev,LINE2,dev->oss.line2);
+		dev->dmasound.line2 = val;
+		mixer_level(dev,LINE2,dev->dmasound.line2);
 		/* fall throuth */
 	case MIXER_READ(SOUND_MIXER_LINE2):
-		return put_user(dev->oss.line2 | dev->oss.line2 << 8, p);
+		return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p);
 
 	default:
 		return -EINVAL;
@@ -770,8 +771,8 @@
 int saa7134_oss_init1(struct saa7134_dev *dev)
 {
 	/* general */
-        init_MUTEX(&dev->oss.lock);
-	init_waitqueue_head(&dev->oss.wq);
+	init_MUTEX(&dev->dmasound.lock);
+	init_waitqueue_head(&dev->dmasound.wq);
 
 	switch (dev->pci->device) {
 	case PCI_DEVICE_ID_PHILIPS_SAA7133:
@@ -783,17 +784,17 @@
 	}
 
 	/* dsp */
-	dev->oss.rate = 32000;
+	dev->dmasound.rate = 32000;
 	if (oss_rate)
-		dev->oss.rate = oss_rate;
-	dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000;
+		dev->dmasound.rate = oss_rate;
+	dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
 
 	/* mixer */
-	dev->oss.line1 = 50;
-	dev->oss.line2 = 50;
-	mixer_level(dev,LINE1,dev->oss.line1);
-	mixer_level(dev,LINE2,dev->oss.line2);
-	mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2);
+	dev->dmasound.line1 = 50;
+	dev->dmasound.line2 = 50;
+	mixer_level(dev,LINE1,dev->dmasound.line1);
+	mixer_level(dev,LINE2,dev->dmasound.line2);
+	mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2);
 
 	return 0;
 }
@@ -809,7 +810,7 @@
 	int next_blk, reg = 0;
 
 	spin_lock(&dev->slock);
-	if (UNSET == dev->oss.dma_blk) {
+	if (UNSET == dev->dmasound.dma_blk) {
 		dprintk("irq: recording stopped\n");
 		goto done;
 	}
@@ -817,11 +818,11 @@
 		dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
 	if (0 == (status & 0x10000000)) {
 		/* odd */
-		if (0 == (dev->oss.dma_blk & 0x01))
+		if (0 == (dev->dmasound.dma_blk & 0x01))
 			reg = SAA7134_RS_BA1(6);
 	} else {
 		/* even */
-		if (1 == (dev->oss.dma_blk & 0x01))
+		if (1 == (dev->dmasound.dma_blk & 0x01))
 			reg = SAA7134_RS_BA2(6);
 	}
 	if (0 == reg) {
@@ -829,25 +830,25 @@
 			(status & 0x10000000) ? "even" : "odd");
 		goto done;
 	}
-	if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) {
-		dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count,
-			dev->oss.bufsize);
+	if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+		dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count,
+			dev->dmasound.bufsize);
 		dsp_dma_stop(dev);
 		goto done;
 	}
 
 	/* next block addr */
-	next_blk = (dev->oss.dma_blk + 2) % dev->oss.blocks;
-	saa_writel(reg,next_blk * dev->oss.blksize);
+	next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+	saa_writel(reg,next_blk * dev->dmasound.blksize);
 	if (oss_debug > 2)
 		dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
 			(status & 0x10000000) ? "even" : "odd ", next_blk,
-			next_blk * dev->oss.blksize);
+			next_blk * dev->dmasound.blksize);
 
 	/* update status & wake waiting readers */
-	dev->oss.dma_blk = (dev->oss.dma_blk + 1) % dev->oss.blocks;
-	dev->oss.read_count += dev->oss.blksize;
-	wake_up(&dev->oss.wq);
+	dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+	dev->dmasound.read_count += dev->dmasound.blksize;
+	wake_up(&dev->dmasound.wq);
 
  done:
 	spin_unlock(&dev->slock);
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
index ae0c7a1..ac6431b 100644
--- a/drivers/media/video/saa7134/saa7134-reg.h
+++ b/drivers/media/video/saa7134/saa7134-reg.h
@@ -27,7 +27,7 @@
 
 /* DMA channels, n = 0 ... 6 */
 #define SAA7134_RS_BA1(n)			((0x200 >> 2) + 4*n)
-#define SAA7134_RS_BA2(n)	       		((0x204 >> 2) + 4*n)
+#define SAA7134_RS_BA2(n)			((0x204 >> 2) + 4*n)
 #define SAA7134_RS_PITCH(n)			((0x208 >> 2) + 4*n)
 #define SAA7134_RS_CONTROL(n)			((0x20c >> 2) + 4*n)
 #define   SAA7134_RS_CONTROL_WSWAP		(0x01 << 25)
@@ -43,16 +43,24 @@
 #define SAA7134_FIFO_SIZE                       (0x2a0 >> 2)
 #define SAA7134_THRESHOULD                      (0x2a4 >> 2)
 
+#define SAA7133_NUM_SAMPLES			(0x588 >> 2)
+#define SAA7133_AUDIO_CHANNEL			(0x58c >> 2)
+#define SAA7133_AUDIO_FORMAT			(0x58f >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL1		(0x46c >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL2		(0x470 >> 2)
+#define SAA7133_DIGITAL_INPUT_XBAR1		(0x464 >> 2)
+#define SAA7133_ANALOG_IO_SELECT                (0x594 >> 2)
+
 /* main control */
 #define SAA7134_MAIN_CTRL                       (0x2a8 >> 2)
-#define   SAA7134_MAIN_CTRL_VPLLE	       	(1 << 15)
-#define   SAA7134_MAIN_CTRL_APLLE	       	(1 << 14)
-#define   SAA7134_MAIN_CTRL_EXOSC	       	(1 << 13)
-#define   SAA7134_MAIN_CTRL_EVFE1	       	(1 << 12)
-#define   SAA7134_MAIN_CTRL_EVFE2	       	(1 << 11)
-#define   SAA7134_MAIN_CTRL_ESFE	       	(1 << 10)
-#define   SAA7134_MAIN_CTRL_EBADC	       	(1 << 9)
-#define   SAA7134_MAIN_CTRL_EBDAC	       	(1 << 8)
+#define   SAA7134_MAIN_CTRL_VPLLE		(1 << 15)
+#define   SAA7134_MAIN_CTRL_APLLE		(1 << 14)
+#define   SAA7134_MAIN_CTRL_EXOSC		(1 << 13)
+#define   SAA7134_MAIN_CTRL_EVFE1		(1 << 12)
+#define   SAA7134_MAIN_CTRL_EVFE2		(1 << 11)
+#define   SAA7134_MAIN_CTRL_ESFE		(1 << 10)
+#define   SAA7134_MAIN_CTRL_EBADC		(1 << 9)
+#define   SAA7134_MAIN_CTRL_EBDAC		(1 << 8)
 #define   SAA7134_MAIN_CTRL_TE6			(1 << 6)
 #define   SAA7134_MAIN_CTRL_TE5			(1 << 5)
 #define   SAA7134_MAIN_CTRL_TE4			(1 << 4)
@@ -348,6 +356,7 @@
 
 /* test modes */
 #define SAA7134_SPECIAL_MODE                    0x1d0
+#define SAA7134_PRODUCTION_TEST_MODE            0x1d1
 
 /* audio -- saa7133 + saa7135 only */
 #define SAA7135_DSP_RWSTATE                     0x580
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 4638856..470903e 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -46,17 +46,11 @@
 			   struct saa7134_buf *buf,
 			   struct saa7134_buf *next)
 {
-	u32 control;
 
 	dprintk("buffer_activate [%p]",buf);
 	buf->vb.state = STATE_ACTIVE;
 	buf->top_seen = 0;
 
-        /* dma: setup channel 5 (= TS) */
-        control = SAA7134_RS_CONTROL_BURST_16 |
-                SAA7134_RS_CONTROL_ME |
-                (buf->pt->dma >> 12);
-
 	if (NULL == next)
 		next = buf;
 	if (V4L2_FIELD_TOP == buf->vb.field) {
@@ -68,8 +62,6 @@
 		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
 		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
 	}
-	saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
-	saa_writel(SAA7134_RS_CONTROL(5),control);
 
 	/* start DMA */
 	saa7134_set_dmabits(dev);
@@ -84,6 +76,7 @@
 	struct saa7134_dev *dev = q->priv_data;
 	struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
 	unsigned int lines, llength, size;
+	u32 control;
 	int err;
 
 	dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
@@ -115,6 +108,18 @@
 		if (err)
 			goto oops;
 	}
+
+	/* dma: setup channel 5 (= TS) */
+	control = SAA7134_RS_CONTROL_BURST_16 |
+		  SAA7134_RS_CONTROL_ME |
+		  (buf->pt->dma >> 12);
+
+	saa_writeb(SAA7134_TS_DMA0, ((lines-1)&0xff));
+	saa_writeb(SAA7134_TS_DMA1, (((lines-1)>>8)&0xff));
+	saa_writeb(SAA7134_TS_DMA2, ((((lines-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
+	saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
+	saa_writel(SAA7134_RS_CONTROL(5),control);
+
 	buf->vb.state = STATE_PREPARED;
 	buf->activate = buffer_activate;
 	buf->vb.field = field;
@@ -164,11 +169,11 @@
 /* ----------------------------------------------------------- */
 /* exported stuff                                              */
 
-static unsigned int tsbufs = 4;
+static unsigned int tsbufs = 8;
 module_param(tsbufs, int, 0444);
 MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32");
 
-static unsigned int ts_nr_packets = 30;
+static unsigned int ts_nr_packets = 64;
 module_param(ts_nr_packets, int, 0444);
 MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
 
@@ -220,10 +225,10 @@
 	if (dev->ts_q.curr) {
 		field = dev->ts_q.curr->vb.field;
 		if (field == V4L2_FIELD_TOP) {
-			if ((status & 0x100000) != 0x100000)
+			if ((status & 0x100000) != 0x000000)
 				goto done;
 		} else {
-			if ((status & 0x100000) != 0x000000)
+			if ((status & 0x100000) != 0x100000)
 				goto done;
 		}
 		saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 61a2d6b..9326842 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -207,6 +207,10 @@
 	saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary));
 }
 
+#define SAA7134_MUTE_MASK 0xbb
+#define SAA7134_MUTE_ANALOG 0x04
+#define SAA7134_MUTE_I2S 0x40
+
 static void mute_input_7134(struct saa7134_dev *dev)
 {
 	unsigned int mute;
@@ -241,7 +245,11 @@
 
 	if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device)
 		/* 7134 mute */
-		saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xbf : 0xbb);
+		saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ?
+						    SAA7134_MUTE_MASK |
+						    SAA7134_MUTE_ANALOG |
+						    SAA7134_MUTE_I2S :
+						    SAA7134_MUTE_MASK);
 
 	/* switch internal audio mux */
 	switch (in->amux) {
@@ -753,17 +761,17 @@
 
 
 	/* switch gpio-connected external audio mux */
-        if (0 != card(dev).gpiomask) {
-        	mask = card(dev).gpiomask;
+	if (0 != card(dev).gpiomask) {
+		mask = card(dev).gpiomask;
 
 		if (card(dev).mute.name && dev->ctl_mute)
 			in = &card(dev).mute;
 		else
 			in = dev->input;
 
-        	saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
-        	saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
-        	saa7134_track_gpio(dev,in->name);
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+		saa7134_track_gpio(dev,in->name);
 	}
 
 	return 0;
@@ -1016,9 +1024,12 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(saa_dsp_writel);
+
 /* ----------------------------------------------------------- */
 /*
  * Local variables:
  * c-basic-offset: 8
  * End:
  */
+
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 35e5e85..45c852d 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -30,6 +30,9 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+
 /* ------------------------------------------------------------------ */
 
 static unsigned int video_debug   = 0;
@@ -48,6 +51,43 @@
 	printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
 
 /* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x191            */
+
+/* Bit 0: VIP code T bit polarity */
+
+#define VP_T_CODE_P_NON_INVERTED	0x00
+#define VP_T_CODE_P_INVERTED		0x01
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x195            */
+
+/* Bit 2: Video output clock delay control */
+
+#define VP_CLK_CTRL2_NOT_DELAYED	0x00
+#define VP_CLK_CTRL2_DELAYED		0x04
+
+/* Bit 1: Video output clock invert control */
+
+#define VP_CLK_CTRL1_NON_INVERTED	0x00
+#define VP_CLK_CTRL1_INVERTED		0x02
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x196            */
+
+/* Bits 2 to 0: VSYNC pin video vertical sync type */
+
+#define VP_VS_TYPE_MASK			0x07
+
+#define VP_VS_TYPE_OFF			0x00
+#define VP_VS_TYPE_V123			0x01
+#define VP_VS_TYPE_V_ITU		0x02
+#define VP_VS_TYPE_VGATE_L		0x03
+#define VP_VS_TYPE_RESERVED1		0x04
+#define VP_VS_TYPE_RESERVED2		0x05
+#define VP_VS_TYPE_F_ITU		0x06
+#define VP_VS_TYPE_SC_FID		0x07
+
+/* ------------------------------------------------------------------ */
 /* data structs for video                                             */
 
 static int video_out[][9] = {
@@ -273,12 +313,12 @@
 
 		.h_start       = 0,
 		.h_stop        = 719,
-  		.video_v_start = 23,
-  		.video_v_stop  = 262,
-  		.vbi_v_start_0 = 10,
-  		.vbi_v_stop_0  = 21,
-  		.vbi_v_start_1 = 273,
-  		.src_timing    = 7,
+		.video_v_start = 23,
+		.video_v_stop  = 262,
+		.vbi_v_start_0 = 10,
+		.vbi_v_stop_0  = 21,
+		.vbi_v_start_1 = 273,
+		.src_timing    = 7,
 
 		.sync_control  = 0x18,
 		.luma_control  = 0x40,
@@ -622,7 +662,7 @@
 		prescale = 1;
 	xscale = 1024 * dev->crop_current.width / prescale / width;
 	yscale = 512 * div * dev->crop_current.height / height;
-       	dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
+	dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
 	set_h_prescale(dev,task,prescale);
 	saa_writeb(SAA7134_H_SCALE_INC1(task),      xscale &  0xff);
 	saa_writeb(SAA7134_H_SCALE_INC2(task),      xscale >> 8);
@@ -752,20 +792,20 @@
 	maxh  = dev->crop_current.height;
 
 	if (V4L2_FIELD_ANY == field) {
-                field = (win->w.height > maxh/2)
-                        ? V4L2_FIELD_INTERLACED
-                        : V4L2_FIELD_TOP;
-        }
-        switch (field) {
-        case V4L2_FIELD_TOP:
-        case V4L2_FIELD_BOTTOM:
-                maxh = maxh / 2;
-                break;
-        case V4L2_FIELD_INTERLACED:
-                break;
-        default:
-                return -EINVAL;
-        }
+		field = (win->w.height > maxh/2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_TOP;
+	}
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	win->field = field;
 	if (win->w.width > maxw)
@@ -1306,13 +1346,13 @@
 			if (res_locked(fh->dev,RESOURCE_VIDEO)) {
 				up(&fh->cap.lock);
 				return POLLERR;
-                        }
-                        if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
-                                up(&fh->cap.lock);
-                                return POLLERR;
-                        }
-                        fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
-                        fh->cap.read_off = 0;
+			}
+			if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
+				up(&fh->cap.lock);
+				return POLLERR;
+			}
+			fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+			fh->cap.read_off = 0;
 		}
 		up(&fh->cap.lock);
 		buf = fh->cap.read_buf;
@@ -1666,9 +1706,10 @@
 	case VIDIOC_QUERYCAP:
 	{
 		struct v4l2_capability *cap = arg;
+		unsigned int tuner_type = dev->tuner_type;
 
 		memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
+		strcpy(cap->driver, "saa7134");
 		strlcpy(cap->card, saa7134_boards[dev->board].name,
 			sizeof(cap->card));
 		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
@@ -1677,9 +1718,13 @@
 			V4L2_CAP_VIDEO_CAPTURE |
 			V4L2_CAP_VIDEO_OVERLAY |
 			V4L2_CAP_VBI_CAPTURE |
-			V4L2_CAP_TUNER |
 			V4L2_CAP_READWRITE |
-			V4L2_CAP_STREAMING;
+			V4L2_CAP_STREAMING |
+			V4L2_CAP_TUNER;
+
+		if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
+			cap->capabilities &= ~V4L2_CAP_TUNER;
+
 		return 0;
 	}
 
@@ -1793,9 +1838,9 @@
 			crop->c.height = b->top - crop->c.top + b->height;
 
 		if (crop->c.left < b->left)
-			crop->c.top = b->left;
+			crop->c.left = b->left;
 		if (crop->c.left > b->left + b->width)
-			crop->c.top = b->left + b->width;
+			crop->c.left = b->left + b->width;
 		if (crop->c.width > b->left - crop->c.left + b->width)
 			crop->c.width = b->left - crop->c.left + b->width;
 
@@ -1817,6 +1862,7 @@
 				break;
 		if (NULL != card_in(dev,n).name) {
 			strcpy(t->name, "Television");
+			t->type = V4L2_TUNER_ANALOG_TV;
 			t->capability = V4L2_TUNER_CAP_NORM |
 				V4L2_TUNER_CAP_STEREO |
 				V4L2_TUNER_CAP_LANG1 |
@@ -1892,26 +1938,26 @@
 	}
 	case VIDIOC_S_AUDIO:
 		return 0;
-        case VIDIOC_G_PARM:
-        {
-                struct v4l2_captureparm *parm = arg;
-                memset(parm,0,sizeof(*parm));
-                return 0;
-        }
+	case VIDIOC_G_PARM:
+	{
+		struct v4l2_captureparm *parm = arg;
+		memset(parm,0,sizeof(*parm));
+		return 0;
+	}
 
-        case VIDIOC_G_PRIORITY:
-        {
-                enum v4l2_priority *p = arg;
+	case VIDIOC_G_PRIORITY:
+	{
+		enum v4l2_priority *p = arg;
 
-                *p = v4l2_prio_max(&dev->prio);
-                return 0;
-        }
-        case VIDIOC_S_PRIORITY:
-        {
-                enum v4l2_priority *prio = arg;
+		*p = v4l2_prio_max(&dev->prio);
+		return 0;
+	}
+	case VIDIOC_S_PRIORITY:
+	{
+		enum v4l2_priority *prio = arg;
 
-                return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
-        }
+		return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
+	}
 
 	/* --- preview ioctls ---------------------------------------- */
 	case VIDIOC_ENUM_FMT:
@@ -2018,7 +2064,7 @@
 		struct v4l2_format *f = arg;
 		return saa7134_try_fmt(dev,fh,f);
 	}
-
+#ifdef HAVE_V4L1
 	case VIDIOCGMBUF:
 	{
 		struct video_mbuf *mbuf = arg;
@@ -2043,6 +2089,7 @@
 		}
 		return 0;
 	}
+#endif
 	case VIDIOC_REQBUFS:
 		return videobuf_reqbufs(saa7134_queue(fh),arg);
 
@@ -2060,7 +2107,7 @@
 	{
 		int res = saa7134_resource(fh);
 
-                if (!res_get(dev,fh,res))
+		if (!res_get(dev,fh,res))
 			return -EBUSY;
 		return videobuf_streamon(saa7134_queue(fh));
 	}
@@ -2102,7 +2149,7 @@
 		struct v4l2_capability *cap = arg;
 
 		memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
+		strcpy(cap->driver, "saa7134");
 		strlcpy(cap->card, saa7134_boards[dev->board].name,
 			sizeof(cap->card));
 		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
@@ -2119,6 +2166,7 @@
 
 		memset(t,0,sizeof(*t));
 		strcpy(t->name, "Radio");
+		t->type = V4L2_TUNER_RADIO;
 
 		saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
 
@@ -2233,7 +2281,7 @@
 {
 	.name          = "saa7134-video",
 	.type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
-	                 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+			 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
 	.hardware      = 0,
 	.fops          = &video_fops,
 	.minor         = -1,
@@ -2280,7 +2328,7 @@
 		dev->tda9887_conf |= TDA9887_AUTOMUTE;
 	dev->automute       = 0;
 
-        INIT_LIST_HEAD(&dev->video_q.queue);
+	INIT_LIST_HEAD(&dev->video_q.queue);
 	init_timer(&dev->video_q.timeout);
 	dev->video_q.timeout.function = saa7134_buffer_timeout;
 	dev->video_q.timeout.data     = (unsigned long)(&dev->video_q);
@@ -2289,13 +2337,28 @@
 	if (saa7134_boards[dev->board].video_out) {
 		/* enable video output */
 		int vo = saa7134_boards[dev->board].video_out;
+		int video_reg;
+		unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
 		saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]);
+		video_reg = video_out[vo][1];
+		if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+			video_reg &= ~VP_T_CODE_P_INVERTED;
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
 		saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
 		saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
 		saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]);
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]);
+		video_reg = video_out[vo][5];
+		if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+			video_reg &= ~VP_CLK_CTRL2_DELAYED;
+		if (vid_port_opts & SET_CLOCK_INVERTED)
+			video_reg |= VP_CLK_CTRL1_INVERTED;
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+		video_reg = video_out[vo][6];
+		if (vid_port_opts & SET_VSYNC_OFF) {
+			video_reg &= ~VP_VS_TYPE_MASK;
+			video_reg |= VP_VS_TYPE_OFF;
+		}
+		saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
 		saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
 		saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
 	}
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 860b895..fb97274 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -24,16 +24,18 @@
 
 #include <linux/pci.h>
 #include <linux/i2c.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/kdev_t.h>
 #include <linux/input.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 
 #include <media/tuner.h>
 #include <media/audiochip.h>
-#include <media/id.h>
 #include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
 #include <media/video-buf.h>
 #include <media/video-buf-dvb.h>
 
@@ -45,6 +47,10 @@
 #endif
 #define UNSET (-1U)
 
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
 /* ----------------------------------------------------------- */
 /* enums                                                       */
 
@@ -187,10 +193,39 @@
 #define SAA7134_BOARD_FLYTV_DIGIMATRIX 64
 #define SAA7134_BOARD_KWORLD_TERMINATOR 65
 #define SAA7134_BOARD_YUAN_TUN900 66
+#define SAA7134_BOARD_BEHOLD_409FM 67
+#define SAA7134_BOARD_GOTVIEW_7135 68
+#define SAA7134_BOARD_PHILIPS_EUROPA  69
+#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71
+#define SAA7134_BOARD_RTD_VFG7350 72
+#define SAA7134_BOARD_RTD_VFG7330 73
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74
+#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75
+#define SAA7134_BOARD_MONSTERTV_MOBILE 76
+#define SAA7134_BOARD_PINNACLE_PCTV_110i 77
+#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78
+#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS     79
+#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
+#define SAA7134_BOARD_PHILIPS_TIGER  81
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
 
+/* ----------------------------------------------------------- */
+/* Since we support 2 remote types, lets tell them apart       */
+
+#define SAA7134_REMOTE_GPIO  1
+#define SAA7134_REMOTE_I2C   2
+
+/* ----------------------------------------------------------- */
+/* Video Output Port Register Initialization Options           */
+
+#define SET_T_CODE_POLARITY_NON_INVERTED	(1 << 0)
+#define SET_CLOCK_NOT_DELAYED			(1 << 1)
+#define SET_CLOCK_INVERTED			(1 << 2)
+#define SET_VSYNC_OFF				(1 << 3)
+
 struct saa7134_input {
 	char                    *name;
 	unsigned int            vmux;
@@ -226,6 +261,7 @@
 	/* peripheral I/O */
 	enum saa7134_video_out  video_out;
 	enum saa7134_mpeg_type  mpeg;
+	unsigned int            vid_port_opts;
 };
 
 #define card_has_radio(dev)   (NULL != saa7134_boards[dev->board].radio.name)
@@ -319,9 +355,9 @@
 	struct saa7134_pgtable     pt_vbi;
 };
 
-/* oss dsp status */
-struct saa7134_oss {
-        struct semaphore           lock;
+/* dmasound dsp status */
+struct saa7134_dmasound {
+	struct semaphore           lock;
 	int                        minor_mixer;
 	int                        minor_dsp;
 	unsigned int               users_dsp;
@@ -347,6 +383,7 @@
 	unsigned int               dma_blk;
 	unsigned int               read_offset;
 	unsigned int               read_count;
+	snd_pcm_substream_t 	   *substream;
 };
 
 /* IR input */
@@ -358,9 +395,9 @@
 	u32                        mask_keycode;
 	u32                        mask_keydown;
 	u32                        mask_keyup;
-        int                        polling;
-        u32                        last_gpio;
-        struct timer_list          timer;
+	int                        polling;
+	u32                        last_gpio;
+	struct timer_list          timer;
 };
 
 /* ts/mpeg status */
@@ -383,8 +420,8 @@
 /* global device status */
 struct saa7134_dev {
 	struct list_head           devlist;
-        struct semaphore           lock;
-       	spinlock_t                 slock;
+	struct semaphore           lock;
+	spinlock_t                 slock;
 #ifdef VIDIOC_G_PRIORITY
 	struct v4l2_prio_state     prio;
 #endif
@@ -394,7 +431,7 @@
 	struct video_device        *video_dev;
 	struct video_device        *radio_dev;
 	struct video_device        *vbi_dev;
-	struct saa7134_oss         oss;
+	struct saa7134_dmasound    dmasound;
 
 	/* infrared remote */
 	int                        has_remote;
@@ -421,7 +458,7 @@
 	/* i2c i/o */
 	struct i2c_adapter         i2c_adap;
 	struct i2c_client          i2c_client;
-	unsigned char              eedata[64];
+	unsigned char              eedata[128];
 
 	/* video overlay */
 	struct v4l2_framebuffer    ovbuf;
@@ -626,6 +663,7 @@
 int  saa7134_input_init1(struct saa7134_dev *dev);
 void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
+void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 255b608..d32737d 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -50,7 +50,6 @@
 
 #include "bttv.h"
 #include <media/audiochip.h>
-#include <media/id.h>
 
 #ifndef VIDEO_AUDIO_BALANCE
 # define VIDEO_AUDIO_BALANCE 32
@@ -310,9 +309,9 @@
 	memset(t,0,sizeof *t);
 
 	client = &t->c;
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        client->adapter = adap;
-        client->addr = addr;
+	memcpy(client,&client_template,sizeof(struct i2c_client));
+	client->adapter = adap;
+	client->addr = addr;
 	i2c_set_clientdata(client, t);
 
 	do_tda7432_init(client);
@@ -472,7 +471,7 @@
 		}
 		}
 
-	 	t->muted=(va->flags & VIDEO_AUDIO_MUTE);
+		t->muted=(va->flags & VIDEO_AUDIO_MUTE);
 		if (t->muted)
 		{
 			/* Mute & update balance*/
@@ -503,12 +502,12 @@
 
 static struct i2c_driver driver = {
 	.owner           = THIS_MODULE,
-        .name            = "i2c tda7432 driver",
+	.name            = "i2c tda7432 driver",
 	.id              = I2C_DRIVERID_TDA7432,
-        .flags           = I2C_DF_NOTIFY,
+	.flags           = I2C_DF_NOTIFY,
 	.attach_adapter  = tda7432_probe,
-        .detach_client   = tda7432_detach,
-        .command         = tda7432_command,
+	.detach_client   = tda7432_detach,
+	.command         = tda7432_command,
 };
 
 static struct i2c_client client_template =
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index c65f0c7..b2dfe07 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -1,172 +1,406 @@
 /*
- *
- * i2c tv tuner chip device driver
- * controls the philips tda8290+75 tuner chip combo.
- */
+
+   i2c tv tuner chip device driver
+   controls the philips tda8290+75 tuner chip combo.
+
+   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.
+*/
+
 #include <linux/i2c.h>
 #include <linux/videodev.h>
 #include <linux/delay.h>
 #include <media/tuner.h>
 
-#define I2C_ADDR_TDA8290        0x4b
-#define I2C_ADDR_TDA8275        0x61
-
 /* ---------------------------------------------------------------------- */
 
-struct freq_entry {
-	u16	freq;
-	u8	value;
+struct tda827x_data {
+	u32 lomax;
+	u8  spd;
+	u8  bs;
+	u8  bp;
+	u8  cp;
+	u8  gc3;
+	u8 div1p5;
 };
 
-static struct freq_entry band_table[] = {
-	{ 0x2DF4, 0x1C },
-	{ 0x2574, 0x14 },
-	{ 0x22B4, 0x0C },
-	{ 0x20D4, 0x0B },
-	{ 0x1E74, 0x3B },
-	{ 0x1C34, 0x33 },
-	{ 0x16F4, 0x5B },
-	{ 0x1454, 0x53 },
-	{ 0x12D4, 0x52 },
-	{ 0x1034, 0x4A },
-	{ 0x0EE4, 0x7A },
-	{ 0x0D34, 0x72 },
-	{ 0x0B54, 0x9A },
-	{ 0x0914, 0x91 },
-	{ 0x07F4, 0x89 },
-	{ 0x0774, 0xB9 },
-	{ 0x067B, 0xB1 },
-	{ 0x0634, 0xD9 },
-	{ 0x05A4, 0xD8 },	// FM radio
-	{ 0x0494, 0xD0 },
-	{ 0x03BC, 0xC8 },
-	{ 0x0394, 0xF8 },	// 57250000 Hz
-	{ 0x0000, 0xF0 },	// 0
+     /* Note lomax entry is lo / 62500 */
+
+static struct tda827x_data tda827x_analog[] = {
+	{ .lomax =   992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  62 MHz */
+	{ .lomax =  1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  66 MHz */
+	{ .lomax =  1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  76 MHz */
+	{ .lomax =  1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  84 MHz */
+	{ .lomax =  1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  93 MHz */
+	{ .lomax =  1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  98 MHz */
+	{ .lomax =  1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */
+	{ .lomax =  1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */
+	{ .lomax =  2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */
+	{ .lomax =  2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */
+	{ .lomax =  2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */
+	{ .lomax =  2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */
+	{ .lomax =  2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */
+	{ .lomax =  3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */
+	{ .lomax =  3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */
+	{ .lomax =  4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */
+	{ .lomax =  4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */
+	{ .lomax =  5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */
+	{ .lomax =  5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */
+	{ .lomax =  7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */
+	{ .lomax =  7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */
+	{ .lomax =  8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */
+	{ .lomax =  8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */
+	{ .lomax =  9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */
+	{ .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */
+	{ .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */
+	{ .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */
+	{ .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */
+	{ .lomax =     0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}  /* End      */
 };
 
-static struct freq_entry div_table[] = {
-	{ 0x1C34, 3 },
-	{ 0x0D34, 2 },
-	{ 0x067B, 1 },
-        { 0x0000, 0 },
-};
-
-static struct freq_entry agc_table[] = {
-	{ 0x22B4, 0x8F },
-	{ 0x0B54, 0x9F },
-	{ 0x09A4, 0x8F },
-	{ 0x0554, 0x9F },
-	{ 0x0000, 0xBF },
-};
-
-static __u8 get_freq_entry( struct freq_entry* table, __u16 freq)
+static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 {
-	while(table->freq && table->freq > freq)
-		table++;
-	return table->value;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static unsigned char i2c_enable_bridge[2] = 	{ 0x21, 0xC0 };
-static unsigned char i2c_disable_bridge[2] = 	{ 0x21, 0x80 };
-static unsigned char i2c_init_tda8275[14] = 	{ 0x00, 0x00, 0x00, 0x00,
-						  0xfC, 0x04, 0xA3, 0x3F,
-						  0x2A, 0x04, 0xFF, 0x00,
-						  0x00, 0x40 };
-static unsigned char i2c_set_VS[2] = 		{ 0x30, 0x6F };
-static unsigned char i2c_set_GP01_CF[2] = 	{ 0x20, 0x0B };
-static unsigned char i2c_tda8290_reset[2] =	{ 0x00, 0x00 };
-static unsigned char i2c_tda8290_standby[2] =	{ 0x00, 0x02 };
-static unsigned char i2c_gainset_off[2] =	{ 0x28, 0x14 };
-static unsigned char i2c_gainset_on[2] =	{ 0x28, 0x54 };
-static unsigned char i2c_agc3_00[2] =		{ 0x80, 0x00 };
-static unsigned char i2c_agc2_BF[2] =		{ 0x60, 0xBF };
-static unsigned char i2c_cb1_D0[2] =		{ 0x30, 0xD0 };
-static unsigned char i2c_cb1_D2[2] =		{ 0x30, 0xD2 };
-static unsigned char i2c_cb1_56[2] =		{ 0x30, 0x56 };
-static unsigned char i2c_cb1_52[2] =		{ 0x30, 0x52 };
-static unsigned char i2c_cb1_50[2] =		{ 0x30, 0x50 };
-static unsigned char i2c_agc2_7F[2] =		{ 0x60, 0x7F };
-static unsigned char i2c_agc3_08[2] =		{ 0x80, 0x08 };
-
-static struct i2c_msg i2c_msg_init[] = {
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_init_tda8275), i2c_init_tda8275 },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_VS), i2c_set_VS },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_GP01_CF), i2c_set_GP01_CF },
-};
-
-static struct i2c_msg i2c_msg_prolog[] = {
-//	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_easy_mode), i2c_easy_mode },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_off), i2c_gainset_off },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_reset), i2c_tda8290_reset },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge },
-};
-
-static struct i2c_msg i2c_msg_config[] = {
-//	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_set_freq), i2c_set_freq },
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_00), i2c_agc3_00 },
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_BF), i2c_agc2_BF },
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D2), i2c_cb1_D2 },
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_56), i2c_cb1_56 },
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_52), i2c_cb1_52 },
-};
-
-static struct i2c_msg i2c_msg_epilog[] = {
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_50), i2c_cb1_50 },
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_7F), i2c_agc2_7F },
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_08), i2c_agc3_08 },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_on), i2c_gainset_on },
-};
-
-static struct i2c_msg i2c_msg_standby[] = {
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge },
-	{ I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D0), i2c_cb1_D0 },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
-	{ I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_standby), i2c_tda8290_standby },
-};
-
-static int tda8290_tune(struct i2c_client *c)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-	struct i2c_msg easy_mode =
-		{ I2C_ADDR_TDA8290, 0, 2, t->i2c_easy_mode };
-	struct i2c_msg set_freq =
-		{ I2C_ADDR_TDA8275, 0, 8, t->i2c_set_freq  };
-
-	i2c_transfer(c->adapter, &easy_mode,      1);
-	i2c_transfer(c->adapter, i2c_msg_prolog, ARRAY_SIZE(i2c_msg_prolog));
-
-	i2c_transfer(c->adapter, &set_freq,       1);
-	i2c_transfer(c->adapter, i2c_msg_config, ARRAY_SIZE(i2c_msg_config));
-
-	msleep(550);
-	i2c_transfer(c->adapter, i2c_msg_epilog, ARRAY_SIZE(i2c_msg_epilog));
-	return 0;
-}
-
-static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq)
-{
+	unsigned char tuner_reg[8];
+	unsigned char reg2[2];
 	u32 N;
+	int i;
+	struct tuner *t = i2c_get_clientdata(c);
+	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
 
 	if (t->mode == V4L2_TUNER_RADIO)
 		freq = freq / 1000;
 
-	N = (((freq<<3)+ifc)&0x3fffc);
+	N = freq + ifc;
+	i = 0;
+	while (tda827x_analog[i].lomax < N) {
+		if(tda827x_analog[i + 1].lomax == 0)
+			break;
+		i++;
+	}
 
-	N = N >> get_freq_entry(div_table, freq);
-	t->i2c_set_freq[0] = 0;
-	t->i2c_set_freq[1] = (unsigned char)(N>>8);
-	t->i2c_set_freq[2] = (unsigned char) N;
-	t->i2c_set_freq[3] = 0x40;
-	t->i2c_set_freq[4] = 0x52;
-	t->i2c_set_freq[5] = get_freq_entry(band_table, freq);
-	t->i2c_set_freq[6] = get_freq_entry(agc_table,  freq);
-	t->i2c_set_freq[7] = 0x8f;
+	N = N << tda827x_analog[i].spd;
+
+	tuner_reg[0] = 0;
+	tuner_reg[1] = (unsigned char)(N>>8);
+	tuner_reg[2] = (unsigned char) N;
+	tuner_reg[3] = 0x40;
+	tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+	tuner_reg[5] = (tda827x_analog[i].spd   << 6) + (tda827x_analog[i].div1p5 <<5) +
+		       (tda827x_analog[i].bs     <<3) +  tda827x_analog[i].bp;
+	tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
+	tuner_reg[7] = 0x8f;
+
+	msg.buf = tuner_reg;
+	msg.len = 8;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	msg.buf= reg2;
+	msg.len = 2;
+	reg2[0] = 0x80;
+	reg2[1] = 0;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	reg2[0] = 0x60;
+	reg2[1] = 0xbf;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4] + 0x80;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	msleep(1);
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4] + 4;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	msleep(1);
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4];
+	i2c_transfer(c->adapter, &msg, 1);
+
+	msleep(550);
+	reg2[0] = 0x30;
+	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	reg2[0] = 0x60;
+	reg2[1] = 0x3f;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	reg2[0] = 0x80;
+	reg2[1] = 0x08;   // Vsync en
+	i2c_transfer(c->adapter, &msg, 1);
 }
 
+static void tda827x_agcf(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char data[] = {0x80, 0x0c};
+	struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+			      .flags = 0, .len = 2};
+	i2c_transfer(c->adapter, &msg, 1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct tda827xa_data {
+	u32 lomax;
+	u8  svco;
+	u8  spd;
+	u8  scr;
+	u8  sbs;
+	u8  gc3;
+};
+
+static struct tda827xa_data tda827xa_analog[] = {
+	{ .lomax =   910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},  /*  56.875 MHz */
+	{ .lomax =  1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  67.25 MHz */
+	{ .lomax =  1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  81.25 MHz */
+	{ .lomax =  1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  97.5  MHz */
+	{ .lomax =  1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},  /* 113.75 MHz */
+	{ .lomax =  2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 134.5 MHz */
+	{ .lomax =  2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 154   MHz */
+	{ .lomax =  2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 162.5 MHz */
+	{ .lomax =  2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 183   MHz */
+	{ .lomax =  3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},  /* 195   MHz */
+	{ .lomax =  3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},  /* 227.5 MHz */
+	{ .lomax =  4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},  /* 269   MHz */
+	{ .lomax =  5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},  /* 325   MHz */
+	{ .lomax =  6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 390   MHz */
+	{ .lomax =  7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 455   MHz */
+	{ .lomax =  8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 520   MHz */
+	{ .lomax =  8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},  /* 538   MHz */
+	{ .lomax =  8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 554   MHz */
+	{ .lomax =  9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 620   MHz */
+	{ .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 650   MHz */
+	{ .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 700   MHz */
+	{ .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 780   MHz */
+	{ .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 820   MHz */
+	{ .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 870   MHz */
+	{ .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},  /* 911   MHz */
+	{ .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
+};
+
+static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+{
+	unsigned char tuner_reg[14];
+	unsigned char reg2[2];
+	u32 N;
+	int i;
+	struct tuner *t = i2c_get_clientdata(c);
+	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
+
+	if (t->mode == V4L2_TUNER_RADIO)
+		freq = freq / 1000;
+
+	N = freq + ifc;
+	i = 0;
+	while (tda827xa_analog[i].lomax < N) {
+		if(tda827xa_analog[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = N << tda827xa_analog[i].spd;
+
+	tuner_reg[0] = 0;
+	tuner_reg[1] = (unsigned char)(N>>8);
+	tuner_reg[2] = (unsigned char) N;
+	tuner_reg[3] = 0;
+	tuner_reg[4] = 0x16;
+	tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
+			tda827xa_analog[i].sbs;
+	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
+	tuner_reg[7] = 0x0c;
+	tuner_reg[8] = 4;
+	tuner_reg[9] = 0x20;
+	tuner_reg[10] = 0xff;
+	tuner_reg[11] = 0xe0;
+	tuner_reg[12] = 0;
+	tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1);
+
+	msg.buf = tuner_reg;
+	msg.len = 14;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	msg.buf= reg2;
+	msg.len = 2;
+	reg2[0] = 0x60;
+	reg2[1] = 0x3c;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	reg2[0] = 0xa0;
+	reg2[1] = 0xc0;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	msleep(2);
+	reg2[0] = 0x30;
+	reg2[1] = 0x10 + tda827xa_analog[i].scr;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	msleep(550);
+	reg2[0] = 0x50;
+	reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+	i2c_transfer(c->adapter, &msg, 1);
+
+	reg2[0] = 0x80;
+	reg2[1] = 0x28;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	reg2[0] = 0xb0;
+	reg2[1] = 0x01;
+	i2c_transfer(c->adapter, &msg, 1);
+
+	reg2[0] = 0xc0;
+	reg2[1] = 0x19 + (t->tda827x_lpsel << 1);
+	i2c_transfer(c->adapter, &msg, 1);
+}
+
+static void tda827xa_agcf(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char data[] = {0x80, 0x2c};
+	struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+			      .flags = 0, .len = 2};
+	i2c_transfer(c->adapter, &msg, 1);
+}
+
+/*---------------------------------------------------------------------*/
+
+static void tda8290_i2c_bridge(struct i2c_client *c, int close)
+{
+	unsigned char  enable[2] = { 0x21, 0xC0 };
+	unsigned char disable[2] = { 0x21, 0x80 };
+	unsigned char *msg;
+	if(close) {
+		msg = enable;
+		i2c_master_send(c, msg, 2);
+		/* let the bridge stabilize */
+		msleep(20);
+	} else {
+		msg = disable;
+		i2c_master_send(c, msg, 2);
+	}
+}
+
+/*---------------------------------------------------------------------*/
+
+static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char soft_reset[]  = { 0x00, 0x00 };
+	unsigned char easy_mode[]   = { 0x01, t->tda8290_easy_mode };
+	unsigned char expert_mode[] = { 0x01, 0x80 };
+	unsigned char gainset_off[] = { 0x28, 0x14 };
+	unsigned char if_agc_spd[]  = { 0x0f, 0x88 };
+	unsigned char adc_head_6[]  = { 0x05, 0x04 };
+	unsigned char adc_head_9[]  = { 0x05, 0x02 };
+	unsigned char adc_head_12[] = { 0x05, 0x01 };
+	unsigned char pll_bw_nom[]  = { 0x0d, 0x47 };
+	unsigned char pll_bw_low[]  = { 0x0d, 0x27 };
+	unsigned char gainset_2[]   = { 0x28, 0x64 };
+	unsigned char agc_rst_on[]  = { 0x0e, 0x0b };
+	unsigned char agc_rst_off[] = { 0x0e, 0x09 };
+	unsigned char if_agc_set[]  = { 0x0f, 0x81 };
+	unsigned char addr_adc_sat  = 0x1a;
+	unsigned char addr_agc_stat = 0x1d;
+	unsigned char addr_pll_stat = 0x1b;
+	unsigned char adc_sat, agc_stat,
+		      pll_stat;
+
+	i2c_master_send(c, easy_mode, 2);
+	i2c_master_send(c, soft_reset, 2);
+	msleep(1);
+
+	expert_mode[1] = t->tda8290_easy_mode + 0x80;
+	i2c_master_send(c, expert_mode, 2);
+	i2c_master_send(c, gainset_off, 2);
+	i2c_master_send(c, if_agc_spd, 2);
+	if (t->tda8290_easy_mode & 0x60)
+		i2c_master_send(c, adc_head_9, 2);
+	else
+		i2c_master_send(c, adc_head_6, 2);
+	i2c_master_send(c, pll_bw_nom, 2);
+
+	tda8290_i2c_bridge(c, 1);
+	if (t->tda827x_ver != 0)
+		tda827xa_tune(c, ifc, freq);
+	else
+		tda827x_tune(c, ifc, freq);
+	/* adjust headroom resp. gain */
+	i2c_master_send(c, &addr_adc_sat, 1);
+	i2c_master_recv(c, &adc_sat, 1);
+	i2c_master_send(c, &addr_agc_stat, 1);
+	i2c_master_recv(c, &agc_stat, 1);
+	i2c_master_send(c, &addr_pll_stat, 1);
+	i2c_master_recv(c, &pll_stat, 1);
+	if (pll_stat & 0x80)
+		tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
+	else
+		tuner_dbg("tda8290 not locked, no signal?\n");
+	if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
+		tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
+			   agc_stat, adc_sat, pll_stat & 0x80);
+		i2c_master_send(c, gainset_2, 2);
+		msleep(100);
+		i2c_master_send(c, &addr_agc_stat, 1);
+		i2c_master_recv(c, &agc_stat, 1);
+		i2c_master_send(c, &addr_pll_stat, 1);
+		i2c_master_recv(c, &pll_stat, 1);
+		if ((agc_stat > 115) || !(pll_stat & 0x80)) {
+			tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
+				   agc_stat, pll_stat & 0x80);
+			if (t->tda827x_ver != 0)
+				tda827xa_agcf(c);
+			else
+				tda827x_agcf(c);
+			msleep(100);
+			i2c_master_send(c, &addr_agc_stat, 1);
+			i2c_master_recv(c, &agc_stat, 1);
+			i2c_master_send(c, &addr_pll_stat, 1);
+			i2c_master_recv(c, &pll_stat, 1);
+			if((agc_stat > 115) || !(pll_stat & 0x80)) {
+				tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
+				i2c_master_send(c, adc_head_12, 2);
+				i2c_master_send(c, pll_bw_low, 2);
+				msleep(100);
+			}
+		}
+	}
+
+	/* l/ l' deadlock? */
+	if(t->tda8290_easy_mode & 0x60) {
+		i2c_master_send(c, &addr_adc_sat, 1);
+		i2c_master_recv(c, &adc_sat, 1);
+		i2c_master_send(c, &addr_pll_stat, 1);
+		i2c_master_recv(c, &pll_stat, 1);
+		if ((adc_sat > 20) || !(pll_stat & 0x80)) {
+			tuner_dbg("trying to resolve SECAM L deadlock\n");
+			i2c_master_send(c, agc_rst_on, 2);
+			msleep(40);
+			i2c_master_send(c, agc_rst_off, 2);
+		}
+	}
+
+	tda8290_i2c_bridge(c, 0);
+	i2c_master_send(c, if_agc_set, 2);
+	return 0;
+}
+
+
+/*---------------------------------------------------------------------*/
+
 #define V4L2_STD_MN	(V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
 #define V4L2_STD_B	(V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
 #define V4L2_STD_GH	(V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
@@ -174,20 +408,37 @@
 
 static void set_audio(struct tuner *t)
 {
-	t->i2c_easy_mode[0] = 0x01;
+	char* mode;
 
-	if (t->std & V4L2_STD_MN)
-		t->i2c_easy_mode[1] = 0x01;
-	else if (t->std & V4L2_STD_B)
-		t->i2c_easy_mode[1] = 0x02;
-	else if (t->std & V4L2_STD_GH)
-		t->i2c_easy_mode[1] = 0x04;
-	else if (t->std & V4L2_STD_PAL_I)
-		t->i2c_easy_mode[1] = 0x08;
-	else if (t->std & V4L2_STD_DK)
-		t->i2c_easy_mode[1] = 0x10;
-	else if (t->std & V4L2_STD_SECAM_L)
-		t->i2c_easy_mode[1] = 0x20;
+	t->tda827x_lpsel = 0;
+	mode = "xx";
+	if (t->std & V4L2_STD_MN) {
+		t->sgIF = 92;
+		t->tda8290_easy_mode = 0x01;
+		t->tda827x_lpsel = 1;
+		mode = "MN";
+	} else if (t->std & V4L2_STD_B) {
+		t->sgIF = 108;
+		t->tda8290_easy_mode = 0x02;
+		mode = "B";
+	} else if (t->std & V4L2_STD_GH) {
+		t->sgIF = 124;
+		t->tda8290_easy_mode = 0x04;
+		mode = "GH";
+	} else if (t->std & V4L2_STD_PAL_I) {
+		t->sgIF = 124;
+		t->tda8290_easy_mode = 0x08;
+		mode = "I";
+	} else if (t->std & V4L2_STD_DK) {
+		t->sgIF = 124;
+		t->tda8290_easy_mode = 0x10;
+		mode = "DK";
+	} else if (t->std & V4L2_STD_SECAM_L) {
+		t->sgIF = 124;
+		t->tda8290_easy_mode = 0x20;
+		mode = "L";
+	}
+    tuner_dbg("setting tda8290 to system %s\n", mode);
 }
 
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
@@ -195,15 +446,13 @@
 	struct tuner *t = i2c_get_clientdata(c);
 
 	set_audio(t);
-	set_frequency(t, 864, freq);
-	tda8290_tune(c);
+	tda8290_tune(c, t->sgIF, freq);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
-	struct tuner *t = i2c_get_clientdata(c);
-	set_frequency(t, 704, freq);
-	tda8290_tune(c);
+	/* if frequency is 5.5 MHz */
+	tda8290_tune(c, 88, freq);
 }
 
 static int has_signal(struct i2c_client *c)
@@ -216,27 +465,145 @@
 	return (afc & 0x80)? 65535:0;
 }
 
+/*---------------------------------------------------------------------*/
+
 static void standby(struct i2c_client *c)
 {
-	i2c_transfer(c->adapter, i2c_msg_standby, ARRAY_SIZE(i2c_msg_standby));
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char cb1[] = { 0x30, 0xD0 };
+	unsigned char tda8290_standby[] = { 0x00, 0x02 };
+	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+
+	tda8290_i2c_bridge(c, 1);
+	if (t->tda827x_ver != 0)
+		cb1[1] = 0x90;
+	i2c_transfer(c->adapter, &msg, 1);
+	tda8290_i2c_bridge(c, 0);
+	i2c_master_send(c, tda8290_standby, 2);
 }
 
+
+static void tda8290_init_if(struct i2c_client *c)
+{
+	unsigned char set_VS[] = { 0x30, 0x6F };
+	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
+
+	i2c_master_send(c, set_VS, 2);
+	i2c_master_send(c, set_GP01_CF, 2);
+}
+
+static void tda8290_init_tuner(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
+					  0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
+	unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
+					  0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
+	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+			      .buf=tda8275_init, .len = 14};
+	if (t->tda827x_ver != 0)
+		msg.buf = tda8275a_init;
+
+	tda8290_i2c_bridge(c, 1);
+	i2c_transfer(c->adapter, &msg, 1);
+	tda8290_i2c_bridge(c, 0);
+}
+
+/*---------------------------------------------------------------------*/
+
 int tda8290_init(struct i2c_client *c)
 {
 	struct tuner *t = i2c_get_clientdata(c);
+	u8 data;
+	int i, ret, tuners_found;
+	u32 tuner_addrs;
+	struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
 
-	strlcpy(c->name, "tda8290+75", sizeof(c->name));
+	tda8290_i2c_bridge(c, 1);
+	/* probe for tuner chip */
+	tuners_found = 0;
+	tuner_addrs = 0;
+	for (i=0x60; i<= 0x63; i++) {
+		msg.addr = i;
+		ret = i2c_transfer(c->adapter, &msg, 1);
+		if (ret == 1) {
+			tuners_found++;
+			tuner_addrs = (tuner_addrs << 8) + i;
+		}
+	}
+	/* if there is more than one tuner, we expect the right one is
+	   behind the bridge and we choose the highest address that doesn't
+	   give a response now
+	 */
+	tda8290_i2c_bridge(c, 0);
+	if(tuners_found > 1)
+		for (i = 0; i < tuners_found; i++) {
+			msg.addr = tuner_addrs  & 0xff;
+			ret = i2c_transfer(c->adapter, &msg, 1);
+			if(ret == 1)
+				tuner_addrs = tuner_addrs >> 8;
+			else
+				break;
+		}
+	if (tuner_addrs == 0) {
+		tuner_addrs = 0x61;
+		tuner_info ("could not clearly identify tuner address, defaulting to %x\n",
+			     tuner_addrs);
+	} else {
+		tuner_addrs = tuner_addrs & 0xff;
+		tuner_info ("setting tuner address to %x\n", tuner_addrs);
+	}
+	t->tda827x_addr = tuner_addrs;
+	msg.addr = tuner_addrs;
+
+	tda8290_i2c_bridge(c, 1);
+	ret = i2c_transfer(c->adapter, &msg, 1);
+	if( ret != 1)
+		tuner_warn ("TDA827x access failed!\n");
+	if ((data & 0x3c) == 0) {
+		strlcpy(c->name, "tda8290+75", sizeof(c->name));
+		t->tda827x_ver = 0;
+	} else {
+		strlcpy(c->name, "tda8290+75a", sizeof(c->name));
+		t->tda827x_ver = 2;
+	}
 	tuner_info("tuner: type set to %s\n", c->name);
+
 	t->tv_freq    = set_tv_freq;
 	t->radio_freq = set_radio_freq;
 	t->has_signal = has_signal;
 	t->standby = standby;
+	t->tda827x_lpsel = 0;
 
-	i2c_master_send(c, i2c_enable_bridge, ARRAY_SIZE(i2c_enable_bridge));
-	i2c_transfer(c->adapter, i2c_msg_init, ARRAY_SIZE(i2c_msg_init));
+	tda8290_init_tuner(c);
+	tda8290_init_if(c);
 	return 0;
 }
 
+int tda8290_probe(struct i2c_client *c)
+{
+	unsigned char soft_reset[]  = { 0x00, 0x00 };
+	unsigned char easy_mode_b[] = { 0x01, 0x02 };
+	unsigned char easy_mode_g[] = { 0x01, 0x04 };
+	unsigned char addr_dto_lsb = 0x07;
+	unsigned char data;
+
+	i2c_master_send(c, easy_mode_b, 2);
+	i2c_master_send(c, soft_reset, 2);
+	i2c_master_send(c, &addr_dto_lsb, 1);
+	i2c_master_recv(c, &data, 1);
+	if (data == 0) {
+		i2c_master_send(c, easy_mode_g, 2);
+		i2c_master_send(c, soft_reset, 2);
+		i2c_master_send(c, &addr_dto_lsb, 1);
+		i2c_master_recv(c, &data, 1);
+		if (data == 0x7b) {
+			return 0;
+		}
+	}
+	return -1;
+}
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 7e3dcdb..a5e37dc 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -32,7 +32,6 @@
 
 #include "bttv.h"
 #include <media/audiochip.h>
-#include <media/id.h>
 
 static int debug; /* insmod parameter */
 module_param(debug, int, S_IRUGO | S_IWUSR);
@@ -126,20 +125,20 @@
 
 static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg)
 {
-        unsigned char write[1];
-        unsigned char read[1];
-        struct i2c_msg msgs[2] = {
-                { addr, 0,        1, write },
-                { addr, I2C_M_RD, 1, read  }
-        };
-        write[0] = reg;
+	unsigned char write[1];
+	unsigned char read[1];
+	struct i2c_msg msgs[2] = {
+		{ addr, 0,        1, write },
+		{ addr, I2C_M_RD, 1, read  }
+	};
+	write[0] = reg;
 
-        if (2 != i2c_transfer(adap,msgs,2)) {
-                printk(KERN_WARNING "tda9875: I/O error (read2)\n");
-                return -1;
-        }
-        dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
-        return read[0];
+	if (2 != i2c_transfer(adap,msgs,2)) {
+		printk(KERN_WARNING "tda9875: I/O error (read2)\n");
+		return -1;
+	}
+	dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
+	return read[0];
 }
 
 static void tda9875_set(struct i2c_client *client)
@@ -184,7 +183,7 @@
 	tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/
 	tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/
 	tda9875_write(client, TDA9875_LOSR, 0x00 );  /* line out (in:mono)*/
- 	tda9875_write(client, TDA9875_AER, 0x00 );   /*06 Effect (AVL+PSEUDO) */
+	tda9875_write(client, TDA9875_AER, 0x00 );   /*06 Effect (AVL+PSEUDO) */
 	tda9875_write(client, TDA9875_MCS, 0x44 );   /* Main ch select (DAC) */
 	tda9875_write(client, TDA9875_MVL, 0x03 );   /* Vol Main left 10dB */
 	tda9875_write(client, TDA9875_MVR, 0x03 );   /* Vol Main right 10dB*/
@@ -200,7 +199,7 @@
 
 	t->mode=AUDIO_UNMUTE;
 	t->lvol=t->rvol =0;  	/* 0dB */
-	t->bass=0; 		        /* 0dB */
+	t->bass=0; 			/* 0dB */
 	t->treble=0;  		/* 0dB */
 	tda9875_set(client);
 
@@ -239,9 +238,9 @@
 	memset(t,0,sizeof *t);
 
 	client = &t->c;
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        client->adapter = adap;
-        client->addr = addr;
+	memcpy(client,&client_template,sizeof(struct i2c_client));
+	client->adapter = adap;
+	client->addr = addr;
 	i2c_set_clientdata(client, t);
 
 	if(!tda9875_checkit(adap,addr)) {
@@ -287,7 +286,7 @@
 	dprintk("In tda9875_command...\n");
 
 	switch (cmd) {
-        /* --- v4l ioctls --- */
+	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
 	   kernel pointer here... */
 	case VIDIOCGAUDIO:
@@ -355,7 +354,7 @@
 //printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
 
 
-                tda9875_set(client);
+		tda9875_set(client);
 
 		break;
 
@@ -374,18 +373,18 @@
 
 static struct i2c_driver driver = {
 	.owner          = THIS_MODULE,
-        .name           = "i2c tda9875 driver",
-        .id             = I2C_DRIVERID_TDA9875,
-        .flags          = I2C_DF_NOTIFY,
+	.name           = "i2c tda9875 driver",
+	.id             = I2C_DRIVERID_TDA9875,
+	.flags          = I2C_DF_NOTIFY,
 	.attach_adapter = tda9875_probe,
-        .detach_client  = tda9875_detach,
-        .command        = tda9875_command,
+	.detach_client  = tda9875_detach,
+	.command        = tda9875_command,
 };
 
 static struct i2c_client client_template =
 {
-        .name      = "tda9875",
-        .driver    = &driver,
+	.name      = "tda9875",
+	.driver    = &driver,
 };
 
 static int __init tda9875_init(void)
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 94053f1..4249127 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -11,7 +11,6 @@
 
 #include <media/audiochip.h>
 #include <media/tuner.h>
-#include <media/id.h>
 
 /* Chips:
    TDA9885 (PAL, NTSC)
@@ -44,8 +43,13 @@
 /* ---------------------------------------------------------------------- */
 
 #define UNSET       (-1U)
-#define PREFIX      "tda9885/6/7: "
-#define dprintk     if (debug) printk
+#define tda9887_info(fmt, arg...) do {\
+	printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
+			i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
+#define tda9887_dbg(fmt, arg...) do {\
+	if (debug) \
+		printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
+			i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
 
 struct tda9887 {
 	struct i2c_client  client;
@@ -55,6 +59,7 @@
 	unsigned int       pinnacle_id;
 	unsigned int       using_v4l2;
 	unsigned int 	   radio_mode;
+	unsigned char 	   data[4];
 };
 
 struct tvnorm {
@@ -180,7 +185,8 @@
 		.name  = "SECAM-L",
 		.b     = ( cPositiveAmTV  |
 			   cQSS           ),
-		.e     = ( cAudioIF_6_5   |
+		.e     = ( cGating_36	  |
+			   cAudioIF_6_5   |
 			   cVideoIF_38_90 ),
 	},{
 		.std   = V4L2_STD_SECAM_DK,
@@ -236,7 +242,7 @@
 
 /* ---------------------------------------------------------------------- */
 
-static void dump_read_message(unsigned char *buf)
+static void dump_read_message(struct tda9887 *t, unsigned char *buf)
 {
 	static char *afc[16] = {
 		"- 12.5 kHz",
@@ -256,15 +262,15 @@
 		"+ 37.5 kHz",
 		"+ 12.5 kHz",
 	};
-	printk(PREFIX "read: 0x%2x\n", buf[0]);
-	printk("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
-	printk("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
-	printk("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
-	printk("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
-	printk("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
+	tda9887_info("read: 0x%2x\n", buf[0]);
+	tda9887_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
+	tda9887_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
+	tda9887_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
+	tda9887_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
+	tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
 }
 
-static void dump_write_message(unsigned char *buf)
+static void dump_write_message(struct tda9887 *t, unsigned char *buf)
 {
 	static char *sound[4] = {
 		"AM/TV",
@@ -304,58 +310,58 @@
 		"44 MHz",
 	};
 
-	printk(PREFIX "write: byte B 0x%02x\n",buf[1]);
-	printk("  B0   video mode      : %s\n",
+	tda9887_info("write: byte B 0x%02x\n",buf[1]);
+	tda9887_info("  B0   video mode      : %s\n",
 	       (buf[1] & 0x01) ? "video trap" : "sound trap");
-	printk("  B1   auto mute fm    : %s\n",
+	tda9887_info("  B1   auto mute fm    : %s\n",
 	       (buf[1] & 0x02) ? "yes" : "no");
-	printk("  B2   carrier mode    : %s\n",
+	tda9887_info("  B2   carrier mode    : %s\n",
 	       (buf[1] & 0x04) ? "QSS" : "Intercarrier");
-	printk("  B3-4 tv sound/radio  : %s\n",
+	tda9887_info("  B3-4 tv sound/radio  : %s\n",
 	       sound[(buf[1] & 0x18) >> 3]);
-	printk("  B5   force mute audio: %s\n",
+	tda9887_info("  B5   force mute audio: %s\n",
 	       (buf[1] & 0x20) ? "yes" : "no");
-	printk("  B6   output port 1   : %s\n",
+	tda9887_info("  B6   output port 1   : %s\n",
 	       (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
-	printk("  B7   output port 2   : %s\n",
+	tda9887_info("  B7   output port 2   : %s\n",
 	       (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
 
-	printk(PREFIX "write: byte C 0x%02x\n",buf[2]);
-	printk("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
-	printk("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
-	printk("  C7   audio gain      : %s\n",
+	tda9887_info("write: byte C 0x%02x\n",buf[2]);
+	tda9887_info("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
+	tda9887_info("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
+	tda9887_info("  C7   audio gain      : %s\n",
 	       (buf[2] & 0x80) ? "-6" : "0");
 
-	printk(PREFIX "write: byte E 0x%02x\n",buf[3]);
-	printk("  E0-1 sound carrier   : %s\n",
+	tda9887_info("write: byte E 0x%02x\n",buf[3]);
+	tda9887_info("  E0-1 sound carrier   : %s\n",
 	       carrier[(buf[3] & 0x03)]);
-	printk("  E6   l pll ganting   : %s\n",
+	tda9887_info("  E6   l pll gating   : %s\n",
 	       (buf[3] & 0x40) ? "36" : "13");
 
 	if (buf[1] & 0x08) {
 		/* radio */
-		printk("  E2-4 video if        : %s\n",
+		tda9887_info("  E2-4 video if        : %s\n",
 		       rif[(buf[3] & 0x0c) >> 2]);
-		printk("  E7   vif agc output  : %s\n",
+		tda9887_info("  E7   vif agc output  : %s\n",
 		       (buf[3] & 0x80)
 		       ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
 		       : "fm radio carrier afc");
 	} else {
 		/* video */
-		printk("  E2-4 video if        : %s\n",
+		tda9887_info("  E2-4 video if        : %s\n",
 		       vif[(buf[3] & 0x1c) >> 2]);
-		printk("  E5   tuner gain      : %s\n",
+		tda9887_info("  E5   tuner gain      : %s\n",
 		       (buf[3] & 0x80)
 		       ? ((buf[3] & 0x20) ? "external" : "normal")
 		       : ((buf[3] & 0x20) ? "minimum"  : "normal"));
-		printk("  E7   vif agc output  : %s\n",
+		tda9887_info("  E7   vif agc output  : %s\n",
 		       (buf[3] & 0x80)
 		       ? ((buf[3] & 0x20)
 			  ? "pin3 port, pin22 vif agc out"
 			  : "pin22 port, pin3 vif acg ext in")
 		       : "pin3+pin22 port");
 	}
-	printk("--\n");
+	tda9887_info("--\n");
 }
 
 /* ---------------------------------------------------------------------- */
@@ -379,11 +385,11 @@
 		}
 	}
 	if (NULL == norm) {
-		dprintk(PREFIX "Unsupported tvnorm entry - audio muted\n");
+		tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
 		return -1;
 	}
 
-	dprintk(PREFIX "configure for: %s\n",norm->name);
+	tda9887_dbg("configure for: %s\n",norm->name);
 	buf[1] = norm->b;
 	buf[2] = norm->c;
 	buf[3] = norm->e;
@@ -458,6 +464,8 @@
 			break;
 		}
 	}
+	if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+		buf[1] &= ~cQSS;
 	return 0;
 }
 
@@ -475,11 +483,11 @@
 		}
 	}
 	if (t->std & V4L2_STD_525_60) {
-                if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
+		if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
 			bCarrierMode = cIntercarrier;
 		} else {
 			bCarrierMode = cQSS;
-                }
+		}
 	}
 
 	if (bCarrierMode != UNSET) {
@@ -505,26 +513,26 @@
 		case 'B':
 		case 'g':
 		case 'G':
-			dprintk(PREFIX "insmod fixup: PAL => PAL-BG\n");
+			tda9887_dbg("insmod fixup: PAL => PAL-BG\n");
 			t->std = V4L2_STD_PAL_BG;
 			break;
 		case 'i':
 		case 'I':
-			dprintk(PREFIX "insmod fixup: PAL => PAL-I\n");
+			tda9887_dbg("insmod fixup: PAL => PAL-I\n");
 			t->std = V4L2_STD_PAL_I;
 			break;
 		case 'd':
 		case 'D':
 		case 'k':
 		case 'K':
-			dprintk(PREFIX "insmod fixup: PAL => PAL-DK\n");
+			tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
 			t->std = V4L2_STD_PAL_DK;
 			break;
 		case '-':
 			/* default parameter, do nothing */
 			break;
 		default:
-			printk(PREFIX "pal= argument not recognised\n");
+			tda9887_info("pal= argument not recognised\n");
 			break;
 		}
 	}
@@ -534,19 +542,19 @@
 		case 'D':
 		case 'k':
 		case 'K':
-			dprintk(PREFIX "insmod fixup: SECAM => SECAM-DK\n");
+			tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
 			t->std = V4L2_STD_SECAM_DK;
 			break;
 		case 'l':
 		case 'L':
-			dprintk(PREFIX "insmod fixup: SECAM => SECAM-L\n");
+			tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
 			t->std = V4L2_STD_SECAM_L;
 			break;
 		case '-':
 			/* default parameter, do nothing */
 			break;
 		default:
-			printk(PREFIX "secam= argument not recognised\n");
+			tda9887_info("secam= argument not recognised\n");
 			break;
 		}
 	}
@@ -559,41 +567,40 @@
 	int rc;
 
 	memset(buf,0,sizeof(buf));
-        if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
-                printk(PREFIX "i2c i/o error: rc == %d (should be 1)\n",rc);
-	dump_read_message(buf);
+	if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
+		tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
+	dump_read_message(t, buf);
 	return 0;
 }
 
 static int tda9887_configure(struct tda9887 *t)
 {
-	unsigned char buf[4];
 	int rc;
 
-	memset(buf,0,sizeof(buf));
-	tda9887_set_tvnorm(t,buf);
+	memset(t->data,0,sizeof(t->data));
+	tda9887_set_tvnorm(t,t->data);
 
-	buf[1] |= cOutputPort1Inactive;
-	buf[1] |= cOutputPort2Inactive;
+	t->data[1] |= cOutputPort1Inactive;
+	t->data[1] |= cOutputPort2Inactive;
 
 	if (UNSET != t->pinnacle_id) {
-		tda9887_set_pinnacle(t,buf);
+		tda9887_set_pinnacle(t,t->data);
 	}
-	tda9887_set_config(t,buf);
-	tda9887_set_insmod(t,buf);
+	tda9887_set_config(t,t->data);
+	tda9887_set_insmod(t,t->data);
 
 	if (t->mode == T_STANDBY) {
-		buf[1] |= cForcedMuteAudioON;
+		t->data[1] |= cForcedMuteAudioON;
 	}
 
 
-	dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n",
-		buf[1],buf[2],buf[3]);
+	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
+		t->data[1],t->data[2],t->data[3]);
 	if (debug > 1)
-		dump_write_message(buf);
+		dump_write_message(t, t->data);
 
-        if (4 != (rc = i2c_master_send(&t->client,buf,4)))
-                printk(PREFIX "i2c i/o error: rc == %d (should be 4)\n",rc);
+	if (4 != (rc = i2c_master_send(&t->client,t->data,4)))
+		tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
 
 	if (debug > 2) {
 		msleep_interruptible(1000);
@@ -608,13 +615,11 @@
 {
 	struct tda9887 *t;
 
-        client_template.adapter = adap;
-        client_template.addr    = addr;
+	client_template.adapter = adap;
+	client_template.addr    = addr;
 
-        printk(PREFIX "chip found @ 0x%x\n", addr<<1);
-
-        if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
-                return -ENOMEM;
+	if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+		return -ENOMEM;
 	memset(t,0,sizeof(*t));
 
 	t->client      = client_template;
@@ -622,6 +627,8 @@
 	t->pinnacle_id = UNSET;
 	t->radio_mode = V4L2_TUNER_MODE_STEREO;
 
+	tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
+
 	i2c_set_clientdata(&t->client, t);
 	i2c_attach_client(&t->client);
 
@@ -655,18 +662,18 @@
 }
 
 #define SWITCH_V4L2	if (!t->using_v4l2 && debug) \
-		          printk(PREFIX "switching to v4l2\n"); \
-	                  t->using_v4l2 = 1;
+			  tda9887_info("switching to v4l2\n"); \
+			  t->using_v4l2 = 1;
 #define CHECK_V4L2	if (t->using_v4l2) { if (debug) \
-			  printk(PREFIX "ignore v4l1 call\n"); \
-		          return 0; }
+			  tda9887_info("ignore v4l1 call\n"); \
+			  return 0; }
 
 static int
 tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct tda9887 *t = i2c_get_clientdata(client);
 
-        switch (cmd) {
+	switch (cmd) {
 
 	/* --- configuration --- */
 	case AUDC_SET_RADIO:
@@ -777,6 +784,11 @@
 		}
 		break;
 	}
+	case VIDIOC_LOG_STATUS:
+	{
+		tda9887_info("Data bytes: b=%02x c=%02x e=%02x\n", t->data[1], t->data[2], t->data[3]);
+		break;
+	}
 	default:
 		/* nothing */
 		break;
@@ -786,7 +798,10 @@
 
 static int tda9887_suspend(struct device * dev, pm_message_t state)
 {
-	dprintk("tda9887: suspend\n");
+	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+	struct tda9887 *t = i2c_get_clientdata(c);
+
+	tda9887_dbg("suspend\n");
 	return 0;
 }
 
@@ -795,7 +810,7 @@
 	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
 	struct tda9887 *t = i2c_get_clientdata(c);
 
-	dprintk("tda9887: resume\n");
+	tda9887_dbg("resume\n");
 	tda9887_configure(t);
 	return 0;
 }
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index 38bf509..a9375ef 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -117,10 +117,10 @@
 #define TEA5767_RESERVED_MASK	0xff
 
 enum tea5767_xtal_freq {
-        TEA5767_LOW_LO_32768    = 0,
-        TEA5767_HIGH_LO_32768   = 1,
-        TEA5767_LOW_LO_13MHz    = 2,
-        TEA5767_HIGH_LO_13MHz   = 3,
+	TEA5767_LOW_LO_32768    = 0,
+	TEA5767_HIGH_LO_32768   = 1,
+	TEA5767_LOW_LO_13MHz    = 2,
+	TEA5767_HIGH_LO_13MHz   = 3,
 };
 
 
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index ad85bef..73c4041 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -28,7 +28,7 @@
 
 /* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
-	0x4b,			/* tda8290 */
+	0x42, 0x43, 0x4a, 0x4b,			/* tda8290 */
 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
 	I2C_CLIENT_END
@@ -189,6 +189,13 @@
 		i2c_master_send(c, buffer, 4);
 		default_tuner_init(c);
 		break;
+	case TUNER_PHILIPS_TD1316:
+		buffer[0] = 0x0b;
+		buffer[1] = 0xdc;
+		buffer[2] = 0x86;
+		buffer[3] = 0xa4;
+		i2c_master_send(c,buffer,4);
+		default_tuner_init(c);
 	default:
 		default_tuner_init(c);
 		break;
@@ -215,9 +222,9 @@
 {
 	struct tuner *t = i2c_get_clientdata(c);
 
-	if ((tun_setup->addr == ADDR_UNSET &&
+	if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
 		(t->mode_mask & tun_setup->mode_mask)) ||
-		tun_setup->addr == c->addr) {
+		tun_setup->addr == c->addr)) {
 			set_type(c, tun_setup->type, tun_setup->mode_mask);
 	}
 }
@@ -341,23 +348,33 @@
 	t->audmode = V4L2_TUNER_MODE_STEREO;
 	t->mode_mask = T_UNINITIALIZED;
 
-
-	tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
-
 	if (show_i2c) {
 		unsigned char buffer[16];
 		int i,rc;
 
 		memset(buffer, 0, sizeof(buffer));
 		rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
-		printk("tuner-%04x I2C RECV = ",addr);
+		tuner_info("I2C RECV = ");
 		for (i=0;i<rc;i++)
 			printk("%02x ",buffer[i]);
 		printk("\n");
 	}
 	/* TEA5767 autodetection code - only for addr = 0xc0 */
 	if (!no_autodetect) {
-		if (addr == 0x60) {
+		switch (addr) {
+		case 0x42:
+		case 0x43:
+		case 0x4a:
+		case 0x4b:
+			/* If chip is not tda8290, don't register.
+			   since it can be tda9887*/
+			if (tda8290_probe(&t->i2c) != 0) {
+				tuner_dbg("chip at addr %x is not a tda8290\n", addr);
+				kfree(t);
+				return 0;
+			}
+			break;
+		case 0x60:
 			if (tea5767_autodetection(&t->i2c) != EINVAL) {
 				t->type = TUNER_TEA5767;
 				t->mode_mask = T_RADIO;
@@ -365,10 +382,9 @@
 				t->freq = 87.5 * 16; /* Sets freq to FM range */
 				default_mode_mask &= ~T_RADIO;
 
-				i2c_attach_client (&t->i2c);
-				set_type(&t->i2c,t->type, t->mode_mask);
-				return 0;
+				goto register_client;
 			}
+			break;
 		}
 	}
 
@@ -381,6 +397,8 @@
 	}
 
 	/* Should be just before return */
+register_client:
+	tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
 	i2c_attach_client (&t->i2c);
 	set_type (&t->i2c,t->type, t->mode_mask);
 	return 0;
@@ -425,23 +443,23 @@
 
 static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
 {
- 	if (mode == t->mode)
- 		return 0;
+	if (mode == t->mode)
+		return 0;
 
- 	t->mode = mode;
+	t->mode = mode;
 
- 	if (check_mode(t, cmd) == EINVAL) {
- 		t->mode = T_STANDBY;
- 		if (t->standby)
- 			t->standby (client);
- 		return EINVAL;
-  	}
-  	return 0;
+	if (check_mode(t, cmd) == EINVAL) {
+		t->mode = T_STANDBY;
+		if (t->standby)
+			t->standby (client);
+		return EINVAL;
+	}
+	return 0;
 }
 
 #define switch_v4l2()	if (!t->using_v4l2) \
-		            tuner_dbg("switching to v4l2\n"); \
-	                t->using_v4l2 = 1;
+			    tuner_dbg("switching to v4l2\n"); \
+			t->using_v4l2 = 1;
 
 static inline int check_v4l2(struct tuner *t)
 {
@@ -479,8 +497,6 @@
 			break;
 		}
 	case AUDC_CONFIG_PINNACLE:
-		if (check_mode(t, "AUDC_CONFIG_PINNACLE") == EINVAL)
-			return 0;
 		switch (*iarg) {
 		case 2:
 			tuner_dbg("pinnacle pal\n");
@@ -616,7 +632,7 @@
 			switch_v4l2();
 			if (V4L2_TUNER_RADIO == f->type &&
 			    V4L2_TUNER_RADIO != t->mode) {
-			        if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
+				if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
 					    == EINVAL)
 					return 0;
 			}
@@ -688,7 +704,7 @@
 			break;
 		}
 	default:
-		tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp=0x%02x,nr=%d,sz=%d)\n",
+		tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n",
 					 cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd),
 					_IOC_NR(cmd), _IOC_SIZE(cmd));
 		break;
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 8edd73a..d832205 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -102,7 +102,7 @@
  */
 static struct tunertype tuners[] = {
 	/* 0-9 */
-        { "Temic PAL (4002 FH5)", TEMIC, PAL,
+	{ "Temic PAL (4002 FH5)", TEMIC, PAL,
 	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
 	{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
 	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
@@ -118,41 +118,41 @@
 	  16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
 	{ "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
 	  16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
- 	{ "Temic NTSC (4036 FY5)", TEMIC, NTSC,
+	{ "Temic NTSC (4036 FY5)", TEMIC, NTSC,
 	  16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
-        { "Alps HSBH1", TEMIC, NTSC,
+	{ "Alps HSBH1", TEMIC, NTSC,
 	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
 
 	/* 10-19 */
-        { "Alps TSBE1", TEMIC, PAL,
+	{ "Alps TSBE1", TEMIC, PAL,
 	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
-        { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
+	{ "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
-        { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+	{ "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
-        { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+	{ "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
 	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
 	{ "Temic PAL_BG (4006FH5)", TEMIC, PAL,
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-  	{ "Alps TSCH6", Alps, NTSC,
-  	  16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
-  	{ "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
-  	  16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
-  	{ "Philips NTSC_M (MK2)", Philips, NTSC,
-  	  16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
-        { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
-          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
-          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+	{ "Alps TSCH6", Alps, NTSC,
+	  16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
+	{ "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
+	  16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
+	{ "Philips NTSC_M (MK2)", Philips, NTSC,
+	  16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
+	{ "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
+	  16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+	{ "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
+	  16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
 
 	/* 20-29 */
-        { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
-          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
-          16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
-        { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
-          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
+	{ "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
+	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+	{ "Temic NTSC (4039 FR5)", TEMIC, NTSC,
+	  16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+	{ "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
+	  16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+	{ "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
 	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
@@ -173,21 +173,21 @@
 	{ "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
 	  16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 },
 	{ "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */
-          16*169,16*464,0xA0,0x90,0x30,0x8e,623},
+	  16*169,16*464,0xA0,0x90,0x30,0x8e,623},
 	{ "MT20xx universal", Microtune, PAL|NTSC,
 	  /* see mt20xx.c for details */ },
 	{ "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
-          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
 	{ "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
-          16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
+	  16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
 	{ "Temic NTSC (4136 FY5)", TEMIC, NTSC,
-          16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
-        { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
-          16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
+	  16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+	{ "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
+	  16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
 	{ "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
-	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
+	  16*158.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
 	{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
-          16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
+	  16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
 
 	/* 40-49 */
 	{ "HITACHI V7-J180AT", HITACHI, NTSC,
@@ -196,24 +196,24 @@
 	  16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
 	{ "Philips 1236D ATSC/NTSC daul in", Philips, ATSC,
 	  16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
-        { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
-        { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+	{ "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
+	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+	{ "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
+	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
 	{ "Microtune 4049 FM5", Microtune, PAL,
 	  16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
 	{ "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
 	  16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
-        { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
-        { "Tenna TNF 8831 BGFF)", Philips, PAL,
-          16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
+	{ "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
+	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
+	{ "Tenna TNF 8831 BGFF)", Philips, PAL,
+	  16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
 	{ "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
 	  16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
 
 	/* 50-59 */
-        { "TCL 2002N", TCL, NTSC,
-          16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
+	{ "TCL 2002N", TCL, NTSC,
+	  16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
 	{ "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL,
 	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
 	{ "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC,
@@ -222,8 +222,8 @@
 	  16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */
 	{ "tda8290+75", Philips, PAL|NTSC,
 	  /* see tda8290.c for details */ },
-	{ "LG PAL (TAPE series)", LGINNOTEK, PAL,
-          16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
+	{ "TCL 2002MB", TCL, PAL,
+	  16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
 	{ "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
 	  16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
 	{ "Philips FQ1236A MK4", Philips, NTSC,
@@ -233,21 +233,25 @@
 	{ "Ymec TVision TVF-5533MF", Philips, NTSC,
 	  16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
 
-	/* 60-66 */
+	/* 60-68 */
 	{ "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
 	  16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
 	{ "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
-          16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
+	  16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
 	{ "Philips TEA5767HN FM Radio", Philips, RADIO,
-          /* see tea5767.c for details */},
+	  /* see tea5767.c for details */},
 	{ "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL,
 	  16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 },
 	{ "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC,
 	  16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732},
 	{ "Ymec TVF66T5-B/DFF", Philips, PAL,
-          16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
- 	{ "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
+	  16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
+	{ "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
 	  16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 },
+	{ "Philips TD1316 Hybrid Tuner", Philips, PAL,
+	  16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 },
+	{ "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC,
+	  16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 },
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
@@ -277,7 +281,7 @@
 	status = tuner_getstatus (c);
 
 	switch (t->type) {
-        	case TUNER_PHILIPS_FM1216ME_MK3:
+		case TUNER_PHILIPS_FM1216ME_MK3:
     		case TUNER_PHILIPS_FM1236_MK3:
 		case TUNER_PHILIPS_FM1256_IH3:
 			stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
@@ -295,10 +299,10 @@
 static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
 	struct tuner *t = i2c_get_clientdata(c);
-	u8 config;
+	u8 config, tuneraddr;
 	u16 div;
 	struct tunertype *tun;
-        unsigned char buffer[4];
+	unsigned char buffer[4];
 	int rc;
 
 	tun = &tuners[t->type];
@@ -373,6 +377,31 @@
 		/* Set the charge pump for fast tuning */
 		tun->config |= TUNER_CHARGE_PUMP;
 		break;
+
+	case TUNER_PHILIPS_TUV1236D:
+		/* 0x40 -> ATSC antenna input 1 */
+		/* 0x48 -> ATSC antenna input 2 */
+		/* 0x00 -> NTSC antenna input 1 */
+		/* 0x08 -> NTSC antenna input 2 */
+		buffer[0] = 0x14;
+		buffer[1] = 0x00;
+		buffer[2] = 0x17;
+		buffer[3] = 0x00;
+		config &= ~0x40;
+		if (t->std & V4L2_STD_ATSC) {
+			config |= 0x40;
+			buffer[1] = 0x04;
+		}
+		/* set to the correct mode (analog or digital) */
+		tuneraddr = c->addr;
+		c->addr = 0x0a;
+		if (2 != (rc = i2c_master_send(c,&buffer[0],2)))
+			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+		if (2 != (rc = i2c_master_send(c,&buffer[2],2)))
+			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+		c->addr = tuneraddr;
+		/* FIXME: input */
+		break;
 	}
 
 	/*
@@ -404,7 +433,7 @@
 	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
 		  buffer[0],buffer[1],buffer[2],buffer[3]);
 
-        if (4 != (rc = i2c_master_send(c,buffer,4)))
+	if (4 != (rc = i2c_master_send(c,buffer,4)))
 		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
 
 	if (t->type == TUNER_MICROTUNE_4042FI5) {
@@ -443,7 +472,7 @@
 {
 	struct tunertype *tun;
 	struct tuner *t = i2c_get_clientdata(c);
-        unsigned char buffer[4];
+	unsigned char buffer[4];
 	unsigned div;
 	int rc;
 
@@ -476,13 +505,13 @@
 		buffer[3] = 0xa4;
 		break;
 	}
-        buffer[0] = (div>>8) & 0x7f;
-        buffer[1] = div      & 0xff;
+	buffer[0] = (div>>8) & 0x7f;
+	buffer[1] = div      & 0xff;
 
 	tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
 	       buffer[0],buffer[1],buffer[2],buffer[3]);
 
-        if (4 != (rc = i2c_master_send(c,buffer,4)))
+	if (4 != (rc = i2c_master_send(c,buffer,4)))
 		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
 }
 
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 1c31ef5..c31bf28 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -31,7 +31,6 @@
 #include <linux/smp_lock.h>
 
 #include <media/audiochip.h>
-#include <media/id.h>
 
 #include "tvaudio.h"
 
@@ -458,8 +457,8 @@
 #define TDA9855_LOUD	1<<5 /* Loudness, 1==off */
 #define TDA9855_SUR	1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
 			     /* Bits 0 to 3 select various combinations
-                              * of line in and line out, only the
-                              * interesting ones are defined */
+			      * of line in and line out, only the
+			      * interesting ones are defined */
 #define TDA9855_EXT	1<<2 /* Selects inputs LIR and LIL.  Pins 41 & 12 */
 #define TDA9855_INT	0    /* Selects inputs LOR and LOL.  (internal) */
 
@@ -1028,7 +1027,7 @@
 #define TEA6300_TR         0x03  /* treble */
 #define TEA6300_FA         0x04  /* fader control */
 #define TEA6300_S          0x05  /* switch register */
-                                 /* values for those registers: */
+				 /* values for those registers: */
 #define TEA6300_S_SA       0x01  /* stereo A input */
 #define TEA6300_S_SB       0x02  /* stereo B */
 #define TEA6300_S_SC       0x04  /* stereo C */
@@ -1042,7 +1041,7 @@
 #define TEA6320_BA         0x05  /* bass (0-4) */
 #define TEA6320_TR         0x06  /* treble (0-4) */
 #define TEA6320_S          0x07  /* switch register */
-                                 /* values for those registers: */
+				 /* values for those registers: */
 #define TEA6320_S_SA       0x07  /* stereo A input */
 #define TEA6320_S_SB       0x06  /* stereo B */
 #define TEA6320_S_SC       0x05  /* stereo C */
@@ -1082,7 +1081,7 @@
 #define TDA8425_BA         0x02  /* bass */
 #define TDA8425_TR         0x03  /* treble */
 #define TDA8425_S1         0x08  /* switch functions */
-                                 /* values for those registers: */
+				 /* values for those registers: */
 #define TDA8425_S1_OFF     0xEE  /* audio off (mute on) */
 #define TDA8425_S1_CH1     0xCE  /* audio channel 1 (mute off) - "linear stereo" mode */
 #define TDA8425_S1_CH2     0xCF  /* audio channel 2 (mute off) - "linear stereo" mode */
@@ -1148,7 +1147,7 @@
 
 /* bit definition of the RESET register, I2C data. */
 #define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */
-                                            /*        code of remote controller */
+					    /*        code of remote controller */
 #define PIC16C54_MISC_MTS_MAIN         0x02 /* bit 1 */
 #define PIC16C54_MISC_MTS_SAP          0x04 /* bit 2 */
 #define PIC16C54_MISC_MTS_BOTH         0x08 /* bit 3 */
@@ -1281,7 +1280,7 @@
 		.setmode    = tda9840_setmode,
 		.checkmode  = generic_checkmode,
 
-	        .init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+		.init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
 				/* ,TDA9840_SW, TDA9840_MONO */} }
 	},
 	{
@@ -1438,7 +1437,7 @@
 	},
 	{
 		.name       = "pic16c54 (PV951)",
-		.id         = I2C_DRIVERID_PIC16C54_PV951,
+		.id         = I2C_DRIVERID_PIC16C54_PV9,
 		.insmodopt  = &pic16c54,
 		.addr_lo    = I2C_PIC16C54 >> 1,
 		.addr_hi    = I2C_PIC16C54>> 1,
@@ -1467,7 +1466,7 @@
 		.setmode    = ta8874z_setmode,
 		.checkmode  = generic_checkmode,
 
-	        .init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
+		.init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
 	},
 	{ .name = NULL } /* EOF */
 };
@@ -1486,8 +1485,8 @@
 		return -ENOMEM;
 	memset(chip,0,sizeof(*chip));
 	memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
-        chip->c.adapter = adap;
-        chip->c.addr = addr;
+	chip->c.adapter = adap;
+	chip->c.addr = addr;
 	i2c_set_clientdata(&chip->c, chip);
 
 	/* find description for the chip */
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 5344d55..72e8741 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -6,12 +6,12 @@
  * which are:
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+			   & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
 
  * Adjustments to fit a more general model and all bugs:
 
- 	Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
+	Copyright (C) 2003 John Klar <linpvr at projectplasma.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
@@ -40,6 +40,7 @@
 
 #include <media/tuner.h>
 #include <media/tveeprom.h>
+#include <media/audiochip.h>
 
 MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
 MODULE_AUTHOR("John Klar");
@@ -53,14 +54,14 @@
 
 #define tveeprom_info(fmt, arg...) do {\
 	printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
-                        c->adapter->nr, c->addr , ##arg); } while (0)
+			c->adapter->nr, c->addr , ##arg); } while (0)
 #define tveeprom_warn(fmt, arg...) do {\
 	printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \
-                        c->adapter->nr, c->addr , ##arg); } while (0)
+			c->adapter->nr, c->addr , ##arg); } while (0)
 #define tveeprom_dbg(fmt, arg...) do {\
 	if (debug) \
-                printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
-                        c->adapter->nr, c->addr , ##arg); } while (0)
+		printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
+			c->adapter->nr, c->addr , ##arg); } while (0)
 
 
 /* ----------------------------------------------------------------------- */
@@ -134,8 +135,8 @@
 	{ TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
 	{ TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
 	{ TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
-        { TUNER_PHILIPS_NTSC,        "Philips TD1536" },
-        { TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
+	{ TUNER_PHILIPS_NTSC,        "Philips TD1536" },
+	{ TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
 	{ TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
 	{ TUNER_ABSENT,        "Philips FI1256MP" },
 	/* 40-49 */
@@ -189,7 +190,7 @@
 	{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
 	{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
 	{ TUNER_TCL_2002N,     "TCL 2002N 6A"},
-	{ TUNER_ABSENT,        "Philips FQ1236 MK3"},
+	{ TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
 	{ TUNER_ABSENT,        "Samsung TCPN 2121P30A"},
 	{ TUNER_ABSENT,        "Samsung TCPE 4121P30A"},
 	{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
@@ -200,95 +201,137 @@
 	{ TUNER_ABSENT,        "Philips FQ1286A MK4"},
 	{ TUNER_ABSENT,        "Philips FQ1216ME MK5"},
 	{ TUNER_ABSENT,        "Philips FQ1236 MK5"},
-	{ TUNER_ABSENT,        "Unspecified"},
-	{ TUNER_LG_PAL_TAPE,   "LG PAL (TAPE Series)"},
-        { TUNER_ABSENT,        "Unspecified"},
-        { TUNER_TCL_2002N,     "TCL 2002N 5H"},
-	/* 100-103 */
-	{ TUNER_ABSENT,        "Unspecified"},
-        { TUNER_TEA5767,       "Philips TEA5767HN FM Radio"},
-        { TUNER_ABSENT,        "Unspecified"},
-        { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05 4"},
+	{ TUNER_ABSENT,        "Samsung TCPG_6121P30A"},
+	{ TUNER_TCL_2002MB,    "TCL 2002MB_3H"},
+	{ TUNER_ABSENT,        "TCL 2002MI_3H"},
+	{ TUNER_TCL_2002N,     "TCL 2002N 5H"},
+	/* 100-109 */
+	{ TUNER_ABSENT,        "Philips FMD1216ME"},
+	{ TUNER_TEA5767,       "Philips TEA5768HL FM Radio"},
+	{ TUNER_ABSENT,        "Panasonic ENV57H12D5"},
+	{ TUNER_ABSENT,        "TCL MFNM05-4"},
+	{ TUNER_ABSENT,        "TCL MNM05-4"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
+	{ TUNER_ABSENT,        "TCL MQNM05-4"},
+	{ TUNER_ABSENT,        "LG TAPC-W701D"},
+	{ TUNER_ABSENT,        "TCL 9886P-WM"},
+	{ TUNER_ABSENT,        "TCL 1676NM-WM"},
 };
 
-/* This list is supplied by Hauppauge. Thanks! */
-static const char *audioIC[] = {
-        /* 0-4 */
-        "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C",
-        /* 5-9 */
-        "MSP3410D", "MSP3415", "MSP3430", "MSP3438", "CS5331",
-        /* 10-14 */
-        "MSP3435", "MSP3440", "MSP3445", "MSP3411", "MSP3416",
-        /* 15-19 */
-        "MSP3425", "MSP3451", "MSP3418", "Type 0x12", "OKI7716",
-        /* 20-24 */
-        "MSP4410", "MSP4420", "MSP4440", "MSP4450", "MSP4408",
-        /* 25-29 */
-        "MSP4418", "MSP4428", "MSP4448", "MSP4458", "Type 0x1d",
-        /* 30-34 */
-        "CX880", "CX881", "CX883", "CX882", "CX25840",
-        /* 35-38 */
-        "CX25841", "CX25842", "CX25843", "CX23418",
+static struct HAUPPAUGE_AUDIOIC
+{
+	enum audiochip  id;
+	char *name;
+}
+audioIC[] =
+{
+	/* 0-4 */
+	{AUDIO_CHIP_NONE,     "None"},
+	{AUDIO_CHIP_TEA6300,  "TEA6300"},
+	{AUDIO_CHIP_TEA6300,  "TEA6320"},
+	{AUDIO_CHIP_TDA985X,  "TDA9850"},
+	{AUDIO_CHIP_MSP34XX,  "MSP3400C"},
+	/* 5-9 */
+	{AUDIO_CHIP_MSP34XX,  "MSP3410D"},
+	{AUDIO_CHIP_MSP34XX,  "MSP3415"},
+	{AUDIO_CHIP_MSP34XX,  "MSP3430"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP3438"},
+	{AUDIO_CHIP_UNKNOWN,  "CS5331"},
+	/* 10-14 */
+	{AUDIO_CHIP_MSP34XX,  "MSP3435"},
+	{AUDIO_CHIP_MSP34XX,  "MSP3440"},
+	{AUDIO_CHIP_MSP34XX,  "MSP3445"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP3411"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP3416"},
+	/* 15-19 */
+	{AUDIO_CHIP_MSP34XX,  "MSP3425"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP3451"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP3418"},
+	{AUDIO_CHIP_UNKNOWN,  "Type 0x12"},
+	{AUDIO_CHIP_UNKNOWN,  "OKI7716"},
+	/* 20-24 */
+	{AUDIO_CHIP_UNKNOWN,  "MSP4410"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP4420"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP4440"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP4450"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP4408"},
+	/* 25-29 */
+	{AUDIO_CHIP_UNKNOWN,  "MSP4418"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP4428"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP4448"},
+	{AUDIO_CHIP_UNKNOWN,  "MSP4458"},
+	{AUDIO_CHIP_UNKNOWN,  "Type 0x1d"},
+	/* 30-34 */
+	{AUDIO_CHIP_INTERNAL, "CX880"},
+	{AUDIO_CHIP_INTERNAL, "CX881"},
+	{AUDIO_CHIP_INTERNAL, "CX883"},
+	{AUDIO_CHIP_INTERNAL, "CX882"},
+	{AUDIO_CHIP_INTERNAL, "CX25840"},
+	/* 35-38 */
+	{AUDIO_CHIP_INTERNAL, "CX25841"},
+	{AUDIO_CHIP_INTERNAL, "CX25842"},
+	{AUDIO_CHIP_INTERNAL, "CX25843"},
+	{AUDIO_CHIP_INTERNAL, "CX23418"},
 };
 
 /* This list is supplied by Hauppauge. Thanks! */
 static const char *decoderIC[] = {
-        /* 0-4 */
-        "None", "BT815", "BT817", "BT819", "BT815A",
-        /* 5-9 */
-        "BT817A", "BT819A", "BT827", "BT829", "BT848",
-        /* 10-14 */
-        "BT848A", "BT849A", "BT829A", "BT827A", "BT878",
-        /* 15-19 */
-        "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
-        /* 20-24 */
-        "CX880", "CX881", "CX883", "SAA7111", "SAA7113",
-        /* 25-29 */
-        "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
-        /* 30-31 */
-        "CX25843", "CX23418",
+	/* 0-4 */
+	"None", "BT815", "BT817", "BT819", "BT815A",
+	/* 5-9 */
+	"BT817A", "BT819A", "BT827", "BT829", "BT848",
+	/* 10-14 */
+	"BT848A", "BT849A", "BT829A", "BT827A", "BT878",
+	/* 15-19 */
+	"BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
+	/* 20-24 */
+	"CX880", "CX881", "CX883", "SAA7111", "SAA7113",
+	/* 25-29 */
+	"CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
+	/* 30-31 */
+	"CX25843", "CX23418",
 };
 
 static int hasRadioTuner(int tunerType)
 {
-        switch (tunerType) {
-                case 18: //PNPEnv_TUNER_FR1236_MK2:
-                case 23: //PNPEnv_TUNER_FM1236:
-                case 38: //PNPEnv_TUNER_FMR1236:
-                case 16: //PNPEnv_TUNER_FR1216_MK2:
-                case 19: //PNPEnv_TUNER_FR1246_MK2:
-                case 21: //PNPEnv_TUNER_FM1216:
-                case 24: //PNPEnv_TUNER_FM1246:
-                case 17: //PNPEnv_TUNER_FR1216MF_MK2:
-                case 22: //PNPEnv_TUNER_FM1216MF:
-                case 20: //PNPEnv_TUNER_FR1256_MK2:
-                case 25: //PNPEnv_TUNER_FM1256:
-                case 33: //PNPEnv_TUNER_4039FR5:
-                case 42: //PNPEnv_TUNER_4009FR5:
-                case 52: //PNPEnv_TUNER_4049FM5:
-                case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
-                case 44: //PNPEnv_TUNER_4009FN5:
-                case 31: //PNPEnv_TUNER_TCPB9085P:
-                case 30: //PNPEnv_TUNER_TCPN9085D:
-                case 46: //PNPEnv_TUNER_TP18NSR01F:
-                case 47: //PNPEnv_TUNER_TP18PSB01D:
-                case 49: //PNPEnv_TUNER_TAPC_I001D:
-                case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
-                case 57: //PNPEnv_TUNER_FM1216ME_MK3:
-                case 59: //PNPEnv_TUNER_FM1216MP_MK3:
-                case 58: //PNPEnv_TUNER_FM1236_MK3:
-                case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
-                case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
-                case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
-                case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
-                case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
-                    return 1;
-        }
-        return 0;
+	switch (tunerType) {
+		case 18: //PNPEnv_TUNER_FR1236_MK2:
+		case 23: //PNPEnv_TUNER_FM1236:
+		case 38: //PNPEnv_TUNER_FMR1236:
+		case 16: //PNPEnv_TUNER_FR1216_MK2:
+		case 19: //PNPEnv_TUNER_FR1246_MK2:
+		case 21: //PNPEnv_TUNER_FM1216:
+		case 24: //PNPEnv_TUNER_FM1246:
+		case 17: //PNPEnv_TUNER_FR1216MF_MK2:
+		case 22: //PNPEnv_TUNER_FM1216MF:
+		case 20: //PNPEnv_TUNER_FR1256_MK2:
+		case 25: //PNPEnv_TUNER_FM1256:
+		case 33: //PNPEnv_TUNER_4039FR5:
+		case 42: //PNPEnv_TUNER_4009FR5:
+		case 52: //PNPEnv_TUNER_4049FM5:
+		case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
+		case 44: //PNPEnv_TUNER_4009FN5:
+		case 31: //PNPEnv_TUNER_TCPB9085P:
+		case 30: //PNPEnv_TUNER_TCPN9085D:
+		case 46: //PNPEnv_TUNER_TP18NSR01F:
+		case 47: //PNPEnv_TUNER_TP18PSB01D:
+		case 49: //PNPEnv_TUNER_TAPC_I001D:
+		case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
+		case 57: //PNPEnv_TUNER_FM1216ME_MK3:
+		case 59: //PNPEnv_TUNER_FM1216MP_MK3:
+		case 58: //PNPEnv_TUNER_FM1236_MK3:
+		case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
+		case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
+		case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
+		case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
+		case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
+		return 1;
+	}
+	return 0;
 }
 
 void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
-                                unsigned char *eeprom_data)
+				unsigned char *eeprom_data)
 {
 	/* ----------------------------------------------
 	** The hauppauge eeprom format is tagged
@@ -312,19 +355,27 @@
 	** # of inputs/outputs ???
 	*/
 
-	int i, j, len, done, beenhere, tag;
+	int i, j, len, done, beenhere, tag,start;
 
-        int tuner1 = 0, t_format1 = 0;
+	int tuner1 = 0, t_format1 = 0, audioic=-1;
 	char *t_name1 = NULL;
-        const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
+	const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
 
-        int tuner2 = 0, t_format2 = 0;
+	int tuner2 = 0, t_format2 = 0;
 	char *t_name2 = NULL;
-        const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
+	const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
 
-        memset(tvee, 0, sizeof(*tvee));
+	memset(tvee, 0, sizeof(*tvee));
 	done = len = beenhere = 0;
-	for (i = 0; !done && i < 256; i += len) {
+
+	/* Hack for processing eeprom for em28xx */
+	if ((eeprom_data[0]==0x1a)&&(eeprom_data[1]==0xeb)&&
+				(eeprom_data[2]==0x67)&&(eeprom_data[3]==0x95))
+		start=0xa0;
+	else
+		start=0;
+
+	for (i = start; !done && i < 256; i += len) {
 		if (eeprom_data[i] == 0x84) {
 			len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8);
 			i += 3;
@@ -338,28 +389,28 @@
 			++i;
 		} else {
 			tveeprom_warn("Encountered bad packet header [%02x]. "
-				   "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
+				"Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
 			return;
 		}
 
-                if (debug) {
-                        tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
-                        for(j = 1; j < len; j++) {
-                                printk(" %02x", eeprom_data[i + j]);
-                        }
-                        printk("\n");
-                }
+		if (debug) {
+			tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
+			for(j = 1; j < len; j++) {
+				printk(" %02x", eeprom_data[i + j]);
+			}
+			printk("\n");
+		}
 
 		/* process by tag */
 		tag = eeprom_data[i];
 		switch (tag) {
 		case 0x00:
-                        /* tag: 'Comprehensive' */
+			/* tag: 'Comprehensive' */
 			tuner1 = eeprom_data[i+6];
 			t_format1 = eeprom_data[i+5];
 			tvee->has_radio = eeprom_data[i+len-1];
-                        /* old style tag, don't know how to detect
-                           IR presence, mark as unknown. */
+			/* old style tag, don't know how to detect
+			IR presence, mark as unknown. */
 			tvee->has_ir = 2;
 			tvee->model =
 				eeprom_data[i+8] +
@@ -370,7 +421,7 @@
 			break;
 
 		case 0x01:
-                        /* tag: 'SerialID' */
+			/* tag: 'SerialID' */
 			tvee->serial_number =
 				eeprom_data[i+6] +
 				(eeprom_data[i+7] << 8) +
@@ -378,17 +429,21 @@
 			break;
 
 		case 0x02:
-                        /* tag 'AudioInfo'
-                           Note mask with 0x7F, high bit used on some older models
-                           to indicate 4052 mux was removed in favor of using MSP
-                           inputs directly. */
-			tvee->audio_processor = eeprom_data[i+2] & 0x7f;
+			/* tag 'AudioInfo'
+			Note mask with 0x7F, high bit used on some older models
+			to indicate 4052 mux was removed in favor of using MSP
+			inputs directly. */
+			audioic = eeprom_data[i+2] & 0x7f;
+			if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+				tvee->audio_processor = audioIC[audioic].id;
+			else
+				tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
 			break;
 
-                /* case 0x03: tag 'EEInfo' */
+		/* case 0x03: tag 'EEInfo' */
 
 		case 0x04:
-                        /* tag 'SerialID2' */
+			/* tag 'SerialID2' */
 			tvee->serial_number =
 				eeprom_data[i+5] +
 				(eeprom_data[i+6] << 8) +
@@ -396,15 +451,20 @@
 			break;
 
 		case 0x05:
-                        /* tag 'Audio2'
-                           Note mask with 0x7F, high bit used on some older models
-                           to indicate 4052 mux was removed in favor of using MSP
-                           inputs directly. */
-			tvee->audio_processor = eeprom_data[i+1] & 0x7f;
+			/* tag 'Audio2'
+			Note mask with 0x7F, high bit used on some older models
+			to indicate 4052 mux was removed in favor of using MSP
+			inputs directly. */
+			audioic = eeprom_data[i+1] & 0x7f;
+			if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+				tvee->audio_processor = audioIC[audioic].id;
+			else
+				tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
+
 			break;
 
 		case 0x06:
-                        /* tag 'ModelRev' */
+			/* tag 'ModelRev' */
 			tvee->model =
 				eeprom_data[i+1] +
 				(eeprom_data[i+2] << 8);
@@ -414,55 +474,55 @@
 			break;
 
 		case 0x07:
-                        /* tag 'Details': according to Hauppauge not interesting
-                           on any PCI-era or later boards. */
+			/* tag 'Details': according to Hauppauge not interesting
+			on any PCI-era or later boards. */
 			break;
 
-                /* there is no tag 0x08 defined */
+		/* there is no tag 0x08 defined */
 
 		case 0x09:
-                        /* tag 'Video' */
+			/* tag 'Video' */
 			tvee->decoder_processor = eeprom_data[i + 1];
 			break;
 
 		case 0x0a:
-                        /* tag 'Tuner' */
+			/* tag 'Tuner' */
 			if (beenhere == 0) {
 				tuner1 = eeprom_data[i+2];
 				t_format1 = eeprom_data[i+1];
 				beenhere = 1;
 			} else {
-                                /* a second (radio) tuner may be present */
+				/* a second (radio) tuner may be present */
 				tuner2 = eeprom_data[i+2];
 				t_format2 = eeprom_data[i+1];
-                                if (t_format2 == 0) {  /* not a TV tuner? */
-                                        tvee->has_radio = 1; /* must be radio */
-                                }
-                        }
+				if (t_format2 == 0) {  /* not a TV tuner? */
+					tvee->has_radio = 1; /* must be radio */
+				}
+			}
 			break;
 
-                case 0x0b:
-                        /* tag 'Inputs': according to Hauppauge this is specific
-                           to each driver family, so no good assumptions can be
-                           made. */
-                        break;
+		case 0x0b:
+			/* tag 'Inputs': according to Hauppauge this is specific
+			to each driver family, so no good assumptions can be
+			made. */
+			break;
 
-                /* case 0x0c: tag 'Balun' */
-                /* case 0x0d: tag 'Teletext' */
+		/* case 0x0c: tag 'Balun' */
+		/* case 0x0d: tag 'Teletext' */
 
 		case 0x0e:
-                        /* tag: 'Radio' */
+			/* tag: 'Radio' */
 			tvee->has_radio = eeprom_data[i+1];
 			break;
 
-                case 0x0f:
-                        /* tag 'IRInfo' */
-                        tvee->has_ir = eeprom_data[i+1];
-                        break;
+		case 0x0f:
+			/* tag 'IRInfo' */
+			tvee->has_ir = eeprom_data[i+1];
+			break;
 
-                /* case 0x10: tag 'VBIInfo' */
-                /* case 0x11: tag 'QCInfo' */
-                /* case 0x12: tag 'InfoBits' */
+		/* case 0x10: tag 'VBIInfo' */
+		/* case 0x11: tag 'QCInfo' */
+		/* case 0x12: tag 'InfoBits' */
 
 		default:
 			tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag);
@@ -483,11 +543,11 @@
 		tvee->rev_str[4] = 0;
 	}
 
-        if (hasRadioTuner(tuner1) && !tvee->has_radio) {
-	    tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
-	    tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
-            tvee->has_radio = 1;
-        }
+	if (hasRadioTuner(tuner1) && !tvee->has_radio) {
+		tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
+		tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
+		tvee->has_radio = 1;
+	}
 
 	if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
 		tvee->tuner_type = hauppauge_tuner[tuner1].id;
@@ -510,45 +570,53 @@
 			tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
 			t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name;
 		}
-                if (t_format2 & (1 << i)) {
-                        tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
-                        t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
-                }
+		if (t_format2 & (1 << i)) {
+			tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
+			t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
+		}
 	}
 
 	tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
-		   tvee->model, tvee->rev_str, tvee->serial_number);
+		tvee->model, tvee->rev_str, tvee->serial_number);
 	tveeprom_info("tuner model is %s (idx %d, type %d)\n",
-		   t_name1, tuner1, tvee->tuner_type);
+		t_name1, tuner1, tvee->tuner_type);
 	tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
-		   t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
-		   t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
-                   t_format1);
-        if (tuner2) {
-                tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
-                           t_name2, tuner2, tvee->tuner2_type);
-        }
-        if (t_format2) {
-                tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
-                           t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
-                           t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
-                           t_format2);
-        }
-	tveeprom_info("audio processor is %s (idx %d)\n",
-		   STRM(audioIC, tvee->audio_processor),
-		   tvee->audio_processor);
-        if (tvee->decoder_processor) {
-                tveeprom_info("decoder processor is %s (idx %d)\n",
-                           STRM(decoderIC, tvee->decoder_processor),
-                           tvee->decoder_processor);
-        }
-        if (tvee->has_ir == 2)
-                tveeprom_info("has %sradio\n",
-                                tvee->has_radio ? "" : "no ");
-        else
-                tveeprom_info("has %sradio, has %sIR remote\n",
-                                tvee->has_radio ? "" : "no ",
-                                tvee->has_ir ? "" : "no ");
+		t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
+		t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
+		t_format1);
+	if (tuner2) {
+		tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
+					t_name2, tuner2, tvee->tuner2_type);
+	}
+	if (t_format2) {
+		tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
+			t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
+			t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
+			t_format2);
+	}
+	if (audioic<0) {
+		tveeprom_info("audio processor is unknown (no idx)\n");
+		tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
+	} else {
+		if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+			tveeprom_info("audio processor is %s (idx %d)\n",
+					audioIC[audioic].name,audioic);
+		else
+			tveeprom_info("audio processor is unknown (idx %d)\n",
+								audioic);
+	}
+	if (tvee->decoder_processor) {
+		tveeprom_info("decoder processor is %s (idx %d)\n",
+			STRM(decoderIC, tvee->decoder_processor),
+			tvee->decoder_processor);
+	}
+	if (tvee->has_ir == 2)
+		tveeprom_info("has %sradio\n",
+				tvee->has_radio ? "" : "no ");
+	else
+		tveeprom_info("has %sradio, has %sIR remote\n",
+				tvee->has_radio ? "" : "no ",
+				tvee->has_ir ? "" : "no ");
 }
 EXPORT_SYMBOL(tveeprom_hauppauge_analog);
 
@@ -569,18 +637,18 @@
 		tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
 		return -1;
 	}
-        if (debug) {
-                int i;
+	if (debug) {
+		int i;
 
-                tveeprom_info("full 256-byte eeprom dump:\n");
-                for (i = 0; i < len; i++) {
-                        if (0 == (i % 16))
-                                tveeprom_info("%02x:", i);
-                        printk(" %02x", eedata[i]);
-                        if (15 == (i % 16))
-                                printk("\n");
-                }
-        }
+		tveeprom_info("full 256-byte eeprom dump:\n");
+		for (i = 0; i < len; i++) {
+			if (0 == (i % 16))
+				tveeprom_info("%02x:", i);
+			printk(" %02x", eedata[i]);
+			if (15 == (i % 16))
+				printk("\n");
+		}
+	}
 	return 0;
 }
 EXPORT_SYMBOL(tveeprom_read);
@@ -590,10 +658,6 @@
 /* run, just call the exported tveeprom_* directly, there is no point in   */
 /* using the indirect way via i2c_driver->command()                        */
 
-#ifndef I2C_DRIVERID_TVEEPROM
-# define I2C_DRIVERID_TVEEPROM I2C_DRIVERID_EXP2
-#endif
-
 static unsigned short normal_i2c[] = {
 	0xa0 >> 1,
 	I2C_CLIENT_END,
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index d86e08e..8318bd1 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -79,7 +79,7 @@
 {
 	struct video_audio va;
 	int left,right,ret,val = 0;
-        struct TVMIXER *mix = file->private_data;
+	struct TVMIXER *mix = file->private_data;
 	struct i2c_client *client = mix->dev;
 	void __user *argp = (void __user *)arg;
 	int __user *p = argp;
@@ -87,25 +87,25 @@
 	if (NULL == client)
 		return -ENODEV;
 
-        if (cmd == SOUND_MIXER_INFO) {
-                mixer_info info;
-                strlcpy(info.id, "tv card", sizeof(info.id));
-                strlcpy(info.name, client->name, sizeof(info.name));
-                info.modify_counter = 42 /* FIXME */;
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
-                return 0;
-        }
-        if (cmd == SOUND_OLD_MIXER_INFO) {
-                _old_mixer_info info;
-                strlcpy(info.id, "tv card", sizeof(info.id));
-                strlcpy(info.name, client->name, sizeof(info.name));
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
-                return 0;
-        }
-        if (cmd == OSS_GETVERSION)
-                return put_user(SOUND_VERSION, p);
+	if (cmd == SOUND_MIXER_INFO) {
+		mixer_info info;
+		strlcpy(info.id, "tv card", sizeof(info.id));
+		strlcpy(info.name, client->name, sizeof(info.name));
+		info.modify_counter = 42 /* FIXME */;
+		if (copy_to_user(argp, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == SOUND_OLD_MIXER_INFO) {
+		_old_mixer_info info;
+		strlcpy(info.id, "tv card", sizeof(info.id));
+		strlcpy(info.name, client->name, sizeof(info.name));
+		if (copy_to_user(argp, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == OSS_GETVERSION)
+		return put_user(SOUND_VERSION, p);
 
 	if (_SIOC_DIR(cmd) & _SIOC_WRITE)
 		if (get_user(val, p))
@@ -181,8 +181,8 @@
 
 static int tvmixer_open(struct inode *inode, struct file *file)
 {
-        int i, minor = iminor(inode);
-        struct TVMIXER *mix = NULL;
+	int i, minor = iminor(inode);
+	struct TVMIXER *mix = NULL;
 	struct i2c_client *client = NULL;
 
 	for (i = 0; i < DEV_MAX; i++) {
@@ -204,7 +204,7 @@
 #endif
 	if (client->adapter->owner)
 		try_module_get(client->adapter->owner);
-        return 0;
+	return 0;
 }
 
 static int tvmixer_release(struct inode *inode, struct file *file)
@@ -231,15 +231,15 @@
 	.owner           = THIS_MODULE,
 #endif
 	.name            = "tv card mixer driver",
-        .id              = I2C_DRIVERID_TVMIXER,
+	.id              = I2C_DRIVERID_TVMIXER,
 #ifdef I2C_DF_DUMMY
 	.flags           = I2C_DF_DUMMY,
 #else
 	.flags           = I2C_DF_NOTIFY,
-        .detach_adapter  = tvmixer_adapters,
+	.detach_adapter  = tvmixer_adapters,
 #endif
-        .attach_adapter  = tvmixer_adapters,
-        .detach_client   = tvmixer_clients,
+	.attach_adapter  = tvmixer_adapters,
+	.detach_client   = tvmixer_clients,
 };
 
 static struct file_operations tvmixer_fops = {
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
new file mode 100644
index 0000000..81e6d44
--- /dev/null
+++ b/drivers/media/video/tvp5150.c
@@ -0,0 +1,829 @@
+/*
+ * tvp5150 - Texas Instruments TVP5150A(M) video decoder driver
+ *
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <linux/video_decoder.h>
+
+#include "tvp5150_reg.h"
+
+MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");	/* standard i2c insmod options */
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = {
+	0xb8 >> 1,
+	0xba >> 1,
+	I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
+static int debug = 0;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (debug >= num) \
+			printk(format , ##args); \
+	} while (0)
+
+/* supported controls */
+static struct v4l2_queryctrl tvp5150_qctrl[] = {
+	{
+	 .id = V4L2_CID_BRIGHTNESS,
+	 .type = V4L2_CTRL_TYPE_INTEGER,
+	 .name = "Brightness",
+	 .minimum = 0,
+	 .maximum = 255,
+	 .step = 1,
+	 .default_value = 0,
+	 .flags = 0,
+	 }, {
+	     .id = V4L2_CID_CONTRAST,
+	     .type = V4L2_CTRL_TYPE_INTEGER,
+	     .name = "Contrast",
+	     .minimum = 0,
+	     .maximum = 255,
+	     .step = 0x1,
+	     .default_value = 0x10,
+	     .flags = 0,
+	     }, {
+		 .id = V4L2_CID_SATURATION,
+		 .type = V4L2_CTRL_TYPE_INTEGER,
+		 .name = "Saturation",
+		 .minimum = 0,
+		 .maximum = 255,
+		 .step = 0x1,
+		 .default_value = 0x10,
+		 .flags = 0,
+		 }, {
+		     .id = V4L2_CID_HUE,
+		     .type = V4L2_CTRL_TYPE_INTEGER,
+		     .name = "Hue",
+		     .minimum = -128,
+		     .maximum = 127,
+		     .step = 0x1,
+		     .default_value = 0x10,
+		     .flags = 0,
+		     }
+};
+
+struct tvp5150 {
+	struct i2c_client *client;
+
+	int norm;
+	int input;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+};
+
+static inline int tvp5150_read(struct i2c_client *c, unsigned char addr)
+{
+	unsigned char buffer[1];
+	int rc;
+
+	buffer[0] = addr;
+	if (1 != (rc = i2c_master_send(c, buffer, 1)))
+		dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+	msleep(10);
+
+	if (1 != (rc = i2c_master_recv(c, buffer, 1)))
+		dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+	return (buffer[0]);
+}
+
+static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
+				 unsigned char value)
+{
+	unsigned char buffer[2];
+	int rc;
+/*	struct tvp5150 *core = i2c_get_clientdata(c); */
+
+	buffer[0] = addr;
+	buffer[1] = value;
+	dprintk(1, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+	if (2 != (rc = i2c_master_send(c, buffer, 2)))
+		dprintk(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
+}
+
+static void dump_reg(struct i2c_client *c)
+{
+	printk("tvp5150: Video input source selection #1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
+	printk("tvp5150: Analog channel controls = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
+	printk("tvp5150: Operation mode controls = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_OP_MODE_CTL));
+	printk("tvp5150: Miscellaneous controls = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_MISC_CTL));
+	printk("tvp5150: Autoswitch mask: TVP5150A / TVP5150AM = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_AUTOSW_MSK));
+	printk("tvp5150: Color killer threshold control = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
+	printk("tvp5150: Luminance processing control #1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1));
+	printk("tvp5150: Luminance processing control #2 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2));
+	printk("tvp5150: Brightness control = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_BRIGHT_CTL));
+	printk("tvp5150: Color saturation control = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_SATURATION_CTL));
+	printk("tvp5150: Hue control = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_HUE_CTL));
+	printk("tvp5150: Contrast control = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CONTRAST_CTL));
+	printk("tvp5150: Outputs and data rates select = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_DATA_RATE_SEL));
+	printk("tvp5150: Luminance processing control #3 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
+	printk("tvp5150: Configuration shared pins = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
+	printk("tvp5150: Active video cropping start MSB = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB));
+	printk("tvp5150: Active video cropping start LSB = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
+	printk("tvp5150: Active video cropping stop MSB = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB));
+	printk("tvp5150: Active video cropping stop LSB = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
+	printk("tvp5150: Genlock/RTC = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_GENLOCK));
+	printk("tvp5150: Horizontal sync start = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
+	printk("tvp5150: Vertical blanking start = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VERT_BLANKING_START));
+	printk("tvp5150: Vertical blanking stop = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
+	printk("tvp5150: Chrominance processing control #1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1));
+	printk("tvp5150: Chrominance processing control #2 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
+	printk("tvp5150: Interrupt reset register B = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_INT_RESET_REG_B));
+	printk("tvp5150: Interrupt enable register B = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
+	printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
+	printk("tvp5150: Video standard = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VIDEO_STD));
+	printk("tvp5150: Cb gain factor = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CB_GAIN_FACT));
+	printk("tvp5150: Cr gain factor = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
+	printk("tvp5150: Macrovision on counter = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
+	printk("tvp5150: Macrovision off counter = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
+	printk("tvp5150: revision select (TVP5150AM1 only) = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_REV_SELECT));
+	printk("tvp5150: MSB of device ID = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_MSB_DEV_ID));
+	printk("tvp5150: LSB of device ID = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LSB_DEV_ID));
+	printk("tvp5150: ROM major version = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_ROM_MAJOR_VER));
+	printk("tvp5150: ROM minor version = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_ROM_MINOR_VER));
+	printk("tvp5150: Vertical line count MSB = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB));
+	printk("tvp5150: Vertical line count LSB = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
+	printk("tvp5150: Interrupt status register B = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
+	printk("tvp5150: Interrupt active register B = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
+	printk("tvp5150: Status register #1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_STATUS_REG_1));
+	printk("tvp5150: Status register #2 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_STATUS_REG_2));
+	printk("tvp5150: Status register #3 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_STATUS_REG_3));
+	printk("tvp5150: Status register #4 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_STATUS_REG_4));
+	printk("tvp5150: Status register #5 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_STATUS_REG_5));
+	printk("tvp5150: Closed caption data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CC_DATA_REG1));
+	printk("tvp5150: Closed caption data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CC_DATA_REG2));
+	printk("tvp5150: Closed caption data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CC_DATA_REG3));
+	printk("tvp5150: Closed caption data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CC_DATA_REG4));
+	printk("tvp5150: WSS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_WSS_DATA_REG1));
+	printk("tvp5150: WSS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_WSS_DATA_REG2));
+	printk("tvp5150: WSS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_WSS_DATA_REG3));
+	printk("tvp5150: WSS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_WSS_DATA_REG4));
+	printk("tvp5150: WSS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_WSS_DATA_REG5));
+	printk("tvp5150: WSS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_WSS_DATA_REG6));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG1));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG2));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG3));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG4));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG5));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG6));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG7));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG8));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG9));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG10));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG11));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG12));
+	printk("tvp5150: VPS data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VPS_DATA_REG13));
+	printk("tvp5150: VITC data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VITC_DATA_REG1));
+	printk("tvp5150: VITC data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VITC_DATA_REG2));
+	printk("tvp5150: VITC data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VITC_DATA_REG3));
+	printk("tvp5150: VITC data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VITC_DATA_REG4));
+	printk("tvp5150: VITC data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VITC_DATA_REG5));
+	printk("tvp5150: VITC data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VITC_DATA_REG6));
+	printk("tvp5150: VITC data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VITC_DATA_REG7));
+	printk("tvp5150: VITC data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VITC_DATA_REG8));
+	printk("tvp5150: VITC data registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VITC_DATA_REG9));
+	printk("tvp5150: VBI FIFO read data = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA));
+	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_1));
+	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_2));
+	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_3));
+	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_4));
+	printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_1_5));
+	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_1));
+	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_2));
+	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_3));
+	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_4));
+	printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_2_5));
+	printk("tvp5150: Teletext filter enable = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
+	printk("tvp5150: Interrupt status register A = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
+	printk("tvp5150: Interrupt enable register A = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
+	printk("tvp5150: Interrupt configuration = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_INT_CONF));
+	printk("tvp5150: VDP configuration RAM data = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VDP_CONF_RAM_DATA));
+	printk("tvp5150: Configuration RAM address low byte = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CONF_RAM_ADDR_LOW));
+	printk("tvp5150: Configuration RAM address high byte = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_CONF_RAM_ADDR_HIGH));
+	printk("tvp5150: VDP status register = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_VDP_STATUS_REG));
+	printk("tvp5150: FIFO word count = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
+	printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
+	printk("tvp5150: FIFO reset = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_FIFO_RESET));
+	printk("tvp5150: Line number interrupt = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
+	printk("tvp5150: Pixel alignment register low byte = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
+	printk("tvp5150: Pixel alignment register high byte = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH));
+	printk("tvp5150: FIFO output control = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
+	printk("tvp5150: Full field enable 1 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_FULL_FIELD_ENA_1));
+	printk("tvp5150: Full field enable 2 = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_FULL_FIELD_ENA_2));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_1));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_2));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_3));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_4));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_5));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_6));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_7));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_8));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_9));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_10));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_11));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_12));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_13));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_14));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_15));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_16));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_17));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_18));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_19));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_20));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_21));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_22));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_23));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_24));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_25));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_27));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_28));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_29));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_30));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_31));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_32));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_33));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_34));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_35));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_36));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_37));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_38));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_39));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_40));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_41));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_42));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_43));
+	printk("tvp5150: Line mode registers = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_LINE_MODE_REG_44));
+	printk("tvp5150: Full field mode register = 0x%02x\n",
+	       tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+}
+
+/****************************************************************************
+			Basic functions
+ ****************************************************************************/
+enum tvp5150_input {
+	TVP5150_ANALOG_CH0 = 0,
+	TVP5150_SVIDEO = 1,
+	TVP5150_ANALOG_CH1 = 2,
+	TVP5150_BLACK_SCREEN = 8
+};
+
+static inline void tvp5150_selmux(struct i2c_client *c,
+				  enum tvp5150_input input)
+{
+	struct tvp5150 *decoder = i2c_get_clientdata(c);
+
+	if (!decoder->enable)
+		input |= TVP5150_BLACK_SCREEN;
+
+	tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
+};
+
+static inline void tvp5150_reset(struct i2c_client *c)
+{
+	struct tvp5150 *decoder = i2c_get_clientdata(c);
+
+	tvp5150_write(c, TVP5150_CONF_SHARED_PIN, 2);
+
+	/* Automatic offset and AGC enabled */
+	tvp5150_write(c, TVP5150_ANAL_CHL_CTL, 0x15);
+
+	/* Normal Operation */
+//      tvp5150_write(c, TVP5150_OP_MODE_CTL, 0x00);
+
+	/* Activate YCrCb output 0x9 or 0xd ? */
+	tvp5150_write(c, TVP5150_MISC_CTL, 0x6f);
+
+	/* Activates video std autodetection for all standards */
+	tvp5150_write(c, TVP5150_AUTOSW_MSK, 0x0);
+
+	/* Default format: 0x47, 4:2:2: 0x40 */
+	tvp5150_write(c, TVP5150_DATA_RATE_SEL, 0x47);
+
+	tvp5150_selmux(c, decoder->input);
+
+	tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_1, 0x0c);
+	tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_2, 0x54);
+
+	tvp5150_write(c, 0x27, 0x20);	/* ?????????? */
+
+	tvp5150_write(c, TVP5150_VIDEO_STD, 0x0);	/* Auto switch */
+
+	tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8);
+	tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8);
+	tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8);
+	tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
+};
+
+static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+{
+/*	struct tvp5150 *decoder = i2c_get_clientdata(c); */
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = tvp5150_read(c, TVP5150_BRIGHT_CTL);
+		return 0;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = tvp5150_read(c, TVP5150_CONTRAST_CTL);
+		return 0;
+	case V4L2_CID_SATURATION:
+		ctrl->value = tvp5150_read(c, TVP5150_SATURATION_CTL);
+		return 0;
+	case V4L2_CID_HUE:
+		ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+{
+/*	struct tvp5150 *decoder = i2c_get_clientdata(c); */
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		tvp5150_write(c, TVP5150_BRIGHT_CTL, ctrl->value);
+		return 0;
+	case V4L2_CID_CONTRAST:
+		tvp5150_write(c, TVP5150_CONTRAST_CTL, ctrl->value);
+		return 0;
+	case V4L2_CID_SATURATION:
+		tvp5150_write(c, TVP5150_SATURATION_CTL, ctrl->value);
+		return 0;
+	case V4L2_CID_HUE:
+		tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/****************************************************************************
+			I2C Command
+ ****************************************************************************/
+static int tvp5150_command(struct i2c_client *client,
+			   unsigned int cmd, void *arg)
+{
+	struct tvp5150 *decoder = i2c_get_clientdata(client);
+
+	switch (cmd) {
+
+	case 0:
+	case DECODER_INIT:
+		tvp5150_reset(client);
+		break;
+
+	case DECODER_DUMP:
+		dump_reg(client);
+		break;
+
+	case DECODER_GET_CAPABILITIES:
+		{
+			struct video_decoder_capability *cap = arg;
+
+			cap->flags = VIDEO_DECODER_PAL |
+			    VIDEO_DECODER_NTSC |
+			    VIDEO_DECODER_SECAM |
+			    VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR;
+			cap->inputs = 3;
+			cap->outputs = 1;
+			break;
+		}
+	case DECODER_GET_STATUS:
+		{
+			break;
+		}
+
+	case DECODER_SET_GPIO:
+		break;
+
+	case DECODER_SET_VBI_BYPASS:
+		break;
+
+	case DECODER_SET_NORM:
+		{
+			int *iarg = arg;
+
+			switch (*iarg) {
+
+			case VIDEO_MODE_NTSC:
+				break;
+
+			case VIDEO_MODE_PAL:
+				break;
+
+			case VIDEO_MODE_SECAM:
+				break;
+
+			case VIDEO_MODE_AUTO:
+				break;
+
+			default:
+				return -EINVAL;
+
+			}
+			decoder->norm = *iarg;
+			break;
+		}
+	case DECODER_SET_INPUT:
+		{
+			int *iarg = arg;
+			if (*iarg < 0 || *iarg > 3) {
+				return -EINVAL;
+			}
+
+			decoder->input = *iarg;
+			tvp5150_selmux(client, decoder->input);
+
+			break;
+		}
+	case DECODER_SET_OUTPUT:
+		{
+			int *iarg = arg;
+
+			/* not much choice of outputs */
+			if (*iarg != 0) {
+				return -EINVAL;
+			}
+			break;
+		}
+	case DECODER_ENABLE_OUTPUT:
+		{
+			int *iarg = arg;
+
+			decoder->enable = (*iarg != 0);
+
+			tvp5150_selmux(client, decoder->input);
+
+			break;
+		}
+	case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			u8 i, n;
+
+			dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL");
+
+			n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+			for (i = 0; i < n; i++)
+				if (qc->id && qc->id == tvp5150_qctrl[i].id) {
+					memcpy(qc, &(tvp5150_qctrl[i]),
+					       sizeof(*qc));
+					return 0;
+				}
+
+			return -EINVAL;
+		}
+	case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl = arg;
+			dprintk(1, KERN_DEBUG "VIDIOC_G_CTRL");
+
+			return tvp5150_get_ctrl(client, ctrl);
+		}
+	case VIDIOC_S_CTRL_OLD:	/* ??? */
+	case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl = arg;
+			u8 i, n;
+			dprintk(1, KERN_DEBUG "VIDIOC_S_CTRL");
+			n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+			for (i = 0; i < n; i++)
+				if (ctrl->id == tvp5150_qctrl[i].id) {
+					if (ctrl->value <
+					    tvp5150_qctrl[i].minimum
+					    || ctrl->value >
+					    tvp5150_qctrl[i].maximum)
+						return -ERANGE;
+					dprintk(1,
+						KERN_DEBUG
+						"VIDIOC_S_CTRL: id=%d, value=%d",
+						ctrl->id, ctrl->value);
+					return tvp5150_set_ctrl(client, ctrl);
+				}
+			return -EINVAL;
+		}
+
+	case DECODER_SET_PICTURE:
+		{
+			struct video_picture *pic = arg;
+			if (decoder->bright != pic->brightness) {
+				/* We want 0 to 255 we get 0-65535 */
+				decoder->bright = pic->brightness;
+				tvp5150_write(client, TVP5150_BRIGHT_CTL,
+					      decoder->bright >> 8);
+			}
+			if (decoder->contrast != pic->contrast) {
+				/* We want 0 to 255 we get 0-65535 */
+				decoder->contrast = pic->contrast;
+				tvp5150_write(client, TVP5150_CONTRAST_CTL,
+					      decoder->contrast >> 8);
+			}
+			if (decoder->sat != pic->colour) {
+				/* We want 0 to 255 we get 0-65535 */
+				decoder->sat = pic->colour;
+				tvp5150_write(client, TVP5150_SATURATION_CTL,
+					      decoder->contrast >> 8);
+			}
+			if (decoder->hue != pic->hue) {
+				/* We want -128 to 127 we get 0-65535 */
+				decoder->hue = pic->hue;
+				tvp5150_write(client, TVP5150_HUE_CTL,
+					      (decoder->hue - 32768) >> 8);
+			}
+			break;
+		}
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+			I2C Client & Driver
+ ****************************************************************************/
+static struct i2c_driver driver;
+
+static struct i2c_client client_template = {
+	.name = "(unset)",
+	.flags = I2C_CLIENT_ALLOW_USE,
+	.driver = &driver,
+};
+
+static int tvp5150_detect_client(struct i2c_adapter *adapter,
+				 int address, int kind)
+{
+	struct i2c_client *client;
+	struct tvp5150 *core;
+	int rv;
+
+	dprintk(1,
+		KERN_INFO
+		"tvp5150.c: detecting tvp5150 client on address 0x%x\n",
+		address << 1);
+
+	client_template.adapter = adapter;
+	client_template.addr = address;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality
+	    (adapter,
+	     I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+		return 0;
+
+	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+
+	core = kmalloc(sizeof(struct tvp5150), GFP_KERNEL);
+	if (core == 0) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	memset(core, 0, sizeof(struct tvp5150));
+	i2c_set_clientdata(client, core);
+
+	rv = i2c_attach_client(client);
+
+	core->norm = VIDEO_MODE_AUTO;
+	core->input = 2;
+	core->enable = 1;
+	core->bright = 32768;
+	core->contrast = 32768;
+	core->hue = 32768;
+	core->sat = 32768;
+
+	if (rv) {
+		kfree(client);
+		kfree(core);
+		return rv;
+	}
+
+	if (debug > 1)
+		dump_reg(client);
+
+	return 0;
+}
+
+static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
+{
+	dprintk(1,
+		KERN_INFO
+		"tvp5150.c: starting probe for adapter %s (0x%x)\n",
+		adapter->name, adapter->id);
+	return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
+}
+
+static int tvp5150_detach_client(struct i2c_client *client)
+{
+	struct tvp5150 *decoder = i2c_get_clientdata(client);
+	int err;
+
+	err = i2c_detach_client(client);
+	if (err) {
+		return err;
+	}
+
+	kfree(decoder);
+	kfree(client);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+	.owner = THIS_MODULE,
+	.name = "tvp5150",
+
+	/* FIXME */
+	.id = I2C_DRIVERID_SAA7110,
+	.flags = I2C_DF_NOTIFY,
+
+	.attach_adapter = tvp5150_attach_adapter,
+	.detach_client = tvp5150_detach_client,
+
+	.command = tvp5150_command,
+};
+
+static int __init tvp5150_init(void)
+{
+	return i2c_add_driver(&driver);
+}
+
+static void __exit tvp5150_exit(void)
+{
+	i2c_del_driver(&driver);
+}
+
+module_init(tvp5150_init);
+module_exit(tvp5150_exit);
diff --git a/drivers/media/video/tvp5150_reg.h b/drivers/media/video/tvp5150_reg.h
new file mode 100644
index 0000000..cd45c1d
--- /dev/null
+++ b/drivers/media/video/tvp5150_reg.h
@@ -0,0 +1,173 @@
+#define TVP5150_VD_IN_SRC_SEL_1      0x00 /* Video input source selection #1 */
+#define TVP5150_ANAL_CHL_CTL         0x01 /* Analog channel controls */
+#define TVP5150_OP_MODE_CTL          0x02 /* Operation mode controls */
+#define TVP5150_MISC_CTL             0x03 /* Miscellaneous controls */
+#define TVP5150_AUTOSW_MSK           0x04 /* Autoswitch mask: TVP5150A / TVP5150AM */
+
+/* Reserved 05h */
+
+#define TVP5150_COLOR_KIL_THSH_CTL   0x06 /* Color killer threshold control */
+#define TVP5150_LUMA_PROC_CTL_1      0x07 /* Luminance processing control #1 */
+#define TVP5150_LUMA_PROC_CTL_2      0x08 /* Luminance processing control #2 */
+#define TVP5150_BRIGHT_CTL           0x09 /* Brightness control */
+#define TVP5150_SATURATION_CTL       0x0a /* Color saturation control */
+#define TVP5150_HUE_CTL              0x0b /* Hue control */
+#define TVP5150_CONTRAST_CTL         0x0c /* Contrast control */
+#define TVP5150_DATA_RATE_SEL        0x0d /* Outputs and data rates select */
+#define TVP5150_LUMA_PROC_CTL_3      0x0e /* Luminance processing control #3 */
+#define TVP5150_CONF_SHARED_PIN      0x0f /* Configuration shared pins */
+
+/* Reserved 10h */
+
+#define TVP5150_ACT_VD_CROP_ST_MSB   0x11 /* Active video cropping start MSB */
+#define TVP5150_ACT_VD_CROP_ST_LSB   0x12 /* Active video cropping start LSB */
+#define TVP5150_ACT_VD_CROP_STP_MSB  0x13 /* Active video cropping stop MSB */
+#define TVP5150_ACT_VD_CROP_STP_LSB  0x14 /* Active video cropping stop LSB */
+#define TVP5150_GENLOCK              0x15 /* Genlock/RTC */
+#define TVP5150_HORIZ_SYNC_START     0x16 /* Horizontal sync start */
+
+/* Reserved 17h */
+
+#define TVP5150_VERT_BLANKING_START 0x18 /* Vertical blanking start */
+#define TVP5150_VERT_BLANKING_STOP  0x19 /* Vertical blanking stop */
+#define TVP5150_CHROMA_PROC_CTL_1   0x1a /* Chrominance processing control #1 */
+#define TVP5150_CHROMA_PROC_CTL_2   0x1b /* Chrominance processing control #2 */
+#define TVP5150_INT_RESET_REG_B     0x1c /* Interrupt reset register B */
+#define TVP5150_INT_ENABLE_REG_B    0x1d /* Interrupt enable register B */
+#define TVP5150_INTT_CONFIG_REG_B   0x1e /* Interrupt configuration register B */
+
+/* Reserved 1Fh-27h */
+
+#define TVP5150_VIDEO_STD           0x28 /* Video standard */
+
+/* Reserved 29h-2bh */
+
+#define TVP5150_CB_GAIN_FACT        0x2c /* Cb gain factor */
+#define TVP5150_CR_GAIN_FACTOR      0x2d /* Cr gain factor */
+#define TVP5150_MACROVISION_ON_CTR  0x2e /* Macrovision on counter */
+#define TVP5150_MACROVISION_OFF_CTR 0x2f /* Macrovision off counter */
+#define TVP5150_REV_SELECT          0x30 /* revision select (TVP5150AM1 only) */
+
+/* Reserved	31h-7Fh */
+
+#define TVP5150_MSB_DEV_ID          0x80 /* MSB of device ID */
+#define TVP5150_LSB_DEV_ID          0x81 /* LSB of device ID */
+#define TVP5150_ROM_MAJOR_VER       0x82 /* ROM major version */
+#define TVP5150_ROM_MINOR_VER       0x83 /* ROM minor version */
+#define TVP5150_VERT_LN_COUNT_MSB   0x84 /* Vertical line count MSB */
+#define TVP5150_VERT_LN_COUNT_LSB   0x85 /* Vertical line count LSB */
+#define TVP5150_INT_STATUS_REG_B    0x86 /* Interrupt status register B */
+#define TVP5150_INT_ACTIVE_REG_B    0x87 /* Interrupt active register B */
+#define TVP5150_STATUS_REG_1        0x88 /* Status register #1 */
+#define TVP5150_STATUS_REG_2        0x89 /* Status register #2 */
+#define TVP5150_STATUS_REG_3        0x8a /* Status register #3 */
+#define TVP5150_STATUS_REG_4        0x8b /* Status register #4 */
+#define TVP5150_STATUS_REG_5        0x8c /* Status register #5 */
+/* Reserved	8Dh-8Fh */
+#define TVP5150_CC_DATA_REG1        0x90 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG2        0x91 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG3        0x92 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG4        0x93 /* Closed caption data registers */
+#define TVP5150_WSS_DATA_REG1       0X94 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG2       0X95 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG3       0X96 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG4       0X97 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG5       0X98 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG6       0X99 /* WSS data registers */
+#define TVP5150_VPS_DATA_REG1       0x9a /* VPS data registers */
+#define TVP5150_VPS_DATA_REG2       0x9b /* VPS data registers */
+#define TVP5150_VPS_DATA_REG3       0x9c /* VPS data registers */
+#define TVP5150_VPS_DATA_REG4       0x9d /* VPS data registers */
+#define TVP5150_VPS_DATA_REG5       0x9e /* VPS data registers */
+#define TVP5150_VPS_DATA_REG6       0x9f /* VPS data registers */
+#define TVP5150_VPS_DATA_REG7       0xa0 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG8       0xa1 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG9       0xa2 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG10      0xa3 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG11      0xa4 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG12      0xa5 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG13      0xa6 /* VPS data registers */
+#define TVP5150_VITC_DATA_REG1      0xa7 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG2      0xa8 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG3      0xa9 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG4      0xaa /* VITC data registers */
+#define TVP5150_VITC_DATA_REG5      0xab /* VITC data registers */
+#define TVP5150_VITC_DATA_REG6      0xac /* VITC data registers */
+#define TVP5150_VITC_DATA_REG7      0xad /* VITC data registers */
+#define TVP5150_VITC_DATA_REG8      0xae /* VITC data registers */
+#define TVP5150_VITC_DATA_REG9      0xaf /* VITC data registers */
+#define TVP5150_VBI_FIFO_READ_DATA  0xb0 /* VBI FIFO read data */
+#define TVP5150_TELETEXT_FIL_1_1    0xb1 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_2    0xb2 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_3    0xb3 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_4    0xb4 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_5    0xb5 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_2_1    0xb6 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_2    0xb7 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_3    0xb8 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_4    0xb9 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_5    0xba /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_ENA    0xbb /* Teletext filter enable */
+/* Reserved	BCh-BFh */
+#define TVP5150_INT_STATUS_REG_A    0xc0 /* Interrupt status register A */
+#define TVP5150_INT_ENABLE_REG_A    0xc1 /* Interrupt enable register A */
+#define TVP5150_INT_CONF            0xc2 /* Interrupt configuration */
+#define TVP5150_VDP_CONF_RAM_DATA   0xc3 /* VDP configuration RAM data */
+#define TVP5150_CONF_RAM_ADDR_LOW   0xc4 /* Configuration RAM address low byte */
+#define TVP5150_CONF_RAM_ADDR_HIGH  0xc5 /* Configuration RAM address high byte */
+#define TVP5150_VDP_STATUS_REG      0xc6 /* VDP status register */
+#define TVP5150_FIFO_WORD_COUNT     0xc7 /* FIFO word count */
+#define TVP5150_FIFO_INT_THRESHOLD  0xc8 /* FIFO interrupt threshold */
+#define TVP5150_FIFO_RESET          0xc9 /* FIFO reset */
+#define TVP5150_LINE_NUMBER_INT     0xca /* Line number interrupt */
+#define TVP5150_PIX_ALIGN_REG_LOW   0xcb /* Pixel alignment register low byte */
+#define TVP5150_PIX_ALIGN_REG_HIGH  0xcc /* Pixel alignment register high byte */
+#define TVP5150_FIFO_OUT_CTRL       0xcd /* FIFO output control */
+/* Reserved	CEh */
+#define TVP5150_FULL_FIELD_ENA_1    0xcf /* Full field enable 1 */
+#define TVP5150_FULL_FIELD_ENA_2    0xd0 /* Full field enable 2 */
+#define TVP5150_LINE_MODE_REG_1     0xd1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_2     0xd2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_3     0xd3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_4     0xd4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_5     0xd5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_6     0xd6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_7     0xd7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_8     0xd8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_9     0xd9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_10    0xda /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_11    0xdb /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_12    0xdc /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_13    0xdd /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_14    0xde /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_15    0xdf /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_16    0xe0 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_17    0xe1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_18    0xe2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_19    0xe3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_20    0xe4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_21    0xe5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_22    0xe6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_23    0xe7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_24    0xe8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_25    0xe9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_27    0xea /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_28    0xeb /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_29    0xec /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_30    0xed /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_31    0xee /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_32    0xef /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_33    0xf0 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_34    0xf1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_35    0xf2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_36    0xf3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_37    0xf4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_38    0xf5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_39    0xf6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_40    0xf7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_41    0xf8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_42    0xf9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_43    0xfa /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_44    0xfb /* Line mode registers */
+#define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */
+/* Reserved	FDh-FFh */
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index d679ca2..4134549 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -708,7 +708,7 @@
 	}
 	case VIDIOCGFREQ: /*  get frequency  */
 	{
-		int *freq = arg;
+		unsigned long *freq = arg;
 
 		freq2.tuner = 0;
 		err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -720,7 +720,7 @@
 	}
 	case VIDIOCSFREQ: /*  set frequency  */
 	{
-		int *freq = arg;
+		unsigned long *freq = arg;
 
 		freq2.tuner = 0;
 		drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -960,7 +960,7 @@
 		fmt->start[1]         = fmt2->fmt.vbi.start[1];
 		fmt->count[1]         = fmt2->fmt.vbi.count[1];
 		fmt->flags            = fmt2->fmt.vbi.flags & 0x03;
-                break;
+		break;
 	}
 	case VIDIOCSVBIFMT:
 	{
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index 574b8e3..acfd3a1 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -147,7 +147,7 @@
 		data,size,dma->nr_pages);
 
 	down_read(&current->mm->mmap_sem);
-        err = get_user_pages(current,current->mm,
+	err = get_user_pages(current,current->mm,
 			     data & PAGE_MASK, dma->nr_pages,
 			     rw == READ, 1, /* force */
 			     dma->pages, NULL);
@@ -750,9 +750,9 @@
 {
 	enum v4l2_field field;
 	unsigned long flags;
-        int retval;
+	int retval;
 
-        /* setup stuff */
+	/* setup stuff */
 	retval = -ENOMEM;
 	q->read_buf = videobuf_alloc(q->msize);
 	if (NULL == q->read_buf)
@@ -760,18 +760,18 @@
 
 	q->read_buf->memory = V4L2_MEMORY_USERPTR;
 	q->read_buf->baddr  = (unsigned long)data;
-        q->read_buf->bsize  = count;
+	q->read_buf->bsize  = count;
 	field = videobuf_next_field(q);
 	retval = q->ops->buf_prepare(q,q->read_buf,field);
 	if (0 != retval)
 		goto done;
 
-        /* start capture & wait */
+	/* start capture & wait */
 	spin_lock_irqsave(q->irqlock,flags);
 	q->ops->buf_queue(q,q->read_buf);
 	spin_unlock_irqrestore(q->irqlock,flags);
-        retval = videobuf_waiton(q->read_buf,0,0);
-        if (0 == retval) {
+	retval = videobuf_waiton(q->read_buf,0,0);
+	if (0 == retval) {
 		videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
 		if (STATE_ERROR == q->read_buf->state)
 			retval = -EIO;
@@ -828,7 +828,7 @@
 	}
 
 	/* wait until capture is done */
-        retval = videobuf_waiton(q->read_buf, nonblocking, 1);
+	retval = videobuf_waiton(q->read_buf, nonblocking, 1);
 	if (0 != retval)
 		goto done;
 	videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
@@ -1096,7 +1096,7 @@
 
 	dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
 		vaddr,vma->vm_start,vma->vm_end);
-        if (vaddr > vma->vm_end)
+	if (vaddr > vma->vm_end)
 		return NOPAGE_SIGBUS;
 	page = alloc_page(GFP_USER);
 	if (!page)
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
new file mode 100644
index 0000000..22f2862
--- /dev/null
+++ b/drivers/media/video/wm8775.c
@@ -0,0 +1,254 @@
+/*
+ * wm8775 - driver version 0.0.1
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ *
+ * Based on saa7115 driver
+ *
+ * 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.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/audiochip.h>
+
+MODULE_DESCRIPTION("wm8775 driver");
+MODULE_AUTHOR("Ulf Eklund");
+MODULE_LICENSE("GPL");
+
+#define wm8775_err(fmt, arg...) do { \
+	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define wm8775_info(fmt, arg...) do { \
+	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+
+static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+enum {
+	R7 = 7, R11 = 11,
+	R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
+	TOT_REGS
+};
+
+struct wm8775_state {
+	u8 input;		/* Last selected input (0-0xf) */
+	u8 muted;
+};
+
+static int wm8775_write(struct i2c_client *client, int reg, u16 val)
+{
+	int i;
+
+	if (reg < 0 || reg >= TOT_REGS) {
+		wm8775_err("Invalid register R%d\n", reg);
+		return -1;
+	}
+
+	for (i = 0; i < 3; i++) {
+		if (i2c_smbus_write_byte_data(client, (reg << 1) |
+					(val >> 8), val & 0xff) == 0) {
+			return 0;
+		}
+	}
+	wm8775_err("I2C: cannot write %03x to register R%d\n", val, reg);
+	return -1;
+}
+
+static int wm8775_command(struct i2c_client *client, unsigned int cmd,
+			  void *arg)
+{
+	struct wm8775_state *state = i2c_get_clientdata(client);
+	int *input = arg;
+
+	switch (cmd) {
+	case AUDC_SET_INPUT:
+		wm8775_write(client, R21, 0x0c0);
+		wm8775_write(client, R14, 0x1d4);
+		wm8775_write(client, R15, 0x1d4);
+
+		if (*input == AUDIO_RADIO) {
+			wm8775_write(client, R21, 0x108);
+			state->input = 8;
+			state->muted = 0;
+			break;
+		}
+		if (*input == AUDIO_MUTE) {
+			state->muted = 1;
+			break;
+		}
+		if (*input == AUDIO_UNMUTE) {
+			wm8775_write(client, R21, 0x100 + state->input);
+			state->muted = 0;
+			break;
+		}
+		/* All other inputs... */
+		wm8775_write(client, R21, 0x102);
+		state->input = 2;
+		state->muted = 0;
+		break;
+
+	case VIDIOC_LOG_STATUS:
+		wm8775_info("Input: %s%s\n",
+			    state->input == 8 ? "radio" : "default",
+			    state->muted ? " (muted)" : "");
+		break;
+
+	case VIDIOC_S_FREQUENCY:
+		/* If I remove this, then it can happen that I have no
+		   sound the first time I tune from static to a valid channel.
+		   It's difficult to reproduce and is almost certainly related
+		   to the zero cross detect circuit. */
+		wm8775_write(client, R21, 0x0c0);
+		wm8775_write(client, R14, 0x1d4);
+		wm8775_write(client, R15, 0x1d4);
+		wm8775_write(client, R21, 0x100 + state->input);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct wm8775_state *state;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return 0;
+
+	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+
+	memset(client, 0, sizeof(struct i2c_client));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver;
+	client->flags = I2C_CLIENT_ALLOW_USE;
+	snprintf(client->name, sizeof(client->name) - 1, "wm8775");
+
+	wm8775_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+	state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
+	if (state == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	state->input = 2;
+	state->muted = 0;
+	i2c_set_clientdata(client, state);
+
+	/* initialize wm8775 */
+	wm8775_write(client, R23, 0x000);	/* RESET */
+	wm8775_write(client, R7, 0x000);	/* Disable zero cross detect timeout */
+	wm8775_write(client, R11, 0x021);	/* Left justified, 24-bit mode */
+	wm8775_write(client, R12, 0x102);	/* Master mode, clock ratio 256fs */
+	wm8775_write(client, R13, 0x000);	/* Powered up */
+	wm8775_write(client, R14, 0x1d4);	/* ADC gain +2.5dB, enable zero cross */
+	wm8775_write(client, R15, 0x1d4);	/* ADC gain +2.5dB, enable zero cross */
+	wm8775_write(client, R16, 0x1bf);	/* ALC Stereo, ALC target level -1dB FS */
+	/* max gain +8dB */
+	wm8775_write(client, R17, 0x185);	/* Enable gain control, use zero cross */
+	/* detection, ALC hold time 42.6 ms */
+	wm8775_write(client, R18, 0x0a2);	/* ALC gain ramp up delay 34 s, */
+	/* ALC gain ramp down delay 33 ms */
+	wm8775_write(client, R19, 0x005);	/* Enable noise gate, threshold -72dBfs */
+	wm8775_write(client, R20, 0x07a);	/* Transient window 4ms, lower PGA gain */
+	/* limit -1dB */
+	wm8775_write(client, R21, 0x102);	/* LRBOTH = 1, use input 2. */
+	i2c_attach_client(client);
+
+	return 0;
+}
+
+static int wm8775_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+	if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+	if (adapter->id == I2C_HW_B_BT848)
+#endif
+		return i2c_probe(adapter, &addr_data, wm8775_attach);
+	return 0;
+}
+
+static int wm8775_detach(struct i2c_client *client)
+{
+	int err;
+
+	err = i2c_detach_client(client);
+	if (err) {
+		return err;
+	}
+	kfree(client);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+	.name = "wm8775",
+
+	.id = I2C_DRIVERID_WM8775,
+	.flags = I2C_DF_NOTIFY,
+
+	.attach_adapter = wm8775_probe,
+	.detach_client = wm8775_detach,
+	.command = wm8775_command,
+	.owner = THIS_MODULE,
+};
+
+
+static int __init wm8775_init_module(void)
+{
+	return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit wm8775_cleanup_module(void)
+{
+	i2c_del_driver(&i2c_driver);
+}
+
+module_init(wm8775_init_module);
+module_exit(wm8775_cleanup_module);
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
index d4740a8..4ed8985 100644
--- a/drivers/media/video/zr36016.c
+++ b/drivers/media/video/zr36016.c
@@ -26,7 +26,6 @@
 
 #define ZR016_VERSION "v0.7"
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
index 13b1e7b..0144576 100644
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -26,7 +26,6 @@
 
 #define ZR050_VERSION "v0.7.1"
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
index b50dc40..129744a 100644
--- a/drivers/media/video/zr36060.c
+++ b/drivers/media/video/zr36060.c
@@ -26,7 +26,6 @@
 
 #define ZR060_VERSION "v0.7"
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 790a293..7402231 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -47,7 +47,6 @@
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -92,9 +91,9 @@
  *  Public data...
  */
 int mpt_lan_index = -1;
-int mpt_stm_index = -1;
+static int mpt_stm_index = -1;
 
-struct proc_dir_entry *mpt_proc_root_dir;
+static struct proc_dir_entry *mpt_proc_root_dir;
 
 #define WHOINIT_UNKNOWN		0xAA
 
@@ -6272,7 +6271,6 @@
 EXPORT_SYMBOL(mpt_suspend);
 #endif
 EXPORT_SYMBOL(ioc_list);
-EXPORT_SYMBOL(mpt_proc_root_dir);
 EXPORT_SYMBOL(mpt_register);
 EXPORT_SYMBOL(mpt_deregister);
 EXPORT_SYMBOL(mpt_event_register);
@@ -6290,7 +6288,6 @@
 EXPORT_SYMBOL(mpt_GetIocState);
 EXPORT_SYMBOL(mpt_print_ioc_summary);
 EXPORT_SYMBOL(mpt_lan_index);
-EXPORT_SYMBOL(mpt_stm_index);
 EXPORT_SYMBOL(mpt_HardResetHandler);
 EXPORT_SYMBOL(mpt_config);
 EXPORT_SYMBOL(mpt_toolbox);
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index e7efeb7..8ad277a 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -49,7 +49,6 @@
 #define MPTBASE_H_INCLUDED
 /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -1007,10 +1006,8 @@
  *  Public data decl's...
  */
 extern struct list_head	  ioc_list;
-extern struct proc_dir_entry	*mpt_proc_root_dir;
 
 extern int		  mpt_lan_index;	/* needed by mptlan.c */
-extern int		  mpt_stm_index;	/* needed by mptstm.c */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif		/* } __KERNEL__ */
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index cb2d59d..602138f 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -45,7 +45,6 @@
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index 28754a9..518996e 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -49,7 +49,6 @@
 #define MPTCTL_H_INCLUDED
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include "linux/version.h"
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
index 750e343..3726ecb 100644
--- a/drivers/message/fusion/mptlan.h
+++ b/drivers/message/fusion/mptlan.h
@@ -66,7 +66,6 @@
 #include <linux/slab.h>
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
-#include <linux/version.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 // #include <linux/trdevice.h>
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 7daa0ed..1eab7cf 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -138,9 +138,8 @@
 	.disable		= mcp_sa11x0_disable,
 };
 
-static int mcp_sa11x0_probe(struct device *dev)
+static int mcp_sa11x0_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct mcp_plat_data *data = pdev->dev.platform_data;
 	struct mcp *mcp;
 	int ret;
@@ -165,7 +164,7 @@
 	mcp->dma_telco_rd	= DMA_Ser4MCP1Rd;
 	mcp->dma_telco_wr	= DMA_Ser4MCP1Wr;
 
-	dev_set_drvdata(dev, mcp);
+	platform_set_drvdata(pdev, mcp);
 
 	if (machine_is_assabet()) {
 		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
@@ -202,26 +201,26 @@
 
  release:
 	release_mem_region(0x80060000, 0x60);
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
  out:
 	return ret;
 }
 
-static int mcp_sa11x0_remove(struct device *dev)
+static int mcp_sa11x0_remove(struct platform_device *dev)
 {
-	struct mcp *mcp = dev_get_drvdata(dev);
+	struct mcp *mcp = platform_get_drvdata(dev);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(dev, NULL);
 	mcp_host_unregister(mcp);
 	release_mem_region(0x80060000, 0x60);
 
 	return 0;
 }
 
-static int mcp_sa11x0_suspend(struct device *dev, pm_message_t state)
+static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct mcp *mcp = dev_get_drvdata(dev);
+	struct mcp *mcp = platform_get_drvdata(dev);
 
 	priv(mcp)->mccr0 = Ser4MCCR0;
 	priv(mcp)->mccr1 = Ser4MCCR1;
@@ -230,9 +229,9 @@
 	return 0;
 }
 
-static int mcp_sa11x0_resume(struct device *dev)
+static int mcp_sa11x0_resume(struct platform_device *dev)
 {
-	struct mcp *mcp = dev_get_drvdata(dev);
+	struct mcp *mcp = platform_get_drvdata(dev);
 
 	Ser4MCCR1 = priv(mcp)->mccr1;
 	Ser4MCCR0 = priv(mcp)->mccr0;
@@ -243,13 +242,14 @@
 /*
  * The driver for the SA11x0 MCP port.
  */
-static struct device_driver mcp_sa11x0_driver = {
-	.name		= "sa11x0-mcp",
-	.bus		= &platform_bus_type,
+static struct platform_driver mcp_sa11x0_driver = {
 	.probe		= mcp_sa11x0_probe,
 	.remove		= mcp_sa11x0_remove,
 	.suspend	= mcp_sa11x0_suspend,
 	.resume		= mcp_sa11x0_resume,
+	.driver		= {
+		.name	= "sa11x0-mcp",
+	},
 };
 
 /*
@@ -257,12 +257,12 @@
  */
 static int __init mcp_sa11x0_init(void)
 {
-	return driver_register(&mcp_sa11x0_driver);
+	return platform_driver_register(&mcp_sa11x0_driver);
 }
 
 static void __exit mcp_sa11x0_exit(void)
 {
-	driver_unregister(&mcp_sa11x0_driver);
+	platform_driver_unregister(&mcp_sa11x0_driver);
 }
 
 module_init(mcp_sa11x0_init);
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index 9c4dd68..11a801b 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -14,7 +14,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
@@ -27,8 +26,8 @@
 
 #define SKY_CPUSTATE_VERSION		"1.1"
 
-static int hdpu_cpustate_probe(struct device *ddev);
-static int hdpu_cpustate_remove(struct device *ddev);
+static int hdpu_cpustate_probe(struct platform_device *pdev);
+static int hdpu_cpustate_remove(struct platform_device *pdev);
 
 struct cpustate_t cpustate;
 
@@ -159,11 +158,12 @@
 	return len;
 }
 
-static struct device_driver hdpu_cpustate_driver = {
-	.name = HDPU_CPUSTATE_NAME,
-	.bus = &platform_bus_type,
+static struct platform_driver hdpu_cpustate_driver = {
 	.probe = hdpu_cpustate_probe,
 	.remove = hdpu_cpustate_remove,
+	.driver = {
+		.name = HDPU_CPUSTATE_NAME,
+	},
 };
 
 /*
@@ -188,9 +188,8 @@
 	&cpustate_fops
 };
 
-static int hdpu_cpustate_probe(struct device *ddev)
+static int hdpu_cpustate_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(ddev);
 	struct resource *res;
 	struct proc_dir_entry *proc_de;
 	int ret;
@@ -218,7 +217,7 @@
 	return 0;
 }
 
-static int hdpu_cpustate_remove(struct device *ddev)
+static int hdpu_cpustate_remove(struct platform_device *pdev)
 {
 
 	cpustate.set_addr = NULL;
@@ -233,13 +232,13 @@
 static int __init cpustate_init(void)
 {
 	int rc;
-	rc = driver_register(&hdpu_cpustate_driver);
+	rc = platform_driver_register(&hdpu_cpustate_driver);
 	return rc;
 }
 
 static void __exit cpustate_exit(void)
 {
-	driver_unregister(&hdpu_cpustate_driver);
+	platform_driver_unregister(&hdpu_cpustate_driver);
 }
 
 module_init(cpustate_init);
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 165f340..ea9d5f23 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -14,7 +14,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
@@ -23,19 +22,20 @@
 
 #include <linux/platform_device.h>
 
-static int hdpu_nexus_probe(struct device *ddev);
-static int hdpu_nexus_remove(struct device *ddev);
+static int hdpu_nexus_probe(struct platform_device *pdev);
+static int hdpu_nexus_remove(struct platform_device *pdev);
 
 static struct proc_dir_entry *hdpu_slot_id;
 static struct proc_dir_entry *hdpu_chassis_id;
 static int slot_id = -1;
 static int chassis_id = -1;
 
-static struct device_driver hdpu_nexus_driver = {
-	.name = HDPU_NEXUS_NAME,
-	.bus = &platform_bus_type,
+static struct platform_driver hdpu_nexus_driver = {
 	.probe = hdpu_nexus_probe,
 	.remove = hdpu_nexus_remove,
+	.driver = {
+		.name = HDPU_NEXUS_NAME,
+	},
 };
 
 int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset,
@@ -56,9 +56,8 @@
 	return sprintf(buffer, "%d\n", chassis_id);
 }
 
-static int hdpu_nexus_probe(struct device *ddev)
+static int hdpu_nexus_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(ddev);
 	struct resource *res;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -81,7 +80,7 @@
 	return 0;
 }
 
-static int hdpu_nexus_remove(struct device *ddev)
+static int hdpu_nexus_remove(struct platform_device *pdev)
 {
 	slot_id = -1;
 	chassis_id = -1;
@@ -95,13 +94,13 @@
 static int __init nexus_init(void)
 {
 	int rc;
-	rc = driver_register(&hdpu_nexus_driver);
+	rc = platform_driver_register(&hdpu_nexus_driver);
 	return rc;
 }
 
 static void __exit nexus_exit(void)
 {
-	driver_unregister(&hdpu_nexus_driver);
+	platform_driver_unregister(&hdpu_nexus_driver);
 }
 
 module_init(nexus_init);
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index ecce4ff..d7e20a3 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -31,7 +31,6 @@
 #include <linux/slab.h>
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/input.h>
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index f31e247..ee8f8a0 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -428,9 +428,8 @@
 	return IRQ_HANDLED;
 }
 
-static int pxamci_probe(struct device *dev)
+static int pxamci_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct mmc_host *mmc;
 	struct pxamci_host *host = NULL;
 	struct resource *r;
@@ -445,7 +444,7 @@
 	if (!r)
 		return -EBUSY;
 
-	mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev);
+	mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
 	if (!mmc) {
 		ret = -ENOMEM;
 		goto out;
@@ -474,7 +473,7 @@
 			 host->pdata->ocr_mask :
 			 MMC_VDD_32_33|MMC_VDD_33_34;
 
-	host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
+	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
 	if (!host->sg_cpu) {
 		ret = -ENOMEM;
 		goto out;
@@ -511,10 +510,10 @@
 	if (ret)
 		goto out;
 
-	dev_set_drvdata(dev, mmc);
+	platform_set_drvdata(pdev, mmc);
 
 	if (host->pdata && host->pdata->init)
-		host->pdata->init(dev, pxamci_detect_irq, mmc);
+		host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
 
 	mmc_add_host(mmc);
 
@@ -527,7 +526,7 @@
 		if (host->base)
 			iounmap(host->base);
 		if (host->sg_cpu)
-			dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+			dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 	}
 	if (mmc)
 		mmc_free_host(mmc);
@@ -535,17 +534,17 @@
 	return ret;
 }
 
-static int pxamci_remove(struct device *dev)
+static int pxamci_remove(struct platform_device *pdev)
 {
-	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct mmc_host *mmc = platform_get_drvdata(pdev);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	if (mmc) {
 		struct pxamci_host *host = mmc_priv(mmc);
 
 		if (host->pdata && host->pdata->exit)
-			host->pdata->exit(dev, mmc);
+			host->pdata->exit(&pdev->dev, mmc);
 
 		mmc_remove_host(mmc);
 
@@ -560,7 +559,7 @@
 		free_irq(host->irq, host);
 		pxa_free_dma(host->dma);
 		iounmap(host->base);
-		dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+		dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
 		release_resource(host->res);
 
@@ -570,9 +569,9 @@
 }
 
 #ifdef CONFIG_PM
-static int pxamci_suspend(struct device *dev, pm_message_t state)
+static int pxamci_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct mmc_host *mmc = platform_get_drvdata(dev);
 	int ret = 0;
 
 	if (mmc)
@@ -581,9 +580,9 @@
 	return ret;
 }
 
-static int pxamci_resume(struct device *dev)
+static int pxamci_resume(struct platform_device *dev)
 {
-	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct mmc_host *mmc = platform_get_drvdata(dev);
 	int ret = 0;
 
 	if (mmc)
@@ -596,23 +595,24 @@
 #define pxamci_resume	NULL
 #endif
 
-static struct device_driver pxamci_driver = {
-	.name		= DRIVER_NAME,
-	.bus		= &platform_bus_type,
+static struct platform_driver pxamci_driver = {
 	.probe		= pxamci_probe,
 	.remove		= pxamci_remove,
 	.suspend	= pxamci_suspend,
 	.resume		= pxamci_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
 };
 
 static int __init pxamci_init(void)
 {
-	return driver_register(&pxamci_driver);
+	return platform_driver_register(&pxamci_driver);
 }
 
 static void __exit pxamci_exit(void)
 {
-	driver_unregister(&pxamci_driver);
+	platform_driver_unregister(&pxamci_driver);
 }
 
 module_init(pxamci_init);
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index e954b83..c7eb7c2 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -42,7 +42,7 @@
 #include "wbsd.h"
 
 #define DRIVER_NAME "wbsd"
-#define DRIVER_VERSION "1.4"
+#define DRIVER_VERSION "1.5"
 
 #ifdef CONFIG_MMC_DEBUG
 #define DBG(x...) \
@@ -1932,14 +1932,14 @@
  * Non-PnP
  */
 
-static int __devinit wbsd_probe(struct device* dev)
+static int __devinit wbsd_probe(struct platform_device* dev)
 {
-	return wbsd_init(dev, io, irq, dma, 0);
+	return wbsd_init(&dev->dev, io, irq, dma, 0);
 }
 
-static int __devexit wbsd_remove(struct device* dev)
+static int __devexit wbsd_remove(struct platform_device* dev)
 {
-	wbsd_shutdown(dev, 0);
+	wbsd_shutdown(&dev->dev, 0);
 
 	return 0;
 }
@@ -1983,9 +1983,9 @@
 
 #ifdef CONFIG_PM
 
-static int wbsd_suspend(struct device *dev, pm_message_t state)
+static int wbsd_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct mmc_host *mmc = platform_get_drvdata(dev);
 	struct wbsd_host *host;
 	int ret;
 
@@ -2005,9 +2005,9 @@
 	return 0;
 }
 
-static int wbsd_resume(struct device *dev)
+static int wbsd_resume(struct platform_device *dev)
 {
-	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct mmc_host *mmc = platform_get_drvdata(dev);
 	struct wbsd_host *host;
 
 	if (!mmc)
@@ -2038,14 +2038,15 @@
 
 static struct platform_device *wbsd_device;
 
-static struct device_driver wbsd_driver = {
-	.name		= DRIVER_NAME,
-	.bus		= &platform_bus_type,
+static struct platform_driver wbsd_driver = {
 	.probe		= wbsd_probe,
-	.remove		= wbsd_remove,
+	.remove		= __devexit_p(wbsd_remove),
 
 	.suspend	= wbsd_suspend,
 	.resume		= wbsd_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
 };
 
 #ifdef CONFIG_PNP
@@ -2054,7 +2055,7 @@
 	.name		= DRIVER_NAME,
 	.id_table	= pnp_dev_table,
 	.probe		= wbsd_pnp_probe,
-	.remove		= wbsd_pnp_remove,
+	.remove		= __devexit_p(wbsd_pnp_remove),
 };
 
 #endif /* CONFIG_PNP */
@@ -2085,7 +2086,7 @@
 
 	if (nopnp)
 	{
-		result = driver_register(&wbsd_driver);
+		result = platform_driver_register(&wbsd_driver);
 		if (result < 0)
 			return result;
 
@@ -2111,7 +2112,7 @@
 	{
 		platform_device_unregister(wbsd_device);
 
-		driver_unregister(&wbsd_driver);
+		platform_driver_unregister(&wbsd_driver);
 	}
 
 	DBG("unloaded\n");
@@ -2127,6 +2128,7 @@
 module_param(dma, int, 0444);
 
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
 MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
 MODULE_VERSION(DRIVER_VERSION);
 
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index c4a19d2..0807c1c 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -20,7 +20,6 @@
  * 	- Plugged memory leak in cfi_staa_writev().
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index de48b35..666cce1 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -82,7 +82,6 @@
  *       * Comb the init routine.  It's still a bit cludgy on a few things.
  */
 
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c
index b7858eb..51f962d 100644
--- a/drivers/mtd/maps/bast-flash.c
+++ b/drivers/mtd/maps/bast-flash.c
@@ -63,11 +63,6 @@
 
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 
-static struct bast_flash_info *to_bast_info(struct device *dev)
-{
-	return (struct bast_flash_info *)dev_get_drvdata(dev);
-}
-
 static void bast_flash_setrw(int to)
 {
 	unsigned int val;
@@ -87,11 +82,11 @@
 	local_irq_restore(flags);
 }
 
-static int bast_flash_remove(struct device *dev)
+static int bast_flash_remove(struct platform_device *pdev)
 {
-	struct bast_flash_info *info = to_bast_info(dev);
+	struct bast_flash_info *info = platform_get_drvdata(pdev);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	if (info == NULL)
 		return 0;
@@ -116,9 +111,8 @@
 	return 0;
 }
 
-static int bast_flash_probe(struct device *dev)
+static int bast_flash_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct bast_flash_info *info;
 	struct resource *res;
 	int err = 0;
@@ -131,13 +125,13 @@
 	}
 
 	memzero(info, sizeof(*info));
-	dev_set_drvdata(dev, info);
+	platform_set_drvdata(pdev, info);
 
 	res = pdev->resource;  /* assume that the flash has one resource */
 
 	info->map.phys = res->start;
 	info->map.size = res->end - res->start + 1;
-	info->map.name = dev->bus_id;
+	info->map.name = pdev->dev.bus_id;	
 	info->map.bankwidth = 2;
 
 	if (info->map.size > AREA_MAXSIZE)
@@ -199,27 +193,28 @@
 	/* fall through to exit error */
 
  exit_error:
-	bast_flash_remove(dev);
+	bast_flash_remove(pdev);
 	return err;
 }
 
-static struct device_driver bast_flash_driver = {
-	.name		= "bast-nor",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver bast_flash_driver = {
 	.probe		= bast_flash_probe,
 	.remove		= bast_flash_remove,
+	.driver		= {
+		.name	= "bast-nor",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static int __init bast_flash_init(void)
 {
 	printk("BAST NOR-Flash Driver, (c) 2004 Simtec Electronics\n");
-	return driver_register(&bast_flash_driver);
+	return platform_driver_register(&bast_flash_driver);
 }
 
 static void __exit bast_flash_exit(void)
 {
-	driver_unregister(&bast_flash_driver);
+	platform_driver_unregister(&bast_flash_driver);
 }
 
 module_init(bast_flash_init);
diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c
index c0daf58..60a6e51 100644
--- a/drivers/mtd/maps/ebony.c
+++ b/drivers/mtd/maps/ebony.c
@@ -21,7 +21,6 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/ibm44x.h>
 #include <platforms/4xx/ebony.h>
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c
index fe738fd8..a3ba52f 100644
--- a/drivers/mtd/maps/integrator-flash.c
+++ b/drivers/mtd/maps/integrator-flash.c
@@ -67,9 +67,8 @@
 
 static const char *probes[] = { "cmdlinepart", "RedBoot", "afs", NULL };
 
-static int armflash_probe(struct device *_dev)
+static int armflash_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(_dev);
 	struct flash_platform_data *plat = dev->dev.platform_data;
 	struct resource *res = dev->resource;
 	unsigned int size = res->end - res->start + 1;
@@ -138,7 +137,7 @@
 	}
 
 	if (err == 0)
-		dev_set_drvdata(&dev->dev, info);
+		platform_set_drvdata(dev, info);
 
 	/*
 	 * If we got an error, free all resources.
@@ -163,12 +162,11 @@
 	return err;
 }
 
-static int armflash_remove(struct device *_dev)
+static int armflash_remove(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(_dev);
-	struct armflash_info *info = dev_get_drvdata(&dev->dev);
+	struct armflash_info *info = platform_get_drvdata(dev);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	platform_set_drvdata(dev, NULL);
 
 	if (info) {
 		if (info->mtd) {
@@ -190,21 +188,22 @@
 	return 0;
 }
 
-static struct device_driver armflash_driver = {
-	.name		= "armflash",
-	.bus		= &platform_bus_type,
+static struct platform_driver armflash_driver = {
 	.probe		= armflash_probe,
 	.remove		= armflash_remove,
+	.driver		= {
+		.name	= "armflash",
+	},
 };
 
 static int __init armflash_init(void)
 {
-	return driver_register(&armflash_driver);
+	return platform_driver_register(&armflash_driver);
 }
 
 static void __exit armflash_exit(void)
 {
-	driver_unregister(&armflash_driver);
+	platform_driver_unregister(&armflash_driver);
 }
 
 module_init(armflash_init);
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
index 641eb2b..fc7a78e 100644
--- a/drivers/mtd/maps/ixp2000.c
+++ b/drivers/mtd/maps/ixp2000.c
@@ -111,13 +111,12 @@
 }
 
 
-static int ixp2000_flash_remove(struct device *_dev)
+static int ixp2000_flash_remove(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(_dev);
 	struct flash_platform_data *plat = dev->dev.platform_data;
-	struct ixp2000_flash_info *info = dev_get_drvdata(&dev->dev);
+	struct ixp2000_flash_info *info = platform_get_drvdata(dev);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	platform_set_drvdata(dev, NULL);
 
 	if(!info)
 		return 0;
@@ -143,10 +142,9 @@
 }
 
 
-static int ixp2000_flash_probe(struct device *_dev)
+static int ixp2000_flash_probe(struct platform_device *dev)
 {
 	static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-	struct platform_device *dev = to_platform_device(_dev);
 	struct ixp2000_flash_data *ixp_data = dev->dev.platform_data;
 	struct flash_platform_data *plat;
 	struct ixp2000_flash_info *info;
@@ -177,7 +175,7 @@
 	}
 	memzero(info, sizeof(struct ixp2000_flash_info));
 
-	dev_set_drvdata(&dev->dev, info);
+	platform_set_drvdata(dev, info);
 
 	/*
 	 * Tell the MTD layer we're not 1:1 mapped so that it does
@@ -248,25 +246,26 @@
 	return 0;
 
 Error:
-	ixp2000_flash_remove(_dev);
+	ixp2000_flash_remove(dev);
 	return err;
 }
 
-static struct device_driver ixp2000_flash_driver = {
-	.name		= "IXP2000-Flash",
-	.bus		= &platform_bus_type,
+static struct platform_driver ixp2000_flash_driver = {
 	.probe		= &ixp2000_flash_probe,
 	.remove		= &ixp2000_flash_remove
+	.driver		= {
+		.name	= "IXP2000-Flash",
+	},
 };
 
 static int __init ixp2000_flash_init(void)
 {
-	return driver_register(&ixp2000_flash_driver);
+	return platform_driver_register(&ixp2000_flash_driver);
 }
 
 static void __exit ixp2000_flash_exit(void)
 {
-	driver_unregister(&ixp2000_flash_driver);
+	platform_driver_unregister(&ixp2000_flash_driver);
 }
 
 module_init(ixp2000_flash_init);
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c
index 56b3a355..a59f802 100644
--- a/drivers/mtd/maps/ixp4xx.c
+++ b/drivers/mtd/maps/ixp4xx.c
@@ -99,13 +99,12 @@
 
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 
-static int ixp4xx_flash_remove(struct device *_dev)
+static int ixp4xx_flash_remove(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(_dev);
 	struct flash_platform_data *plat = dev->dev.platform_data;
-	struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev);
+	struct ixp4xx_flash_info *info = platform_get_drvdata(dev);
 
-	dev_set_drvdata(&dev->dev, NULL);
+	platform_set_drvdata(dev, NULL);
 
 	if(!info)
 		return 0;
@@ -130,9 +129,8 @@
 	return 0;
 }
 
-static int ixp4xx_flash_probe(struct device *_dev)
+static int ixp4xx_flash_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(_dev);
 	struct flash_platform_data *plat = dev->dev.platform_data;
 	struct ixp4xx_flash_info *info;
 	int err = -1;
@@ -153,7 +151,7 @@
 	}
 	memzero(info, sizeof(struct ixp4xx_flash_info));
 
-	dev_set_drvdata(&dev->dev, info);
+	platform_set_drvdata(dev, info);
 
 	/*
 	 * Tell the MTD layer we're not 1:1 mapped so that it does
@@ -214,25 +212,26 @@
 	return 0;
 
 Error:
-	ixp4xx_flash_remove(_dev);
+	ixp4xx_flash_remove(dev);
 	return err;
 }
 
-static struct device_driver ixp4xx_flash_driver = {
-	.name		= "IXP4XX-Flash",
-	.bus		= &platform_bus_type,
+static struct platform_driver ixp4xx_flash_driver = {
 	.probe		= ixp4xx_flash_probe,
 	.remove		= ixp4xx_flash_remove,
+	.driver		= {
+		.name	= "IXP4XX-Flash",
+	},
 };
 
 static int __init ixp4xx_flash_init(void)
 {
-	return driver_register(&ixp4xx_flash_driver);
+	return platform_driver_register(&ixp4xx_flash_driver);
 }
 
 static void __exit ixp4xx_flash_exit(void)
 {
-	driver_unregister(&ixp4xx_flash_driver);
+	platform_driver_unregister(&ixp4xx_flash_driver);
 }
 
 
diff --git a/drivers/mtd/maps/ocotea.c b/drivers/mtd/maps/ocotea.c
index 6e559bc..c223514 100644
--- a/drivers/mtd/maps/ocotea.c
+++ b/drivers/mtd/maps/ocotea.c
@@ -19,7 +19,6 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/ibm44x.h>
 #include <platforms/4xx/ocotea.h>
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c
index fd3b4a5..418afff 100644
--- a/drivers/mtd/maps/omap_nor.c
+++ b/drivers/mtd/maps/omap_nor.c
@@ -70,11 +70,10 @@
 	}
 }
 
-static int __devinit omapflash_probe(struct device *dev)
+static int __devinit omapflash_probe(struct platform_device *pdev)
 {
 	int err;
 	struct omapflash_info *info;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct flash_platform_data *pdata = pdev->dev.platform_data;
 	struct resource *res = pdev->resource;
 	unsigned long size = res->end - res->start + 1;
@@ -119,7 +118,7 @@
 #endif
 		add_mtd_device(info->mtd);
 
-	dev_set_drvdata(&pdev->dev, info);
+	platform_set_drvdata(pdev, info);
 
 	return 0;
 
@@ -133,12 +132,11 @@
 	return err;
 }
 
-static int __devexit omapflash_remove(struct device *dev)
+static int __devexit omapflash_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct omapflash_info *info = dev_get_drvdata(&pdev->dev);
+	struct omapflash_info *info = platform_get_drvdata(pdev);
 
-	dev_set_drvdata(&pdev->dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	if (info) {
 		if (info->parts) {
@@ -155,21 +153,22 @@
 	return 0;
 }
 
-static struct device_driver omapflash_driver = {
-	.name	= "omapflash",
-	.bus	= &platform_bus_type,
+static struct platform_driver omapflash_driver = {
 	.probe	= omapflash_probe,
 	.remove	= __devexit_p(omapflash_remove),
+	.driver = {
+		.name	= "omapflash",
+	},
 };
 
 static int __init omapflash_init(void)
 {
-	return driver_register(&omapflash_driver);
+	return platform_driver_register(&omapflash_driver);
 }
 
 static void __exit omapflash_exit(void)
 {
-	driver_unregister(&omapflash_driver);
+	platform_driver_unregister(&omapflash_driver);
 }
 
 module_init(omapflash_init);
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
index a02eed9..5d3c754 100644
--- a/drivers/mtd/maps/plat-ram.c
+++ b/drivers/mtd/maps/plat-ram.c
@@ -56,9 +56,9 @@
  * device private data to struct platram_info conversion
 */
 
-static inline struct platram_info *to_platram_info(struct device *dev)
+static inline struct platram_info *to_platram_info(struct platform_device *dev)
 {
-	return (struct platram_info *)dev_get_drvdata(dev);
+	return (struct platram_info *)platform_get_drvdata(dev);
 }
 
 /* platram_setrw
@@ -83,13 +83,13 @@
  * called to remove the device from the driver's control
 */
 
-static int platram_remove(struct device *dev)
+static int platram_remove(struct platform_device *pdev)
 {
-	struct platram_info *info = to_platram_info(dev);
+	struct platram_info *info = to_platram_info(pdev);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
-	dev_dbg(dev, "removing device\n");
+	dev_dbg(&pdev->dev, "removing device\n");
 
 	if (info == NULL)
 		return 0;
@@ -130,61 +130,60 @@
  * driver is found.
 */
 
-static int platram_probe(struct device *dev)
+static int platram_probe(struct platform_device *pdev)
 {
-	struct platform_device *pd = to_platform_device(dev);
 	struct platdata_mtd_ram	*pdata;
 	struct platram_info *info;
 	struct resource *res;
 	int err = 0;
 
-	dev_dbg(dev, "probe entered\n");
+	dev_dbg(&pdev->dev, "probe entered\n");
 
-	if (dev->platform_data == NULL) {
-		dev_err(dev, "no platform data supplied\n");
+	if (pdev->dev.platform_data == NULL) {
+		dev_err(&pdev->dev, "no platform data supplied\n");
 		err = -ENOENT;
 		goto exit_error;
 	}
 
-	pdata = dev->platform_data;
+	pdata = pdev->dev.platform_data;
 
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
 	if (info == NULL) {
-		dev_err(dev, "no memory for flash info\n");
+		dev_err(&pdev->dev, "no memory for flash info\n");
 		err = -ENOMEM;
 		goto exit_error;
 	}
 
 	memset(info, 0, sizeof(*info));
-	dev_set_drvdata(dev, info);
+	platform_set_drvdata(pdev, info);
 
-	info->dev = dev;
+	info->dev = &pdev->dev;
 	info->pdata = pdata;
 
 	/* get the resource for the memory mapping */
 
-	res = platform_get_resource(pd, IORESOURCE_MEM, 0);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	if (res == NULL) {
-		dev_err(dev, "no memory resource specified\n");
+		dev_err(&pdev->dev, "no memory resource specified\n");
 		err = -ENOENT;
 		goto exit_free;
 	}
 
-	dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start);
+	dev_dbg(&pdev->dev, "got platform resource %p (0x%lx)\n", res, res->start);
 
 	/* setup map parameters */
 
 	info->map.phys = res->start;
 	info->map.size = (res->end - res->start) + 1;
-	info->map.name = pdata->mapname != NULL ? pdata->mapname : (char *)pd->name;
+	info->map.name = pdata->mapname != NULL ? pdata->mapname : (char *)pdev->name;
 	info->map.bankwidth = pdata->bankwidth;
 
 	/* register our usage of the memory area */
 
-	info->area = request_mem_region(res->start, info->map.size, pd->name);
+	info->area = request_mem_region(res->start, info->map.size, pdev->name);
 	if (info->area == NULL) {
-		dev_err(dev, "failed to request memory region\n");
+		dev_err(&pdev->dev, "failed to request memory region\n");
 		err = -EIO;
 		goto exit_free;
 	}
@@ -192,23 +191,23 @@
 	/* remap the memory area */
 
 	info->map.virt = ioremap(res->start, info->map.size);
-	dev_dbg(dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size);
+	dev_dbg(&pdev->dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size);
 
 	if (info->map.virt == NULL) {
-		dev_err(dev, "failed to ioremap() region\n");
+		dev_err(&pdev->dev, "failed to ioremap() region\n");
 		err = -EIO;
 		goto exit_free;
 	}
 
 	simple_map_init(&info->map);
 
-	dev_dbg(dev, "initialised map, probing for mtd\n");
+	dev_dbg(&pdev->dev, "initialised map, probing for mtd\n");
 
 	/* probe for the right mtd map driver */
 
 	info->mtd = do_map_probe("map_ram" , &info->map);
 	if (info->mtd == NULL) {
-		dev_err(dev, "failed to probe for map_ram\n");
+		dev_err(&pdev->dev, "failed to probe for map_ram\n");
 		err = -ENOMEM;
 		goto exit_free;
 	}
@@ -237,27 +236,28 @@
 #endif /* CONFIG_MTD_PARTITIONS */
 
 	if (add_mtd_device(info->mtd)) {
-		dev_err(dev, "add_mtd_device() failed\n");
+		dev_err(&pdev->dev, "add_mtd_device() failed\n");
 		err = -ENOMEM;
 	}
 
-	dev_info(dev, "registered mtd device\n");
+	dev_info(&pdev->dev, "registered mtd device\n");
 	return err;
 
  exit_free:
-	platram_remove(dev);
+	platram_remove(pdev);
  exit_error:
 	return err;
 }
 
 /* device driver info */
 
-static struct device_driver platram_driver = {
-	.name		= "mtd-ram",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver platram_driver = {
 	.probe		= platram_probe,
 	.remove		= platram_remove,
+	.driver		= {
+		.name	= "mtd-ram",
+		.owner	= THIS_MODULE,
+	},
 };
 
 /* module init/exit */
@@ -265,12 +265,12 @@
 static int __init platram_init(void)
 {
 	printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n");
-	return driver_register(&platram_driver);
+	return platform_driver_register(&platram_driver);
 }
 
 static void __exit platram_exit(void)
 {
-	driver_unregister(&platram_driver);
+	platform_driver_unregister(&platram_driver);
 }
 
 module_init(platram_init);
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index 9e8bb17..5cefb01 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -356,9 +356,8 @@
 
 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
-static int __init sa1100_mtd_probe(struct device *dev)
+static int __init sa1100_mtd_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct flash_platform_data *plat = pdev->dev.platform_data;
 	struct mtd_partition *parts;
 	const char *part_type = NULL;
@@ -402,28 +401,28 @@
 
 	info->nr_parts = nr_parts;
 
-	dev_set_drvdata(dev, info);
+	platform_set_drvdata(pdev, info);
 	err = 0;
 
  out:
 	return err;
 }
 
-static int __exit sa1100_mtd_remove(struct device *dev)
+static int __exit sa1100_mtd_remove(struct platform_device *pdev)
 {
-	struct sa_info *info = dev_get_drvdata(dev);
-	struct flash_platform_data *plat = dev->platform_data;
+	struct sa_info *info = platform_get_drvdata(pdev);
+	struct flash_platform_data *plat = pdev->dev.platform_data;
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 	sa1100_destroy(info, plat);
 
 	return 0;
 }
 
 #ifdef CONFIG_PM
-static int sa1100_mtd_suspend(struct device *dev, pm_message_t state)
+static int sa1100_mtd_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct sa_info *info = dev_get_drvdata(dev);
+	struct sa_info *info = platform_get_drvdata(dev);
 	int ret = 0;
 
 	if (info)
@@ -432,17 +431,17 @@
 	return ret;
 }
 
-static int sa1100_mtd_resume(struct device *dev)
+static int sa1100_mtd_resume(struct platform_device *dev)
 {
-	struct sa_info *info = dev_get_drvdata(dev);
+	struct sa_info *info = platform_get_drvdata(dev);
 	if (info)
 		info->mtd->resume(info->mtd);
 	return 0;
 }
 
-static void sa1100_mtd_shutdown(struct device *dev)
+static void sa1100_mtd_shutdown(struct platform_device *dev)
 {
-	struct sa_info *info = dev_get_drvdata(dev);
+	struct sa_info *info = platform_get_drvdata(dev);
 	if (info && info->mtd->suspend(info->mtd) == 0)
 		info->mtd->resume(info->mtd);
 }
@@ -452,24 +451,25 @@
 #define sa1100_mtd_shutdown NULL
 #endif
 
-static struct device_driver sa1100_mtd_driver = {
-	.name		= "flash",
-	.bus		= &platform_bus_type,
+static struct platform_driver sa1100_mtd_driver = {
 	.probe		= sa1100_mtd_probe,
 	.remove		= __exit_p(sa1100_mtd_remove),
 	.suspend	= sa1100_mtd_suspend,
 	.resume		= sa1100_mtd_resume,
 	.shutdown	= sa1100_mtd_shutdown,
+	.driver		= {
+		.name	= "flash",
+	},
 };
 
 static int __init sa1100_mtd_init(void)
 {
-	return driver_register(&sa1100_mtd_driver);
+	return platform_driver_register(&sa1100_mtd_driver);
 }
 
 static void __exit sa1100_mtd_exit(void)
 {
-	driver_unregister(&sa1100_mtd_driver);
+	platform_driver_unregister(&sa1100_mtd_driver);
 }
 
 module_init(sa1100_mtd_init);
diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c
index 5c17bca..f46bec6 100644
--- a/drivers/mtd/maps/walnut.c
+++ b/drivers/mtd/maps/walnut.c
@@ -21,7 +21,6 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/ibm4xx.h>
 #include <platforms/4xx/walnut.h>
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 3cafcdf..9c5945d 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -17,6 +17,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/version.h>
 #include <asm/io.h>
 
 /* fixme: this is ugly */
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c
index 056dfc1..a3c7fea 100644
--- a/drivers/mtd/nand/autcpu12.c
+++ b/drivers/mtd/nand/autcpu12.c
@@ -27,7 +27,6 @@
  *	10-06-2002 TG	128K card support added
  */
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 97e9b78..d209214 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -125,14 +125,14 @@
 	return s3c2410_nand_mtd_toours(mtd)->info;
 }
 
-static struct s3c2410_nand_info *to_nand_info(struct device *dev)
+static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
 {
-	return dev_get_drvdata(dev);
+	return platform_get_drvdata(dev);
 }
 
-static struct s3c2410_platform_nand *to_nand_plat(struct device *dev)
+static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
 {
-	return dev->platform_data;
+	return dev->dev.platform_data;
 }
 
 /* timing calculations */
@@ -165,9 +165,9 @@
 /* controller setup */
 
 static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
-			       struct device *dev)
+			       struct platform_device *pdev)
 {
-	struct s3c2410_platform_nand *plat = to_nand_plat(dev);
+	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
 	unsigned long clkrate = clk_get_rate(info->clk);
 	int tacls, twrph0, twrph1;
 	unsigned long cfg;
@@ -430,11 +430,11 @@
 
 /* device management functions */
 
-static int s3c2410_nand_remove(struct device *dev)
+static int s3c2410_nand_remove(struct platform_device *pdev)
 {
-	struct s3c2410_nand_info *info = to_nand_info(dev);
+	struct s3c2410_nand_info *info = to_nand_info(pdev);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	if (info == NULL)
 		return 0;
@@ -562,10 +562,9 @@
  * nand layer to look for devices
 */
 
-static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
+static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct s3c2410_platform_nand *plat = to_nand_plat(dev);
+	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
 	struct s3c2410_nand_info *info;
 	struct s3c2410_nand_mtd *nmtd;
 	struct s3c2410_nand_set *sets;
@@ -575,26 +574,26 @@
 	int nr_sets;
 	int setno;
 
-	pr_debug("s3c2410_nand_probe(%p)\n", dev);
+	pr_debug("s3c2410_nand_probe(%p)\n", pdev);
 
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
 	if (info == NULL) {
-		dev_err(dev, "no memory for flash info\n");
+		dev_err(&pdev->dev, "no memory for flash info\n");
 		err = -ENOMEM;
 		goto exit_error;
 	}
 
 	memzero(info, sizeof(*info));
-	dev_set_drvdata(dev, info);
+	platform_set_drvdata(pdev, info);
 
 	spin_lock_init(&info->controller.lock);
 	init_waitqueue_head(&info->controller.wq);
 
 	/* get the clock source and enable it */
 
-	info->clk = clk_get(dev, "nand");
+	info->clk = clk_get(&pdev->dev, "nand");
 	if (IS_ERR(info->clk)) {
-		dev_err(dev, "failed to get clock");
+		dev_err(&pdev->dev, "failed to get clock");
 		err = -ENOENT;
 		goto exit_error;
 	}
@@ -611,27 +610,27 @@
 	info->area = request_mem_region(res->start, size, pdev->name);
 
 	if (info->area == NULL) {
-		dev_err(dev, "cannot reserve register region\n");
+		dev_err(&pdev->dev, "cannot reserve register region\n");
 		err = -ENOENT;
 		goto exit_error;
 	}
 
-	info->device     = dev;
+	info->device     = &pdev->dev;
 	info->platform   = plat;
 	info->regs       = ioremap(res->start, size);
 	info->is_s3c2440 = is_s3c2440;
 
 	if (info->regs == NULL) {
-		dev_err(dev, "cannot reserve register region\n");
+		dev_err(&pdev->dev, "cannot reserve register region\n");
 		err = -EIO;
 		goto exit_error;
 	}
 
-	dev_dbg(dev, "mapped registers at %p\n", info->regs);
+	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
 
 	/* initialise the hardware */
 
-	err = s3c2410_nand_inithw(info, dev);
+	err = s3c2410_nand_inithw(info, pdev);
 	if (err != 0)
 		goto exit_error;
 
@@ -645,7 +644,7 @@
 	size = nr_sets * sizeof(*info->mtds);
 	info->mtds = kmalloc(size, GFP_KERNEL);
 	if (info->mtds == NULL) {
-		dev_err(dev, "failed to allocate mtd storage\n");
+		dev_err(&pdev->dev, "failed to allocate mtd storage\n");
 		err = -ENOMEM;
 		goto exit_error;
 	}
@@ -677,7 +676,7 @@
 	return 0;
 
  exit_error:
-	s3c2410_nand_remove(dev);
+	s3c2410_nand_remove(pdev);
 
 	if (err == 0)
 		err = -EINVAL;
@@ -686,44 +685,46 @@
 
 /* driver device registration */
 
-static int s3c2410_nand_probe(struct device *dev)
+static int s3c2410_nand_probe(struct platform_device *dev)
 {
 	return s3c24xx_nand_probe(dev, 0);
 }
 
-static int s3c2440_nand_probe(struct device *dev)
+static int s3c2440_nand_probe(struct platform_device *dev)
 {
 	return s3c24xx_nand_probe(dev, 1);
 }
 
-static struct device_driver s3c2410_nand_driver = {
-	.name		= "s3c2410-nand",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2410_nand_driver = {
 	.probe		= s3c2410_nand_probe,
 	.remove		= s3c2410_nand_remove,
+	.driver		= {
+		.name	= "s3c2410-nand",
+		.owner	= THIS_MODULE,
+	},
 };
 
-static struct device_driver s3c2440_nand_driver = {
-	.name		= "s3c2440-nand",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2440_nand_driver = {
 	.probe		= s3c2440_nand_probe,
 	.remove		= s3c2410_nand_remove,
+	.driver		= {
+		.name	= "s3c2440-nand",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static int __init s3c2410_nand_init(void)
 {
 	printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
 
-	driver_register(&s3c2440_nand_driver);
-	return driver_register(&s3c2410_nand_driver);
+	platform_driver_register(&s3c2440_nand_driver);
+	return platform_driver_register(&s3c2410_nand_driver);
 }
 
 static void __exit s3c2410_nand_exit(void)
 {
-	driver_unregister(&s3c2440_nand_driver);
-	driver_unregister(&s3c2410_nand_driver);
+	platform_driver_unregister(&s3c2440_nand_driver);
+	platform_driver_unregister(&s3c2410_nand_driver);
 }
 
 module_init(s3c2410_nand_init);
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index cc38fa0..f67d5d6 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -12,6 +12,8 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/partitions.h>
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index 041ee59..0ab8d29 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -18,6 +18,7 @@
 #include <linux/mtd/blktrans.h>
 #include <linux/mtd/mtd.h>
 #include <linux/vmalloc.h>
+#include <linux/jiffies.h>
 
 #include <asm/types.h>
 
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 1958d9e..ebd7313 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -447,7 +447,7 @@
 
 config SGI_IOC3_ETH
 	bool "SGI IOC3 Ethernet"
-	depends on NET_ETHERNET && PCI && SGI_IP27 && BROKEN
+	depends on NET_ETHERNET && PCI && SGI_IP27
 	select CRC32
 	select MII
 	help
@@ -812,7 +812,7 @@
 	tristate "SMC 91C9x/91C1xxx support"
 	select CRC32
 	select MII
-	depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH)
+	depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00)
 	help
 	  This is a driver for SMC's 91x series of Ethernet chipsets,
 	  including the SMC91C94 and the SMC91C111. Say Y if you want it
@@ -2523,6 +2523,19 @@
 	  module; it is called bsd_comp and will show up in the directory
 	  modules once you have said "make modules". If unsure, say N.
 
+config PPP_MPPE
+       tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
+       depends on PPP && EXPERIMENTAL
+       select CRYPTO
+       select CRYPTO_SHA1
+       select CRYPTO_ARC4
+       ---help---
+         Support for the MPPE Encryption protocol, as employed by the
+	 Microsoft Point-to-Point Tunneling Protocol.
+
+	 See http://pptpclient.sourceforge.net/ for information on
+	 configuring PPTP clients and servers to utilize this method.
+
 config PPPOE
 	tristate "PPP over Ethernet (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && PPP
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7c313cb..4cffd34 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -112,6 +112,7 @@
 obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
 obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
 obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
+obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
 obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
 
 obj-$(CONFIG_SLIP) += slip.o
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 0ee3e27..c53848f 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -18,7 +18,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/dma-mapping.h>
 
 #include <asm/uaccess.h>
@@ -29,8 +28,8 @@
 
 #define DRV_MODULE_NAME		"b44"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"0.95"
-#define DRV_MODULE_RELDATE	"Aug 3, 2004"
+#define DRV_MODULE_VERSION	"0.96"
+#define DRV_MODULE_RELDATE	"Nov 8, 2005"
 
 #define B44_DEF_MSG_ENABLE	  \
 	(NETIF_MSG_DRV		| \
@@ -102,14 +101,16 @@
 static void b44_halt(struct b44 *);
 static void b44_init_rings(struct b44 *);
 static void b44_init_hw(struct b44 *);
-static int b44_poll(struct net_device *dev, int *budget);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void b44_poll_controller(struct net_device *dev);
-#endif
 
 static int dma_desc_align_mask;
 static int dma_desc_sync_size;
 
+static const char b44_gstrings[][ETH_GSTRING_LEN] = {
+#define _B44(x...)	# x,
+B44_STAT_REG_DECLARE
+#undef _B44
+};
+
 static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
                                                 dma_addr_t dma_base,
                                                 unsigned long offset,
@@ -502,7 +503,10 @@
 	for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) {
 		*val++ += br32(bp, reg);
 	}
-	val = &bp->hw_stats.rx_good_octets;
+
+	/* Pad */
+	reg += 8*4UL;
+
 	for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) {
 		*val++ += br32(bp, reg);
 	}
@@ -653,7 +657,7 @@
 
 	/* Hardware bug work-around, the chip is unable to do PCI DMA
 	   to/from anything above 1GB :-( */
-	if(mapping+RX_PKT_BUF_SZ > B44_DMA_MASK) {
+	if (mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
 		/* Sigh... */
 		pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
 		dev_kfree_skb_any(skb);
@@ -663,7 +667,7 @@
 		mapping = pci_map_single(bp->pdev, skb->data,
 					 RX_PKT_BUF_SZ,
 					 PCI_DMA_FROMDEVICE);
-		if(mapping+RX_PKT_BUF_SZ > B44_DMA_MASK) {
+		if (mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
 			pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
 			dev_kfree_skb_any(skb);
 			return -ENOMEM;
@@ -890,11 +894,10 @@
 {
 	struct net_device *dev = dev_id;
 	struct b44 *bp = netdev_priv(dev);
-	unsigned long flags;
 	u32 istat, imask;
 	int handled = 0;
 
-	spin_lock_irqsave(&bp->lock, flags);
+	spin_lock(&bp->lock);
 
 	istat = br32(bp, B44_ISTAT);
 	imask = br32(bp, B44_IMASK);
@@ -905,6 +908,12 @@
 	istat &= imask;
 	if (istat) {
 		handled = 1;
+
+		if (unlikely(!netif_running(dev))) {
+			printk(KERN_INFO "%s: late interrupt.\n", dev->name);
+			goto irq_ack;
+		}
+
 		if (netif_rx_schedule_prep(dev)) {
 			/* NOTE: These writes are posted by the readback of
 			 *       the ISTAT register below.
@@ -917,10 +926,11 @@
 			       dev->name);
 		}
 
+irq_ack:
 		bw32(bp, B44_ISTAT, istat);
 		br32(bp, B44_ISTAT);
 	}
-	spin_unlock_irqrestore(&bp->lock, flags);
+	spin_unlock(&bp->lock);
 	return IRQ_RETVAL(handled);
 }
 
@@ -948,6 +958,7 @@
 {
 	struct b44 *bp = netdev_priv(dev);
 	struct sk_buff *bounce_skb;
+	int rc = NETDEV_TX_OK;
 	dma_addr_t mapping;
 	u32 len, entry, ctrl;
 
@@ -957,29 +968,28 @@
 	/* This is a hard error, log it. */
 	if (unlikely(TX_BUFFS_AVAIL(bp) < 1)) {
 		netif_stop_queue(dev);
-		spin_unlock_irq(&bp->lock);
 		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
 		       dev->name);
-		return 1;
+		goto err_out;
 	}
 
 	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
-	if(mapping+len > B44_DMA_MASK) {
+	if (mapping + len > B44_DMA_MASK) {
 		/* Chip can't handle DMA to/from >1GB, use bounce buffer */
 		pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
 
 		bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ,
 					     GFP_ATOMIC|GFP_DMA);
 		if (!bounce_skb)
-			return NETDEV_TX_BUSY;
+			goto err_out;
 
 		mapping = pci_map_single(bp->pdev, bounce_skb->data,
 					 len, PCI_DMA_TODEVICE);
-		if(mapping+len > B44_DMA_MASK) {
+		if (mapping + len > B44_DMA_MASK) {
 			pci_unmap_single(bp->pdev, mapping,
 					 len, PCI_DMA_TODEVICE);
 			dev_kfree_skb_any(bounce_skb);
-			return NETDEV_TX_BUSY;
+			goto err_out;
 		}
 
 		memcpy(skb_put(bounce_skb, len), skb->data, skb->len);
@@ -1019,11 +1029,16 @@
 	if (TX_BUFFS_AVAIL(bp) < 1)
 		netif_stop_queue(dev);
 
-	spin_unlock_irq(&bp->lock);
-
 	dev->trans_start = jiffies;
 
-	return 0;
+out_unlock:
+	spin_unlock_irq(&bp->lock);
+
+	return rc;
+
+err_out:
+	rc = NETDEV_TX_BUSY;
+	goto out_unlock;
 }
 
 static int b44_change_mtu(struct net_device *dev, int new_mtu)
@@ -1097,8 +1112,7 @@
  *
  * The chip has been shut down and the driver detached from
  * the networking, so no interrupts or new tx packets will
- * end up in the driver.  bp->lock is not held and we are not
- * in an interrupt context and thus may sleep.
+ * end up in the driver.
  */
 static void b44_init_rings(struct b44 *bp)
 {
@@ -1170,16 +1184,14 @@
 	int size;
 
 	size  = B44_RX_RING_SIZE * sizeof(struct ring_info);
-	bp->rx_buffers = kmalloc(size, GFP_KERNEL);
+	bp->rx_buffers = kzalloc(size, GFP_KERNEL);
 	if (!bp->rx_buffers)
 		goto out_err;
-	memset(bp->rx_buffers, 0, size);
 
 	size = B44_TX_RING_SIZE * sizeof(struct ring_info);
-	bp->tx_buffers = kmalloc(size, GFP_KERNEL);
+	bp->tx_buffers = kzalloc(size, GFP_KERNEL);
 	if (!bp->tx_buffers)
 		goto out_err;
-	memset(bp->tx_buffers, 0, size);
 
 	size = DMA_TABLE_BYTES;
 	bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
@@ -1190,10 +1202,10 @@
 		struct dma_desc *rx_ring;
 		dma_addr_t rx_ring_dma;
 
-		if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+		rx_ring = kzalloc(size, GFP_KERNEL);
+		if (!rx_ring)
 			goto out_err;
 
-		memset(rx_ring, 0, size);
 		rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
 		                             DMA_TABLE_BYTES,
 		                             DMA_BIDIRECTIONAL);
@@ -1216,10 +1228,10 @@
 		struct dma_desc *tx_ring;
 		dma_addr_t tx_ring_dma;
 
-		if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+		tx_ring = kzalloc(size, GFP_KERNEL);
+		if (!tx_ring)
 			goto out_err;
 
-		memset(tx_ring, 0, size);
 		tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
 		                             DMA_TABLE_BYTES,
 		                             DMA_TO_DEVICE);
@@ -1382,22 +1394,21 @@
 
 	err = b44_alloc_consistent(bp);
 	if (err)
-		return err;
-
-	err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
-	if (err)
-		goto err_out_free;
-
-	spin_lock_irq(&bp->lock);
+		goto out;
 
 	b44_init_rings(bp);
 	b44_init_hw(bp);
-	bp->flags |= B44_FLAG_INIT_COMPLETE;
 
 	netif_carrier_off(dev);
 	b44_check_phy(bp);
 
-	spin_unlock_irq(&bp->lock);
+	err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
+	if (unlikely(err < 0)) {
+		b44_chip_reset(bp);
+		b44_free_rings(bp);
+		b44_free_consistent(bp);
+		goto out;
+	}
 
 	init_timer(&bp->timer);
 	bp->timer.expires = jiffies + HZ;
@@ -1406,11 +1417,7 @@
 	add_timer(&bp->timer);
 
 	b44_enable_ints(bp);
-
-	return 0;
-
-err_out_free:
-	b44_free_consistent(bp);
+out:
 	return err;
 }
 
@@ -1445,6 +1452,8 @@
 
 	netif_stop_queue(dev);
 
+	netif_poll_disable(dev);
+
 	del_timer_sync(&bp->timer);
 
 	spin_lock_irq(&bp->lock);
@@ -1454,13 +1463,14 @@
 #endif
 	b44_halt(bp);
 	b44_free_rings(bp);
-	bp->flags &= ~B44_FLAG_INIT_COMPLETE;
 	netif_carrier_off(bp->dev);
 
 	spin_unlock_irq(&bp->lock);
 
 	free_irq(dev->irq, dev);
 
+	netif_poll_enable(dev);
+
 	b44_free_consistent(bp);
 
 	return 0;
@@ -1525,8 +1535,6 @@
 {
 	struct b44 *bp = netdev_priv(dev);
 	u32 val;
-	int i=0;
-	unsigned char zero[6] = {0,0,0,0,0,0};
 
 	val = br32(bp, B44_RXCONFIG);
 	val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
@@ -1534,14 +1542,17 @@
 		val |= RXCONFIG_PROMISC;
 		bw32(bp, B44_RXCONFIG, val);
 	} else {
+		unsigned char zero[6] = {0, 0, 0, 0, 0, 0};
+		int i = 0;
+
 		__b44_set_mac_addr(bp);
 
 		if (dev->flags & IFF_ALLMULTI)
 			val |= RXCONFIG_ALLMULTI;
 		else
-			i=__b44_load_mcast(bp, dev);
+			i = __b44_load_mcast(bp, dev);
 		
-		for(;i<64;i++) {
+		for (; i < 64; i++) {
 			__b44_cam_write(bp, zero, i);			
 		}
 		bw32(bp, B44_RXCONFIG, val);
@@ -1605,7 +1616,7 @@
 {
 	struct b44 *bp = netdev_priv(dev);
 
-	if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+	if (!netif_running(dev))
 		return -EAGAIN;
 	cmd->supported = (SUPPORTED_Autoneg);
 	cmd->supported |= (SUPPORTED_100baseT_Half |
@@ -1643,7 +1654,7 @@
 {
 	struct b44 *bp = netdev_priv(dev);
 
-	if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+	if (!netif_running(dev))
 		return -EAGAIN;
 
 	/* We do not support gigabit. */
@@ -1773,6 +1784,37 @@
 	return 0;
 }
 
+static void b44_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	switch(stringset) {
+	case ETH_SS_STATS:
+		memcpy(data, *b44_gstrings, sizeof(b44_gstrings));
+		break;
+	}
+}
+
+static int b44_get_stats_count(struct net_device *dev)
+{
+	return ARRAY_SIZE(b44_gstrings);
+}
+
+static void b44_get_ethtool_stats(struct net_device *dev,
+				  struct ethtool_stats *stats, u64 *data)
+{
+	struct b44 *bp = netdev_priv(dev);
+	u32 *val = &bp->hw_stats.tx_good_octets;
+	u32 i;
+
+	spin_lock_irq(&bp->lock);
+
+	b44_stats_update(bp);
+
+	for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++)
+		*data++ = *val++;
+
+	spin_unlock_irq(&bp->lock);
+}
+
 static struct ethtool_ops b44_ethtool_ops = {
 	.get_drvinfo		= b44_get_drvinfo,
 	.get_settings		= b44_get_settings,
@@ -1785,6 +1827,9 @@
 	.set_pauseparam		= b44_set_pauseparam,
 	.get_msglevel		= b44_get_msglevel,
 	.set_msglevel		= b44_set_msglevel,
+	.get_strings		= b44_get_strings,
+	.get_stats_count	= b44_get_stats_count,
+	.get_ethtool_stats	= b44_get_ethtool_stats,
 	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
@@ -1893,9 +1938,9 @@
 	
 	err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
 	if (err) {
-	  printk(KERN_ERR PFX "No usable DMA configuration, "
-		 "aborting.\n");
-	  goto err_out_free_res;
+		printk(KERN_ERR PFX "No usable DMA configuration, "
+		       "aborting.\n");
+		goto err_out_free_res;
 	}
 
 	b44reg_base = pci_resource_start(pdev, 0);
@@ -1917,10 +1962,8 @@
 	bp = netdev_priv(dev);
 	bp->pdev = pdev;
 	bp->dev = dev;
-	if (b44_debug >= 0)
-		bp->msg_enable = (1 << b44_debug) - 1;
-	else
-		bp->msg_enable = B44_DEF_MSG_ENABLE;
+
+	bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
 
 	spin_lock_init(&bp->lock);
 
@@ -2010,17 +2053,14 @@
 static void __devexit b44_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	struct b44 *bp = netdev_priv(dev);
 
-	if (dev) {
-		struct b44 *bp = netdev_priv(dev);
-
-		unregister_netdev(dev);
-		iounmap(bp->regs);
-		free_netdev(dev);
-		pci_release_regions(pdev);
-		pci_disable_device(pdev);
-		pci_set_drvdata(pdev, NULL);
-	}
+	unregister_netdev(dev);
+	iounmap(bp->regs);
+	free_netdev(dev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
 }
 
 static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 593cb0a..b178662 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -346,29 +346,63 @@
 
 #define B44_MCAST_TABLE_SIZE	32
 
+#define	B44_STAT_REG_DECLARE		\
+	_B44(tx_good_octets)		\
+	_B44(tx_good_pkts)		\
+	_B44(tx_octets)			\
+	_B44(tx_pkts)			\
+	_B44(tx_broadcast_pkts)		\
+	_B44(tx_multicast_pkts)		\
+	_B44(tx_len_64)			\
+	_B44(tx_len_65_to_127)		\
+	_B44(tx_len_128_to_255)		\
+	_B44(tx_len_256_to_511)		\
+	_B44(tx_len_512_to_1023)	\
+	_B44(tx_len_1024_to_max)	\
+	_B44(tx_jabber_pkts)		\
+	_B44(tx_oversize_pkts)		\
+	_B44(tx_fragment_pkts)		\
+	_B44(tx_underruns)		\
+	_B44(tx_total_cols)		\
+	_B44(tx_single_cols)		\
+	_B44(tx_multiple_cols)		\
+	_B44(tx_excessive_cols)		\
+	_B44(tx_late_cols)		\
+	_B44(tx_defered)		\
+	_B44(tx_carrier_lost)		\
+	_B44(tx_pause_pkts)		\
+	_B44(rx_good_octets)		\
+	_B44(rx_good_pkts)		\
+	_B44(rx_octets)			\
+	_B44(rx_pkts)			\
+	_B44(rx_broadcast_pkts)		\
+	_B44(rx_multicast_pkts)		\
+	_B44(rx_len_64)			\
+	_B44(rx_len_65_to_127)		\
+	_B44(rx_len_128_to_255)		\
+	_B44(rx_len_256_to_511)		\
+	_B44(rx_len_512_to_1023)	\
+	_B44(rx_len_1024_to_max)	\
+	_B44(rx_jabber_pkts)		\
+	_B44(rx_oversize_pkts)		\
+	_B44(rx_fragment_pkts)		\
+	_B44(rx_missed_pkts)		\
+	_B44(rx_crc_align_errs)		\
+	_B44(rx_undersize)		\
+	_B44(rx_crc_errs)		\
+	_B44(rx_align_errs)		\
+	_B44(rx_symbol_errs)		\
+	_B44(rx_pause_pkts)		\
+	_B44(rx_nonpause_pkts)
+
 /* SW copy of device statistics, kept up to date by periodic timer
- * which probes HW values.  Must have same relative layout as HW
- * register above, because b44_stats_update depends upon this.
+ * which probes HW values. Check b44_stats_update if you mess with
+ * the layout
  */
 struct b44_hw_stats {
-	u32 tx_good_octets, tx_good_pkts, tx_octets;
-	u32 tx_pkts, tx_broadcast_pkts, tx_multicast_pkts;
-	u32 tx_len_64, tx_len_65_to_127, tx_len_128_to_255;
-	u32 tx_len_256_to_511, tx_len_512_to_1023, tx_len_1024_to_max;
-	u32 tx_jabber_pkts, tx_oversize_pkts, tx_fragment_pkts;
-	u32 tx_underruns, tx_total_cols, tx_single_cols;
-	u32 tx_multiple_cols, tx_excessive_cols, tx_late_cols;
-	u32 tx_defered, tx_carrier_lost, tx_pause_pkts;
-	u32 __pad1[8];
-
-	u32 rx_good_octets, rx_good_pkts, rx_octets;
-	u32 rx_pkts, rx_broadcast_pkts, rx_multicast_pkts;
-	u32 rx_len_64, rx_len_65_to_127, rx_len_128_to_255;
-	u32 rx_len_256_to_511, rx_len_512_to_1023, rx_len_1024_to_max;
-	u32 rx_jabber_pkts, rx_oversize_pkts, rx_fragment_pkts;
-	u32 rx_missed_pkts, rx_crc_align_errs, rx_undersize;
-	u32 rx_crc_errs, rx_align_errs, rx_symbol_errs;
-	u32 rx_pause_pkts, rx_nonpause_pkts;
+#define _B44(x)	u32 x;
+B44_STAT_REG_DECLARE
+#undef _B44
 };
 
 struct b44 {
@@ -386,7 +420,6 @@
 
 	u32			dma_offset;
 	u32			flags;
-#define B44_FLAG_INIT_COMPLETE	0x00000001
 #define B44_FLAG_BUGGY_TXPTR	0x00000002
 #define B44_FLAG_REORDER_BUG	0x00000004
 #define B44_FLAG_PAUSE_AUTO	0x00008000
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 8f46427..49fa1e4 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -2707,7 +2707,7 @@
 
 	if (j == entry_count) {
 		bp->flash_info = NULL;
-		printk(KERN_ALERT "Unknown flash/EEPROM type.\n");
+		printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
 		rc = -ENODEV;
 	}
 
@@ -3903,6 +3903,8 @@
 
 	pkt_size = 1514;
 	skb = dev_alloc_skb(pkt_size);
+	if (!skb)
+		return -ENOMEM;
 	packet = skb_put(skb, pkt_size);
 	memcpy(packet, bp->mac_addr, 6);
 	memset(packet + 6, 0x0, 8);
@@ -4798,11 +4800,7 @@
   	struct bnx2 *bp = dev->priv;
 	int rc;
 
-	if (eeprom->offset > bp->flash_info->total_size)
-		return -EINVAL;
-
-	if ((eeprom->offset + eeprom->len) > bp->flash_info->total_size)
-		eeprom->len = bp->flash_info->total_size - eeprom->offset;
+	/* parameters already validated in ethtool_get_eeprom */
 
 	rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
 
@@ -4816,11 +4814,7 @@
   	struct bnx2 *bp = dev->priv;
 	int rc;
 
-	if (eeprom->offset > bp->flash_info->total_size)
-		return -EINVAL;
-
-	if ((eeprom->offset + eeprom->len) > bp->flash_info->total_size)
-		eeprom->len = bp->flash_info->total_size - eeprom->offset;
+	/* parameters already validated in ethtool_set_eeprom */
 
 	rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
 
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 8032126..94cec3c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1604,35 +1604,27 @@
 	(NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)
 
 /* 
- * Compute the features available to the bonding device by 
- * intersection of all of the slave devices' BOND_INTERSECT_FEATURES.
- * Call this after attaching or detaching a slave to update the 
- * bond's features.
+ * Compute the common dev->feature set available to all slaves.  Some
+ * feature bits are managed elsewhere, so preserve feature bits set on
+ * master device that are not part of the examined set.
  */
 static int bond_compute_features(struct bonding *bond)
 {
-	int i;
+	unsigned long features = BOND_INTERSECT_FEATURES;
 	struct slave *slave;
 	struct net_device *bond_dev = bond->dev;
-	int features = bond->bond_features;
+	int i;
 
-	bond_for_each_slave(bond, slave, i) {
-		struct net_device * slave_dev = slave->dev;
-		if (i == 0) {
-			features |= BOND_INTERSECT_FEATURES;
-		}
-		features &=
-			~(~slave_dev->features & BOND_INTERSECT_FEATURES);
-	}
+	bond_for_each_slave(bond, slave, i)
+		features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
 
-	/* turn off NETIF_F_SG if we need a csum and h/w can't do it */
 	if ((features & NETIF_F_SG) && 
-		!(features & (NETIF_F_IP_CSUM |
-			      NETIF_F_NO_CSUM |
-			      NETIF_F_HW_CSUM))) {
+	    !(features & (NETIF_F_IP_CSUM |
+			  NETIF_F_NO_CSUM |
+			  NETIF_F_HW_CSUM)))
 		features &= ~NETIF_F_SG;
-	}
 
+	features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
 	bond_dev->features = features;
 
 	return 0;
@@ -4561,8 +4553,6 @@
 			       NETIF_F_HW_VLAN_RX |
 			       NETIF_F_HW_VLAN_FILTER);
 
-	bond->bond_features = bond_dev->features;
-
 #ifdef CONFIG_PROC_FS
 	bond_create_proc_entry(bond);
 #endif
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index bbf9da8..1433e91 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -40,8 +40,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION	"2.6.4"
-#define DRV_RELDATE	"September 26, 2005"
+#define DRV_VERSION	"2.6.5"
+#define DRV_RELDATE	"November 4, 2005"
 #define DRV_NAME	"bonding"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
@@ -211,9 +211,6 @@
 	struct   bond_params params;
 	struct   list_head vlan_list;
 	struct   vlan_group *vlgrp;
-	/* the features the bonding device supports, independently 
-	 * of any slaves */
-	int	 bond_features; 
 };
 
 /**
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 50f43db..1f7ca45 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -67,7 +67,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 
 #include <linux/module.h>
 #include <linux/kernel.h>
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index b68b9ca..64105e4 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -409,7 +409,6 @@
 static void e100_rx(struct net_device *dev);
 static int e100_close(struct net_device *dev);
 static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
 static int e100_set_config(struct net_device* dev, struct ifmap* map);
 static void e100_tx_timeout(struct net_device *dev);
 static struct net_device_stats *e100_get_stats(struct net_device *dev);
@@ -436,6 +435,8 @@
 static void e100_clear_network_leds(unsigned long dummy);
 static void e100_set_network_leds(int active);
 
+static struct ethtool_ops e100_ethtool_ops;
+
 static void broadcom_check_speed(struct net_device* dev);
 static void broadcom_check_duplex(struct net_device* dev);
 static void tdk_check_speed(struct net_device* dev);
@@ -495,6 +496,7 @@
 	dev->get_stats          = e100_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 	dev->set_mac_address    = e100_set_mac_address;
+	dev->ethtool_ops	= &e100_ethtool_ops;
 	dev->do_ioctl           = e100_ioctl;
 	dev->set_config		= e100_set_config;
 	dev->tx_timeout         = e100_tx_timeout;
@@ -1448,8 +1450,6 @@
 
 	spin_lock(&np->lock); /* Preempt protection */
 	switch (cmd) {
-		case SIOCETHTOOL:
-			return e100_ethtool_ioctl(dev,ifr);
 		case SIOCGMIIPHY: /* Get PHY address */
 			data->phy_id = mdio_phy_addr;
 			break;
@@ -1486,88 +1486,81 @@
 	return 0;
 }
 
-static int
-e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+static int e100_set_settings(struct net_device *dev,
+			     struct ethtool_cmd *ecmd)
 {
-	struct ethtool_cmd ecmd;
-
-	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
-		return -EFAULT;
-
-	switch (ecmd.cmd) {
-		case ETHTOOL_GSET:
-		{
-			memset((void *) &ecmd, 0, sizeof (ecmd));
-			ecmd.supported =
-			  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+	ecmd->supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
 			  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
 			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
-			ecmd.port = PORT_TP;
-			ecmd.transceiver = XCVR_EXTERNAL;
-			ecmd.phy_address = mdio_phy_addr;
-			ecmd.speed = current_speed;
-			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-			ecmd.advertising = ADVERTISED_TP;
-			if (current_duplex == autoneg && current_speed_selection == 0)
-				ecmd.advertising |= ADVERTISED_Autoneg;
-			else {
-				ecmd.advertising |=
-				  ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
-				  ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
-				if (current_speed_selection == 10)
-					ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
-				else if (current_speed_selection == 100)
-					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
-				if (current_duplex == half)
-					ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
-				else if (current_duplex == full)
-					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
-			}
-			ecmd.autoneg = AUTONEG_ENABLE;
-			if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
-				return -EFAULT;
-		}
-		break;
-		case ETHTOOL_SSET:
-		{
-			if (!capable(CAP_NET_ADMIN)) {
-				return -EPERM;
-			}
-			if (ecmd.autoneg == AUTONEG_ENABLE) {
-				e100_set_duplex(dev, autoneg);
-				e100_set_speed(dev, 0);
-			} else {
-				e100_set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full);
-				e100_set_speed(dev, ecmd.speed == SPEED_10 ? 10: 100);
-			}
-		}
-		break;
-		case ETHTOOL_GDRVINFO:
-		{
-			struct ethtool_drvinfo info;
-			memset((void *) &info, 0, sizeof (info));
-			strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
-			strncpy(info.version, "$Revision: 1.31 $", sizeof(info.version) - 1);
-			strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
-			strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
-			info.regdump_len = 0;
-			info.eedump_len = 0;
-			info.testinfo_len = 0;
-			if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
-				return -EFAULT;
-		}
-		break;
-		case ETHTOOL_NWAY_RST:
-			if (current_duplex == autoneg && current_speed_selection == 0)
-				e100_negotiate(dev);
-		break;
-		default:
-			return -EOPNOTSUPP;
-		break;
+	ecmd->port = PORT_TP;
+	ecmd->transceiver = XCVR_EXTERNAL;
+	ecmd->phy_address = mdio_phy_addr;
+	ecmd->speed = current_speed;
+	ecmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+	ecmd->advertising = ADVERTISED_TP;
+
+	if (current_duplex == autoneg && current_speed_selection == 0)
+		ecmd->advertising |= ADVERTISED_Autoneg;
+	else {
+		ecmd->advertising |=
+			ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+			ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+		if (current_speed_selection == 10)
+			ecmd->advertising &= ~(ADVERTISED_100baseT_Half |
+					       ADVERTISED_100baseT_Full);
+		else if (current_speed_selection == 100)
+			ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
+					       ADVERTISED_10baseT_Full);
+		if (current_duplex == half)
+			ecmd->advertising &= ~(ADVERTISED_10baseT_Full |
+					       ADVERTISED_100baseT_Full);
+		else if (current_duplex == full)
+			ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
+					       ADVERTISED_100baseT_Half);
 	}
+
+	ecmd->autoneg = AUTONEG_ENABLE;
 	return 0;
 }
 
+static int e100_set_settings(struct net_device *dev,
+			     struct ethtool_cmd *ecmd)
+{
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+		e100_set_duplex(dev, autoneg);
+		e100_set_speed(dev, 0);
+	} else {
+		e100_set_duplex(dev, ecmd->duplex == DUPLEX_HALF ? half : full);
+		e100_set_speed(dev, ecmd->speed == SPEED_10 ? 10: 100);
+	}
+
+	return 0;
+}
+
+static void e100_get_drvinfo(struct net_device *dev,
+			     struct ethtool_drvinfo *info)
+{
+	strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 1);
+	strncpy(info->version, "$Revision: 1.31 $", sizeof(info->version) - 1);
+	strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1);
+	strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1);
+}
+
+static int e100_nway_reset(struct net_device *dev)
+{
+	if (current_duplex == autoneg && current_speed_selection == 0)
+		e100_negotiate(dev);
+	return 0;
+}
+
+static struct ethtool_ops e100_ethtool_ops = {
+	.get_settings	= e100_get_settings,
+	.set_settings	= e100_set_settings,
+	.get_drvinfo	= e100_get_drvinfo,
+	.nway_reset	= e100_nway_reset,
+	.get_link	= ethtool_op_get_link,
+};
+
 static int
 e100_set_config(struct net_device *dev, struct ifmap *map)
 {
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 0d33a93..03804cc 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -398,13 +398,19 @@
 };
 #endif
 
-static int depca_isa_probe (struct device *);
+static int depca_isa_probe (struct platform_device *);
 
-static struct device_driver depca_isa_driver = {
-	.name   = depca_string,
-	.bus    = &platform_bus_type,
+static int __devexit depca_isa_remove(struct platform_device *pdev)
+{
+	return depca_device_remove(&pdev->dev);
+}
+
+static struct platform_driver depca_isa_driver = {
 	.probe  = depca_isa_probe,
-	.remove = __devexit_p(depca_device_remove),
+	.remove = __devexit_p(depca_isa_remove),
+	.driver	= {
+		.name   = depca_string,
+	},
 };
 	
 /*
@@ -1525,7 +1531,7 @@
 	return adapter;
 }
 
-static int __init depca_isa_probe (struct device *device)
+static int __init depca_isa_probe (struct platform_device *device)
 {
 	struct net_device *dev;
 	struct depca_private *lp;
@@ -1533,7 +1539,7 @@
 	enum depca_type adapter = unknown;
 	int status = 0;
 
-	ioaddr = (u_long) device->platform_data;
+	ioaddr = (u_long) device->dev.platform_data;
 
 	if ((status = depca_common_init (ioaddr, &dev)))
 		goto out;
@@ -1553,7 +1559,7 @@
 	lp->adapter = adapter;
 	lp->mem_start = mem_start;
 	
-	if ((status = depca_hw_init(dev, device)))
+	if ((status = depca_hw_init(dev, &device->dev)))
 		goto out_free;
 	
 	return 0;
@@ -2082,7 +2088,7 @@
 #ifdef CONFIG_EISA
         err |= eisa_driver_register (&depca_eisa_driver);
 #endif
-	err |= driver_register (&depca_isa_driver);
+	err |= platform_driver_register (&depca_isa_driver);
 	depca_platform_probe ();
 	
         return err;
@@ -2097,7 +2103,7 @@
 #ifdef CONFIG_EISA
         eisa_driver_unregister (&depca_eisa_driver);
 #endif
-	driver_unregister (&depca_isa_driver);
+	platform_driver_unregister (&depca_isa_driver);
 
 	for (i = 0; depca_io_ports[i].iobase; i++) {
 		if (depca_io_ports[i].device) {
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
index 7809838..2a290cc 100644
--- a/drivers/net/dgrs.c
+++ b/drivers/net/dgrs.c
@@ -1549,7 +1549,7 @@
 static int __init dgrs_init_module (void)
 {
 	int	i;
-	int eisacount = 0, pcicount = 0;
+	int	cardcount = 0;
 
 	/*
 	 *	Command line variable overrides
@@ -1591,15 +1591,13 @@
 	 *	Find and configure all the cards
 	 */
 #ifdef CONFIG_EISA
-	eisacount = eisa_driver_register(&dgrs_eisa_driver);
-	if (eisacount < 0)
-		return eisacount;
+	cardcount = eisa_driver_register(&dgrs_eisa_driver);
+	if (cardcount < 0)
+		return cardcount;
 #endif
-#ifdef CONFIG_PCI
-	pcicount = pci_register_driver(&dgrs_pci_driver);
-	if (pcicount)
-		return pcicount;
-#endif
+	cardcount = pci_register_driver(&dgrs_pci_driver);
+	if (cardcount)
+		return cardcount;
 	return 0;
 }
 
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index c0af6fb..24996da 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -60,7 +60,6 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
-#include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
@@ -149,7 +148,7 @@
 } board_info_t;
 
 /* function declaration ------------------------------------- */
-static int dm9000_probe(struct device *);
+static int dm9000_probe(struct platform_device *);
 static int dm9000_open(struct net_device *);
 static int dm9000_start_xmit(struct sk_buff *, struct net_device *);
 static int dm9000_stop(struct net_device *);
@@ -379,9 +378,8 @@
  * Search DM9000 board, allocate space and register it
  */
 static int
-dm9000_probe(struct device *dev)
+dm9000_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct dm9000_plat_data *pdata = pdev->dev.platform_data;
 	struct board_info *db;	/* Point a board information structure */
 	struct net_device *ndev;
@@ -399,7 +397,7 @@
 	}
 
 	SET_MODULE_OWNER(ndev);
-	SET_NETDEV_DEV(ndev, dev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	PRINTK2("dm9000_probe()");
 
@@ -570,7 +568,7 @@
 		printk("%s: Invalid ethernet MAC address.  Please "
 		       "set using ifconfig\n", ndev->name);
 
-	dev_set_drvdata(dev, ndev);
+	platform_set_drvdata(pdev, ndev);
 	ret = register_netdev(ndev);
 
 	if (ret == 0) {
@@ -1141,9 +1139,9 @@
 }
 
 static int
-dm9000_drv_suspend(struct device *dev, pm_message_t state)
+dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct net_device *ndev = dev_get_drvdata(dev);
+	struct net_device *ndev = platform_get_drvdata(dev);
 
 	if (ndev) {
 		if (netif_running(ndev)) {
@@ -1155,9 +1153,9 @@
 }
 
 static int
-dm9000_drv_resume(struct device *dev)
+dm9000_drv_resume(struct platform_device *dev)
 {
-	struct net_device *ndev = dev_get_drvdata(dev);
+	struct net_device *ndev = platform_get_drvdata(dev);
 	board_info_t *db = (board_info_t *) ndev->priv;
 
 	if (ndev) {
@@ -1173,12 +1171,11 @@
 }
 
 static int
-dm9000_drv_remove(struct device *dev)
+dm9000_drv_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct net_device *ndev = dev_get_drvdata(dev);
+	struct net_device *ndev = platform_get_drvdata(pdev);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	unregister_netdev(ndev);
 	dm9000_release_board(pdev, (board_info_t *) ndev->priv);
@@ -1189,13 +1186,14 @@
 	return 0;
 }
 
-static struct device_driver dm9000_driver = {
-	.name    = "dm9000",
-	.bus     = &platform_bus_type,
+static struct platform_driver dm9000_driver = {
 	.probe   = dm9000_probe,
 	.remove  = dm9000_drv_remove,
 	.suspend = dm9000_drv_suspend,
 	.resume  = dm9000_drv_resume,
+	.driver	= {
+		.name	= "dm9000",
+	},
 };
 
 static int __init
@@ -1203,13 +1201,13 @@
 {
 	printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME);
 
-	return driver_register(&dm9000_driver);	/* search board and register */
+	return platform_driver_register(&dm9000_driver);	/* search board and register */
 }
 
 static void __exit
 dm9000_cleanup(void)
 {
-	driver_unregister(&dm9000_driver);
+	platform_driver_unregister(&dm9000_driver);
 }
 
 module_init(dm9000_init);
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index eb169a8..7a6aeae 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1478,7 +1478,7 @@
 
 	if(pci_dma_mapping_error(rx->dma_addr)) {
 		dev_kfree_skb_any(rx->skb);
-		rx->skb = 0;
+		rx->skb = NULL;
 		rx->dma_addr = 0;
 		return -ENOMEM;
 	}
@@ -1764,7 +1764,7 @@
 	if((err = e100_hw_init(nic)))
 		goto err_clean_cbs;
 	e100_set_multicast_list(nic->netdev);
-	e100_start_receiver(nic, 0);
+	e100_start_receiver(nic, NULL);
 	mod_timer(&nic->watchdog, jiffies);
 	if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
 		nic->netdev->name, nic->netdev)))
@@ -1844,7 +1844,7 @@
 		mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
 			BMCR_LOOPBACK);
 
-	e100_start_receiver(nic, 0);
+	e100_start_receiver(nic, NULL);
 
 	if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
 		err = -ENOMEM;
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 22aec6e..525624f 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -80,7 +80,7 @@
  *			   into nv_close, otherwise reenabling for wol can
  *			   cause DMA to kfree'd memory.
  *	0.31: 14 Nov 2004: ethtool support for getting/setting link
- *	                   capabilities.
+ *			   capabilities.
  *	0.32: 16 Apr 2005: RX_ERROR4 handling added.
  *	0.33: 16 May 2005: Support for MCP51 added.
  *	0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
@@ -89,14 +89,17 @@
  *	0.37: 10 Jul 2005: Additional ethtool support, cleanup of pci id list
  *	0.38: 16 Jul 2005: tx irq rewrite: Use global flags instead of
  *			   per-packet flags.
- *      0.39: 18 Jul 2005: Add 64bit descriptor support.
- *      0.40: 19 Jul 2005: Add support for mac address change.
- *      0.41: 30 Jul 2005: Write back original MAC in nv_close instead
+ *	0.39: 18 Jul 2005: Add 64bit descriptor support.
+ *	0.40: 19 Jul 2005: Add support for mac address change.
+ *	0.41: 30 Jul 2005: Write back original MAC in nv_close instead
  *			   of nv_remove
- *      0.42: 06 Aug 2005: Fix lack of link speed initialization
+ *	0.42: 06 Aug 2005: Fix lack of link speed initialization
  *			   in the second (and later) nv_open call
- *      0.43: 10 Aug 2005: Add support for tx checksum.
- *      0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
+ *	0.43: 10 Aug 2005: Add support for tx checksum.
+ *	0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
+ *	0.45: 18 Sep 2005: Remove nv_stop/start_rx from every link check
+ *	0.46: 20 Oct 2005: Add irq optimization modes.
+ *	0.47: 26 Oct 2005: Add phyaddr 0 in phy scan.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -108,7 +111,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION		"0.44"
+#define FORCEDETH_VERSION		"0.47"
 #define DRV_NAME			"forcedeth"
 
 #include <linux/module.h>
@@ -163,7 +166,8 @@
 #define NVREG_IRQ_LINK			0x0040
 #define NVREG_IRQ_TX_ERROR		0x0080
 #define NVREG_IRQ_TX1			0x0100
-#define NVREG_IRQMASK_WANTED		0x00df
+#define NVREG_IRQMASK_THROUGHPUT	0x00df
+#define NVREG_IRQMASK_CPU		0x0040
 
 #define NVREG_IRQ_UNKNOWN	(~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
 					NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \
@@ -177,7 +181,8 @@
  * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
  */
 	NvRegPollingInterval = 0x00c,
-#define NVREG_POLL_DEFAULT	970
+#define NVREG_POLL_DEFAULT_THROUGHPUT	970
+#define NVREG_POLL_DEFAULT_CPU	13
 	NvRegMisc1 = 0x080,
 #define NVREG_MISC1_HD		0x02
 #define NVREG_MISC1_FORCE	0x3b0f3c
@@ -538,6 +543,25 @@
  */
 static int max_interrupt_work = 5;
 
+/*
+ * Optimization can be either throuput mode or cpu mode
+ * 
+ * Throughput Mode: Every tx and rx packet will generate an interrupt.
+ * CPU Mode: Interrupts are controlled by a timer.
+ */
+#define NV_OPTIMIZATION_MODE_THROUGHPUT 0
+#define NV_OPTIMIZATION_MODE_CPU        1
+static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
+
+/*
+ * Poll interval for timer irq
+ *
+ * This interval determines how frequent an interrupt is generated.
+ * The is value is determined by [(time_in_micro_secs * 100) / (2^10)]
+ * Min = 0, and Max = 65535
+ */
+static int poll_interval = -1;
+
 static inline struct fe_priv *get_nvpriv(struct net_device *dev)
 {
 	return netdev_priv(dev);
@@ -1328,67 +1352,71 @@
 			if (!(Flags & NV_RX_DESCRIPTORVALID))
 				goto next_pkt;
 
-			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 (Flags & NV_RX_ERROR) {
+				if (Flags & NV_RX_MISSEDFRAME) {
+					np->stats.rx_missed_errors++;
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
-			}
-			/* framing errors are soft errors. */
-			if (Flags & NV_RX_FRAMINGERR) {
-				if (Flags & NV_RX_SUBSTRACT1) {
-					len--;
+				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) {
+						np->stats.rx_errors++;
+						goto next_pkt;
+					}
+				}
+				/* framing errors are soft errors. */
+				if (Flags & NV_RX_FRAMINGERR) {
+					if (Flags & NV_RX_SUBSTRACT1) {
+						len--;
+					}
 				}
 			}
 		} else {
 			if (!(Flags & NV_RX2_DESCRIPTORVALID))
 				goto next_pkt;
 
-			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 (Flags & NV_RX2_ERROR) {
+				if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
-			}
-			/* framing errors are soft errors */
-			if (Flags & NV_RX2_FRAMINGERR) {
-				if (Flags & NV_RX2_SUBSTRACT1) {
-					len--;
+				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) {
+						np->stats.rx_errors++;
+						goto next_pkt;
+					}
+				}
+				/* framing errors are soft errors */
+				if (Flags & NV_RX2_FRAMINGERR) {
+					if (Flags & NV_RX2_SUBSTRACT1) {
+						len--;
+					}
 				}
 			}
 			Flags &= NV_RX2_CHECKSUMMASK;
@@ -1612,6 +1640,17 @@
 	spin_unlock_irq(&np->lock);
 }
 
+/**
+ * nv_update_linkspeed: Setup the MAC according to the link partner
+ * @dev: Network device to be configured
+ *
+ * The function queries the PHY and checks if there is a link partner.
+ * If yes, then it sets up the MAC accordingly. Otherwise, the MAC is
+ * set to 10 MBit HD.
+ *
+ * The function returns 0 if there is no link partner and 1 if there is
+ * a good link partner.
+ */
 static int nv_update_linkspeed(struct net_device *dev)
 {
 	struct fe_priv *np = netdev_priv(dev);
@@ -1751,13 +1790,11 @@
 static void nv_linkchange(struct net_device *dev)
 {
 	if (nv_update_linkspeed(dev)) {
-		if (netif_carrier_ok(dev)) {
-			nv_stop_rx(dev);
-		} else {
+		if (!netif_carrier_ok(dev)) {
 			netif_carrier_on(dev);
 			printk(KERN_INFO "%s: link up.\n", dev->name);
+			nv_start_rx(dev);
 		}
-		nv_start_rx(dev);
 	} else {
 		if (netif_carrier_ok(dev)) {
 			netif_carrier_off(dev);
@@ -1799,22 +1836,18 @@
 		if (!(events & np->irqmask))
 			break;
 
-		if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_ERR)) {
+		spin_lock(&np->lock);
+		nv_tx_done(dev);
+		spin_unlock(&np->lock);
+		
+		nv_rx_process(dev);
+		if (nv_alloc_rx(dev)) {
 			spin_lock(&np->lock);
-			nv_tx_done(dev);
+			if (!np->in_shutdown)
+				mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
 			spin_unlock(&np->lock);
 		}
-
-		if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
-			nv_rx_process(dev);
-			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);
-			}
-		}
-
+		
 		if (events & NVREG_IRQ_LINK) {
 			spin_lock(&np->lock);
 			nv_link_irq(dev);
@@ -2216,7 +2249,14 @@
 	writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed);
 	writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
 	writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2);
-	writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval);
+	if (poll_interval == -1) {
+		if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT)
+			writel(NVREG_POLL_DEFAULT_THROUGHPUT, base + NvRegPollingInterval);
+		else
+			writel(NVREG_POLL_DEFAULT_CPU, base + NvRegPollingInterval);
+	}
+	else
+		writel(poll_interval & 0xFFFF, base + NvRegPollingInterval);
 	writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
 	writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID|NVREG_ADAPTCTL_RUNNING,
 			base + NvRegAdapterControl);
@@ -2501,7 +2541,11 @@
 	} else {
 		np->tx_flags = NV_TX2_VALID;
 	}
-	np->irqmask = NVREG_IRQMASK_WANTED;
+	if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT)
+		np->irqmask = NVREG_IRQMASK_THROUGHPUT;
+	else
+		np->irqmask = NVREG_IRQMASK_CPU;
+
 	if (id->driver_data & DEV_NEED_TIMERIRQ)
 		np->irqmask |= NVREG_IRQ_TIMER;
 	if (id->driver_data & DEV_NEED_LINKTIMER) {
@@ -2514,16 +2558,17 @@
 	}
 
 	/* find a suitable phy */
-	for (i = 1; i < 32; i++) {
+	for (i = 1; i <= 32; i++) {
 		int id1, id2;
+		int phyaddr = i & 0x1F;
 
 		spin_lock_irq(&np->lock);
-		id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ);
+		id1 = mii_rw(dev, phyaddr, MII_PHYSID1, MII_READ);
 		spin_unlock_irq(&np->lock);
 		if (id1 < 0 || id1 == 0xffff)
 			continue;
 		spin_lock_irq(&np->lock);
-		id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ);
+		id2 = mii_rw(dev, phyaddr, MII_PHYSID2, MII_READ);
 		spin_unlock_irq(&np->lock);
 		if (id2 < 0 || id2 == 0xffff)
 			continue;
@@ -2531,23 +2576,19 @@
 		id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
 		id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
 		dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n",
-				pci_name(pci_dev), id1, id2, i);
-		np->phyaddr = i;
+			pci_name(pci_dev), id1, id2, phyaddr);
+		np->phyaddr = phyaddr;
 		np->phy_oui = id1 | id2;
 		break;
 	}
-	if (i == 32) {
-		/* PHY in isolate mode? No phy attached and user wants to
-		 * test loopback? Very odd, but can be correct.
-		 */
+	if (i == 33) {
 		printk(KERN_INFO "%s: open: Could not find a valid PHY.\n",
-				pci_name(pci_dev));
+		       pci_name(pci_dev));
+		goto out_freering;
 	}
-
-	if (i != 32) {
-		/* reset it */
-		phy_init(dev);
-	}
+	
+	/* reset it */
+	phy_init(dev);
 
 	/* set default link speed settings */
 	np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
@@ -2689,6 +2730,10 @@
 
 module_param(max_interrupt_work, int, 0);
 MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt");
+module_param(optimization_mode, int, 0);
+MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer.");
+module_param(poll_interval, int, 0);
+MODULE_PARM_DESC(poll_interval, "Interval determines how frequent timer interrupt is generated by [(time_in_micro_secs * 100) / (2^10)]. Min is 0 and Max is 65535.");
 
 MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
 MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 9342d5b..f5d49a1 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -37,6 +37,7 @@
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
 #include <linux/fs.h>
+#include <linux/platform_device.h>
 
 #include <linux/vmalloc.h>
 #include <asm/pgtable.h>
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 1105543..e7ec96c 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -4,7 +4,6 @@
 #include <linux/mii.h>
 #include <linux/netdevice.h>
 #include <linux/types.h>
-#include <linux/version.h>
 #include <linux/list.h>
 
 #include <linux/fs_enet_pd.h>
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index a940b96..e67b1d0 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -34,6 +34,7 @@
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
 #include <linux/fs.h>
+#include <linux/platform_device.h>
 
 #include <asm/immap_cpm2.h>
 #include <asm/mpc8260.h>
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 5ef4e84..2e8f444 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -34,6 +34,7 @@
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
 #include <linux/fs.h>
+#include <linux/platform_device.h>
 
 #include <asm/irq.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index d8c6e9c..a3897fd 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -34,6 +34,7 @@
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
 #include <linux/fs.h>
+#include <linux/platform_device.h>
 
 #include <asm/irq.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 962580f..e3a3295 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -90,7 +90,6 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/dma-mapping.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
@@ -127,8 +126,8 @@
 static void adjust_link(struct net_device *dev);
 static void init_registers(struct net_device *dev);
 static int init_phy(struct net_device *dev);
-static int gfar_probe(struct device *device);
-static int gfar_remove(struct device *device);
+static int gfar_probe(struct platform_device *pdev);
+static int gfar_remove(struct platform_device *pdev);
 static void free_skb_resources(struct gfar_private *priv);
 static void gfar_set_multi(struct net_device *dev);
 static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
@@ -157,12 +156,11 @@
 
 /* Set up the ethernet device structure, private data,
  * and anything else we need before we start */
-static int gfar_probe(struct device *device)
+static int gfar_probe(struct platform_device *pdev)
 {
 	u32 tempval;
 	struct net_device *dev = NULL;
 	struct gfar_private *priv = NULL;
-	struct platform_device *pdev = to_platform_device(device);
 	struct gianfar_platform_data *einfo;
 	struct resource *r;
 	int idx;
@@ -209,7 +207,7 @@
 
 	spin_lock_init(&priv->lock);
 
-	dev_set_drvdata(device, dev);
+	platform_set_drvdata(pdev, dev);
 
 	/* Stop the DMA engine now, in case it was running before */
 	/* (The firmware could have used it, and left it running). */
@@ -246,7 +244,7 @@
 	dev->base_addr = (unsigned long) (priv->regs);
 
 	SET_MODULE_OWNER(dev);
-	SET_NETDEV_DEV(dev, device);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/* Fill in the dev structure */
 	dev->open = gfar_enet_open;
@@ -378,12 +376,12 @@
 	return err;
 }
 
-static int gfar_remove(struct device *device)
+static int gfar_remove(struct platform_device *pdev)
 {
-	struct net_device *dev = dev_get_drvdata(device);
+	struct net_device *dev = platform_get_drvdata(pdev);
 	struct gfar_private *priv = netdev_priv(dev);
 
-	dev_set_drvdata(device, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	iounmap((void *) priv->regs);
 	free_netdev(dev);
@@ -1862,11 +1860,12 @@
 }
 
 /* Structure for a device driver */
-static struct device_driver gfar_driver = {
-	.name = "fsl-gianfar",
-	.bus = &platform_bus_type,
+static struct platform_driver gfar_driver = {
 	.probe = gfar_probe,
 	.remove = gfar_remove,
+	.driver	= {
+		.name = "fsl-gianfar",
+	},
 };
 
 static int __init gfar_init(void)
@@ -1876,7 +1875,7 @@
 	if (err)
 		return err;
 
-	err = driver_register(&gfar_driver);
+	err = platform_driver_register(&gfar_driver);
 
 	if (err)
 		gfar_mdio_exit();
@@ -1886,7 +1885,7 @@
 
 static void __exit gfar_exit(void)
 {
-	driver_unregister(&gfar_driver);
+	platform_driver_unregister(&gfar_driver);
 	gfar_mdio_exit();
 }
 
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index c77ca6c..220084e 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -43,7 +43,6 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/crc32.h>
 #include <linux/workqueue.h>
 #include <linux/ethtool.h>
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 68e3578..5a2d810 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -34,7 +34,6 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/crc32.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index 5a74d3d..9544279 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -32,7 +32,6 @@
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/platform_device.h>
 #include <asm/ocp.h>
 #include <linux/crc32.h>
@@ -134,7 +133,7 @@
 	if (NULL == dev)
 		return -EINVAL;
 
-	new_bus = kmalloc(sizeof(struct mii_bus), GFP_KERNEL);
+	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
 
 	if (NULL == new_bus)
 		return -ENOMEM;
diff --git a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c
index 666cfbb..5958a63 100644
--- a/drivers/net/gt96100eth.c
+++ b/drivers/net/gt96100eth.c
@@ -72,8 +72,6 @@
 static void dump_rx_desc(int dbg_lvl, struct net_device *dev, int i);
 static void dump_skb(int dbg_lvl, struct net_device *dev,
 		     struct sk_buff *skb);
-static void dump_hw_addr(int dbg_lvl, struct net_device *dev,
-			 const char* pfx, unsigned char* addr_str);
 static void update_stats(struct gt96100_private *gp);
 static void abort(struct net_device *dev, u32 abort_bits);
 static void hard_stop(struct net_device *dev);
@@ -334,13 +332,13 @@
 
 static void
 dump_hw_addr(int dbg_lvl, struct net_device *dev, const char* pfx,
-	     unsigned char* addr_str)
+	     const char* func, unsigned char* addr_str)
 {
 	int i;
 	char buf[100], octet[5];
     
 	if (dbg_lvl <= GT96100_DEBUG) {
-		strcpy(buf, pfx);
+		sprintf(buf, pfx, func);
 		for (i = 0; i < 6; i++) {
 			sprintf(octet, "%2.2x%s",
 				addr_str[i], i<5 ? ":" : "\n");
@@ -708,7 +706,7 @@
 
 	info("%s found at 0x%x, irq %d\n",
 	     chip_name(gp->chip_rev), gtif->iobase, gtif->irq);
-	dump_hw_addr(0, dev, "HW Address ", dev->dev_addr);
+	dump_hw_addr(0, dev, "%s: HW Address ", __FUNCTION__, dev->dev_addr);
 	info("%s chip revision=%d\n", chip_name(gp->chip_rev), gp->chip_rev);
 	info("%s ethernet port %d\n", chip_name(gp->chip_rev), gp->port_num);
 	info("external PHY ID1=0x%04x, ID2=0x%04x\n", phy_id1, phy_id2);
@@ -1488,7 +1486,7 @@
 		gt96100_add_hash_entry(dev, dev->dev_addr);
 
 		for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) {
-			dump_hw_addr(2, dev, __FUNCTION__ ": addr=",
+			dump_hw_addr(2, dev, "%s: addr=", __FUNCTION__,
 				     mcptr->dmi_addr);
 			gt96100_add_hash_entry(dev, mcptr->dmi_addr);
 		}
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index b71fab6..e92c17f 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -96,7 +96,6 @@
 
 #undef HP100_MULTICAST_FILTER	/* Need to be debugged... */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 94239f6..ceb98fd 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -35,7 +35,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
@@ -59,7 +58,7 @@
 
 #include "ibmveth.h"
 
-#define DEBUG 1
+#undef DEBUG
 
 #define ibmveth_printk(fmt, args...) \
   printk(KERN_INFO "%s: " fmt, __FILE__, ## args)
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 49e5467..6a3129b 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -46,10 +46,8 @@
 #include <linux/udp.h>
 
 #ifdef CONFIG_SERIAL_8250
-#include <linux/serial.h>
-#include <asm/serial.h>
-#define IOC3_BAUD (22000000 / (3*16))
-#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #endif
 
 #include <linux/netdevice.h>
@@ -1146,12 +1144,11 @@
  * around ioc3 oddities in this respect.
  *
  * The IOC3 serials use a 22MHz clock rate with an additional divider by 3.
- * (IOC3_BAUD = (22000000 / (3*16)))
  */
 
 static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
 {
-	struct serial_struct req;
+	struct uart_port port;
 
 	/*
 	 * We need to recognice and treat the fourth MENET serial as it
@@ -1165,20 +1162,25 @@
 	if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3)
 		return;
 
-	/* Register to interrupt zero because we share the interrupt with
-	   the serial driver which we don't properly support yet.  */
-	memset(&req, 0, sizeof(req));
-	req.irq             = 0;
-	req.flags           = IOC3_COM_FLAGS;
-	req.io_type         = SERIAL_IO_MEM;
-	req.iomem_reg_shift = 0;
-	req.baud_base       = IOC3_BAUD;
+	/*
+	 * Register to interrupt zero because we share the interrupt with
+	 * the serial driver which we don't properly support yet.
+	 *
+	 * Can't use UPF_IOREMAP as the whole of IOC3 resources have already
+	 * been registered.
+	 */
+	memset(&port, 0, sizeof(port));
+	port.irq      = 0;
+	port.flags    = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+	port.iotype   = UPIO_MEM;
+	port.regshift = 0;
+	port.uartclk  = 22000000 / 3;
 
-	req.iomem_base      = (unsigned char *) &ioc3->sregs.uarta;
-	register_serial(&req);
+	port.membase  = (unsigned char *) &ioc3->sregs.uarta;
+	serial8250_register_port(&port);
 
-	req.iomem_base      = (unsigned char *) &ioc3->sregs.uartb;
-	register_serial(&req);
+	port.membase  = (unsigned char *) &ioc3->sregs.uartb;
+	serial8250_register_port(&port);
 }
 #endif
 
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 0282771..3137592 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -1459,8 +1459,10 @@
        */
       IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __FUNCTION__
           ,dev->name, INB (OBOE_STATUS), irq->ifr_baudrate );
-      if (!in_interrupt () && !capable (CAP_NET_ADMIN))
-        return -EPERM;
+      if (!in_interrupt () && !capable (CAP_NET_ADMIN)) {
+	ret = -EPERM;
+	goto out;
+      }
 
       /* self->speed=irq->ifr_baudrate; */
       /* toshoboe_setbaud(self); */
@@ -1470,8 +1472,10 @@
     case SIOCSMEDIABUSY:       /* Set media busy */
       IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __FUNCTION__
           ,dev->name, INB (OBOE_STATUS), capable (CAP_NET_ADMIN) );
-      if (!capable (CAP_NET_ADMIN))
-        return -EPERM;
+      if (!capable (CAP_NET_ADMIN)) {
+	ret = -EPERM;
+	goto out;
+      }
       irda_device_set_media_busy (self->netdev, TRUE);
       break;
     case SIOCGRECEIVING:       /* Check if we are receiving right now */
@@ -1483,7 +1487,7 @@
       IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
       ret = -EOPNOTSUPP;
     }
-
+out:
   spin_unlock_irqrestore(&self->spinlock, flags);
   return ret;
 
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 76e0b9f..63d38fb 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -291,9 +291,9 @@
 /*
  * Suspend the IrDA interface.
  */
-static int sa1100_irda_suspend(struct device *_dev, pm_message_t state)
+static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	struct net_device *dev = dev_get_drvdata(_dev);
+	struct net_device *dev = platform_get_drvdata(pdev);
 	struct sa1100_irda *si;
 
 	if (!dev)
@@ -316,9 +316,9 @@
 /*
  * Resume the IrDA interface.
  */
-static int sa1100_irda_resume(struct device *_dev)
+static int sa1100_irda_resume(struct platform_device *pdev)
 {
-	struct net_device *dev = dev_get_drvdata(_dev);
+	struct net_device *dev = platform_get_drvdata(pdev);
 	struct sa1100_irda *si;
 
 	if (!dev)
@@ -886,9 +886,8 @@
 	return io->head ? 0 : -ENOMEM;
 }
 
-static int sa1100_irda_probe(struct device *_dev)
+static int sa1100_irda_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(_dev);
 	struct net_device *dev;
 	struct sa1100_irda *si;
 	unsigned int baudrate_mask;
@@ -967,7 +966,7 @@
 
 	err = register_netdev(dev);
 	if (err == 0)
-		dev_set_drvdata(&pdev->dev, dev);
+		platform_set_drvdata(pdev, dev);
 
 	if (err) {
  err_mem_5:
@@ -985,9 +984,9 @@
 	return err;
 }
 
-static int sa1100_irda_remove(struct device *_dev)
+static int sa1100_irda_remove(struct platform_device *pdev)
 {
-	struct net_device *dev = dev_get_drvdata(_dev);
+	struct net_device *dev = platform_get_drvdata(pdev);
 
 	if (dev) {
 		struct sa1100_irda *si = dev->priv;
@@ -1004,13 +1003,14 @@
 	return 0;
 }
 
-static struct device_driver sa1100ir_driver = {
-	.name		= "sa11x0-ir",
-	.bus		= &platform_bus_type,
+static struct platform_driver sa1100ir_driver = {
 	.probe		= sa1100_irda_probe,
 	.remove		= sa1100_irda_remove,
 	.suspend	= sa1100_irda_suspend,
 	.resume		= sa1100_irda_resume,
+	.driver		= {
+		.name	= "sa11x0-ir",
+	},
 };
 
 static int __init sa1100_irda_init(void)
@@ -1023,12 +1023,12 @@
 	if (power_level > 3)
 		power_level = 3;
 
-	return driver_register(&sa1100ir_driver);
+	return platform_driver_register(&sa1100ir_driver);
 }
 
 static void __exit sa1100_irda_exit(void)
 {
-	driver_unregister(&sa1100ir_driver);
+	platform_driver_unregister(&sa1100ir_driver);
 }
 
 module_init(sa1100_irda_init);
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index a1d207f..ec94ecd 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -214,14 +214,15 @@
 
 /* Power Management */
 
-static int smsc_ircc_suspend(struct device *dev, pm_message_t state);
-static int smsc_ircc_resume(struct device *dev);
+static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state);
+static int smsc_ircc_resume(struct platform_device *dev);
 
-static struct device_driver smsc_ircc_driver = {
-	.name		= SMSC_IRCC2_DRIVER_NAME,
-	.bus		= &platform_bus_type,
+static struct platform_driver smsc_ircc_driver = {
 	.suspend	= smsc_ircc_suspend,
 	.resume		= smsc_ircc_resume,
+	.driver		= {
+		.name	= SMSC_IRCC2_DRIVER_NAME,
+	},
 };
 
 /* Transceivers for SMSC-ircc */
@@ -346,7 +347,7 @@
 
 	IRDA_DEBUG(1, "%s\n", __FUNCTION__);
 
-	ret = driver_register(&smsc_ircc_driver);
+	ret = platform_driver_register(&smsc_ircc_driver);
 	if (ret) {
 		IRDA_ERROR("%s, Can't register driver!\n", driver_name);
 		return ret;
@@ -378,7 +379,7 @@
 	}
 
 	if (ret)
-		driver_unregister(&smsc_ircc_driver);
+		platform_driver_unregister(&smsc_ircc_driver);
 
 	return ret;
 }
@@ -491,7 +492,7 @@
 		err = PTR_ERR(self->pldev);
 		goto err_out5;
 	}
-	dev_set_drvdata(&self->pldev->dev, self);
+	platform_set_drvdata(self->pldev, self);
 
 	IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
 	dev_count++;
@@ -1685,9 +1686,9 @@
 	return 0;
 }
 
-static int smsc_ircc_suspend(struct device *dev, pm_message_t state)
+static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct smsc_ircc_cb *self = dev_get_drvdata(dev);
+	struct smsc_ircc_cb *self = platform_get_drvdata(dev);
 
 	if (!self->io.suspended) {
 		IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
@@ -1706,9 +1707,9 @@
 	return 0;
 }
 
-static int smsc_ircc_resume(struct device *dev)
+static int smsc_ircc_resume(struct platform_device *dev)
 {
-	struct smsc_ircc_cb *self = dev_get_drvdata(dev);
+	struct smsc_ircc_cb *self = platform_get_drvdata(dev);
 
 	if (self->io.suspended) {
 		IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
@@ -1788,7 +1789,7 @@
 			smsc_ircc_close(dev_self[i]);
 	}
 
-	driver_unregister(&smsc_ircc_driver);
+	platform_driver_unregister(&smsc_ircc_driver);
 }
 
 /*
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index d86d8f0..77eadf8 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -58,7 +58,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 2fb3101..b039bd8 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -194,7 +194,7 @@
  * Probe for a SONIC ethernet controller on a Mips Jazz board.
  * Actually probing is superfluous but we're paranoid.
  */
-static int __init jazz_sonic_probe(struct device *device)
+static int __init jazz_sonic_probe(struct platform_device *pdev)
 {
 	struct net_device *dev;
 	struct sonic_local *lp;
@@ -212,8 +212,8 @@
 		return -ENOMEM;
 
 	lp = netdev_priv(dev);
-	lp->device = device;
-	SET_NETDEV_DEV(dev, device);
+	lp->device = &pdev->dev;
+	SET_NETDEV_DEV(dev, &pdev->dev);
  	SET_MODULE_OWNER(dev);
 
 	netdev_boot_setup_check(dev);
@@ -264,9 +264,9 @@
 
 #include "sonic.c"
 
-static int __devexit jazz_sonic_device_remove (struct device *device)
+static int __devexit jazz_sonic_device_remove (struct platform_device *pdev)
 {
-	struct net_device *dev = device->driver_data;
+	struct net_device *dev = platform_get_drvdata(pdev);
 	struct sonic_local* lp = netdev_priv(dev);
 
 	unregister_netdev (dev);
@@ -278,18 +278,19 @@
 	return 0;
 }
 
-static struct device_driver jazz_sonic_driver = {
-	.name	= jazz_sonic_string,
-	.bus	= &platform_bus_type,
+static struct platform_driver jazz_sonic_driver = {
 	.probe	= jazz_sonic_probe,
 	.remove	= __devexit_p(jazz_sonic_device_remove),
+	.driver	= {
+		.name	= jazz_sonic_string,
+	},
 };
 
 static int __init jazz_sonic_init_module(void)
 {
 	int err;
 
-	if ((err = driver_register(&jazz_sonic_driver))) {
+	if ((err = platform_driver_register(&jazz_sonic_driver))) {
 		printk(KERN_ERR "Driver registration failed\n");
 		return err;
 	}
@@ -313,7 +314,7 @@
 
 static void __exit jazz_sonic_cleanup_module(void)
 {
-	driver_unregister(&jazz_sonic_driver);
+	platform_driver_unregister(&jazz_sonic_driver);
 
 	if (jazz_sonic_device) {
 		platform_device_unregister(jazz_sonic_device);
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index ce57618..d8c99f0 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -15,7 +15,6 @@
  * and fixed access to Sonic Sys card which masquerades as a Farallon 
  * by rayk@knightsmanor.org */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index 9ef4592..02d5c68 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -525,7 +525,7 @@
 	return macsonic_init(dev);
 }
 
-static int __init mac_sonic_probe(struct device *device)
+static int __init mac_sonic_probe(struct platform_device *device)
 {
 	struct net_device *dev;
 	struct sonic_local *lp;
@@ -537,8 +537,8 @@
 		return -ENOMEM;
 
 	lp = netdev_priv(dev);
-	lp->device = device;
-	SET_NETDEV_DEV(dev, device);
+	lp->device = &device->dev;
+	SET_NETDEV_DEV(dev, &device->dev);
  	SET_MODULE_OWNER(dev);
 
 	/* This will catch fatal stuff like -ENOMEM as well as success */
@@ -579,9 +579,9 @@
 
 #include "sonic.c"
 
-static int __devexit mac_sonic_device_remove (struct device *device)
+static int __devexit mac_sonic_device_remove (struct platform_device *device)
 {
-	struct net_device *dev = device->driver_data;
+	struct net_device *dev = platform_get_drvdata(device);
 	struct sonic_local* lp = netdev_priv(dev);
 
 	unregister_netdev (dev);
@@ -592,18 +592,19 @@
 	return 0;
 }
 
-static struct device_driver mac_sonic_driver = {
-	.name   = mac_sonic_string,
-	.bus    = &platform_bus_type,
+static struct platform_driver mac_sonic_driver = {
 	.probe  = mac_sonic_probe,
 	.remove = __devexit_p(mac_sonic_device_remove),
+	.driver	= {
+		.name = mac_sonic_string,
+	},
 };
 
 static int __init mac_sonic_init_module(void)
 {
 	int err;
 
-	if ((err = driver_register(&mac_sonic_driver))) {
+	if ((err = platform_driver_register(&mac_sonic_driver))) {
 		printk(KERN_ERR "Driver registration failed\n");
 		return err;
 	}
@@ -628,7 +629,7 @@
 
 static void __exit mac_sonic_cleanup_module(void)
 {
-	driver_unregister(&mac_sonic_driver);
+	platform_driver_unregister(&mac_sonic_driver);
 
 	if (mac_sonic_device) {
 		platform_device_unregister(mac_sonic_device);
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 71f2c67..3cb9b3f 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1387,9 +1387,8 @@
  * Input :	struct device *
  * Output :	-ENOMEM if failed , 0 if success
  */
-static int mv643xx_eth_probe(struct device *ddev)
+static int mv643xx_eth_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(ddev);
 	struct mv643xx_eth_platform_data *pd;
 	int port_num = pdev->id;
 	struct mv643xx_private *mp;
@@ -1402,7 +1401,7 @@
 	if (!dev)
 		return -ENOMEM;
 
-	dev_set_drvdata(ddev, dev);
+	platform_set_drvdata(pdev, dev);
 
 	mp = netdev_priv(dev);
 
@@ -1546,21 +1545,20 @@
 	return err;
 }
 
-static int mv643xx_eth_remove(struct device *ddev)
+static int mv643xx_eth_remove(struct platform_device *pdev)
 {
-	struct net_device *dev = dev_get_drvdata(ddev);
+	struct net_device *dev = platform_get_drvdata(pdev);
 
 	unregister_netdev(dev);
 	flush_scheduled_work();
 
 	free_netdev(dev);
-	dev_set_drvdata(ddev, NULL);
+	platform_set_drvdata(pdev, NULL);
 	return 0;
 }
 
-static int mv643xx_eth_shared_probe(struct device *ddev)
+static int mv643xx_eth_shared_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(ddev);
 	struct resource *res;
 
 	printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n");
@@ -1578,7 +1576,7 @@
 
 }
 
-static int mv643xx_eth_shared_remove(struct device *ddev)
+static int mv643xx_eth_shared_remove(struct platform_device *pdev)
 {
 	iounmap(mv643xx_eth_shared_base);
 	mv643xx_eth_shared_base = NULL;
@@ -1586,18 +1584,20 @@
 	return 0;
 }
 
-static struct device_driver mv643xx_eth_driver = {
-	.name = MV643XX_ETH_NAME,
-	.bus = &platform_bus_type,
+static struct platform_driver mv643xx_eth_driver = {
 	.probe = mv643xx_eth_probe,
 	.remove = mv643xx_eth_remove,
+	.driver = {
+		.name = MV643XX_ETH_NAME,
+	},
 };
 
-static struct device_driver mv643xx_eth_shared_driver = {
-	.name = MV643XX_ETH_SHARED_NAME,
-	.bus = &platform_bus_type,
+static struct platform_driver mv643xx_eth_shared_driver = {
 	.probe = mv643xx_eth_shared_probe,
 	.remove = mv643xx_eth_shared_remove,
+	.driver = {
+		.name = MV643XX_ETH_SHARED_NAME,
+	},
 };
 
 /*
@@ -1613,11 +1613,11 @@
 {
 	int rc;
 
-	rc = driver_register(&mv643xx_eth_shared_driver);
+	rc = platform_driver_register(&mv643xx_eth_shared_driver);
 	if (!rc) {
-		rc = driver_register(&mv643xx_eth_driver);
+		rc = platform_driver_register(&mv643xx_eth_driver);
 		if (rc)
-			driver_unregister(&mv643xx_eth_shared_driver);
+			platform_driver_unregister(&mv643xx_eth_shared_driver);
 	}
 	return rc;
 }
@@ -1633,8 +1633,8 @@
  */
 static void __exit mv643xx_cleanup_module(void)
 {
-	driver_unregister(&mv643xx_eth_driver);
-	driver_unregister(&mv643xx_eth_shared_driver);
+	platform_driver_unregister(&mv643xx_eth_driver);
+	platform_driver_unregister(&mv643xx_eth_shared_driver);
 }
 
 module_init(mv643xx_init_module);
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index bcfda51..f769f9b 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -1,7 +1,6 @@
 #ifndef __MV643XX_ETH_H__
 #define __MV643XX_ETH_H__
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index a3c3fc9..f857ae9 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -110,7 +110,6 @@
 #include <linux/init.h>
 #include <linux/ip.h>	/* for iph */
 #include <linux/in.h>	/* for IPPROTO_... */
-#include <linux/eeprom.h>
 #include <linux/compiler.h>
 #include <linux/prefetch.h>
 #include <linux/ethtool.h>
@@ -445,7 +444,6 @@
 
 	u32			MEAR_cache;
 	u32			IMR_cache;
-	struct eeprom		ee;
 
 	unsigned		linkstate;
 
@@ -1558,15 +1556,13 @@
 	unsigned i;
 	for (i=0; i<3; i++) {
 		u32 data;
-#if 0	/* I've left this in as an example of how to use eeprom.h */
-		data = eeprom_readw(&dev->ee, 0xa + 2 - i);
-#else
+
 		/* Read from the perfect match memory: this is loaded by
 		 * the chip from the EEPROM via the EELOAD self test.
 		 */
 		writel(i*2, dev->base + RFCR);
 		data = readl(dev->base + RFDR);
-#endif
+
 		*mac++ = data;
 		*mac++ = data >> 8;
 	}
@@ -1851,8 +1847,6 @@
 	spin_lock_init(&dev->misc_lock);
 	dev->pci_dev = pci_dev;
 
-	dev->ee.cache = &dev->MEAR_cache;
-	dev->ee.lock = &dev->misc_lock;
 	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, &pci_dev->dev);
 
@@ -1887,9 +1881,6 @@
 
 	dev->IMR_cache = 0;
 
-	setup_ee_mem_bitbanger(&dev->ee, dev->base + MEAR, 3, 2, 1, 0,
-		0);
-
 	err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ,
 			  DRV_NAME, ndev);
 	if (err) {
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 59e8183..400f652 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -31,6 +31,7 @@
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
+#include <asm/string.h>
 
 #define PPP_VERSION	"2.4.2"
 
@@ -835,8 +836,11 @@
  err:
 	/* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */
 	ap->state = SC_PREV_ERROR;
-	if (skb)
+	if (skb) {
+		/* make skb appear as freshly allocated */
 		skb_trim(skb, 0);
+		skb_reserve(skb, - skb_headroom(skb));
+	}
 }
 
 /* Called when the tty driver has data for us. Runs parallel with the
@@ -889,10 +893,17 @@
 				skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
 				if (skb == 0)
 					goto nomem;
-				/* Try to get the payload 4-byte aligned */
+ 				ap->rpkt = skb;
+ 			}
+ 			if (skb->len == 0) {
+ 				/* Try to get the payload 4-byte aligned.
+ 				 * This should match the
+ 				 * PPP_ALLSTATIONS/PPP_UI/compressed tests in
+ 				 * process_input_packet, but we do not have
+ 				 * enough chars here to test buf[1] and buf[2].
+ 				 */
 				if (buf[0] != PPP_ALLSTATIONS)
 					skb_reserve(skb, 2 + (buf[0] & 1));
-				ap->rpkt = skb;
 			}
 			if (n > skb_tailroom(skb)) {
 				/* packet overflowed MRU */
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index d3c9958..50430f7 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -137,13 +137,14 @@
 
 /*
  * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC,
- * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP.
+ * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP,
+ * SC_MUST_COMP
  * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
  * Bits in xstate: SC_COMP_RUN
  */
 #define SC_FLAG_BITS	(SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \
 			 |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \
-			 |SC_COMP_TCP|SC_REJ_COMP_TCP)
+			 |SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP)
 
 /*
  * Private data structure for each channel.
@@ -1027,6 +1028,56 @@
 	ppp_xmit_unlock(ppp);
 }
 
+static inline struct sk_buff *
+pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
+{
+	struct sk_buff *new_skb;
+	int len;
+	int new_skb_size = ppp->dev->mtu +
+		ppp->xcomp->comp_extra + ppp->dev->hard_header_len;
+	int compressor_skb_size = ppp->dev->mtu +
+		ppp->xcomp->comp_extra + PPP_HDRLEN;
+	new_skb = alloc_skb(new_skb_size, GFP_ATOMIC);
+	if (!new_skb) {
+		if (net_ratelimit())
+			printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+		return NULL;
+	}
+	if (ppp->dev->hard_header_len > PPP_HDRLEN)
+		skb_reserve(new_skb,
+			    ppp->dev->hard_header_len - PPP_HDRLEN);
+
+	/* compressor still expects A/C bytes in hdr */
+	len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
+				   new_skb->data, skb->len + 2,
+				   compressor_skb_size);
+	if (len > 0 && (ppp->flags & SC_CCP_UP)) {
+		kfree_skb(skb);
+		skb = new_skb;
+		skb_put(skb, len);
+		skb_pull(skb, 2);	/* pull off A/C bytes */
+	} else if (len == 0) {
+		/* didn't compress, or CCP not up yet */
+		kfree_skb(new_skb);
+		new_skb = skb;
+	} else {
+		/*
+		 * (len < 0)
+		 * MPPE requires that we do not send unencrypted
+		 * frames.  The compressor will return -1 if we
+		 * should drop the frame.  We cannot simply test
+		 * the compress_proto because MPPE and MPPC share
+		 * the same number.
+		 */
+		if (net_ratelimit())
+			printk(KERN_ERR "ppp: compressor dropped pkt\n");
+		kfree_skb(skb);
+		kfree_skb(new_skb);
+		new_skb = NULL;
+	}
+	return new_skb;
+}
+
 /*
  * Compress and send a frame.
  * The caller should have locked the xmit path,
@@ -1113,29 +1164,14 @@
 	/* try to do packet compression */
 	if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
 	    && proto != PPP_LCP && proto != PPP_CCP) {
-		new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len,
-				    GFP_ATOMIC);
-		if (new_skb == 0) {
-			printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+		if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) {
+			if (net_ratelimit())
+				printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n");
 			goto drop;
 		}
-		if (ppp->dev->hard_header_len > PPP_HDRLEN)
-			skb_reserve(new_skb,
-				    ppp->dev->hard_header_len - PPP_HDRLEN);
-
-		/* compressor still expects A/C bytes in hdr */
-		len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
-					   new_skb->data, skb->len + 2,
-					   ppp->dev->mtu + PPP_HDRLEN);
-		if (len > 0 && (ppp->flags & SC_CCP_UP)) {
-			kfree_skb(skb);
-			skb = new_skb;
-			skb_put(skb, len);
-			skb_pull(skb, 2);	/* pull off A/C bytes */
-		} else {
-			/* didn't compress, or CCP not up yet */
-			kfree_skb(new_skb);
-		}
+		skb = pad_compress_skb(ppp, skb);
+		if (!skb)
+			goto drop;
 	}
 
 	/*
@@ -1155,7 +1191,8 @@
 	return;
 
  drop:
-	kfree_skb(skb);
+	if (skb)
+		kfree_skb(skb);
 	++ppp->stats.tx_errors;
 }
 
@@ -1552,6 +1589,9 @@
 	    && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)
 		skb = ppp_decompress_frame(ppp, skb);
 
+	if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR)
+		goto err;
+
 	proto = PPP_PROTO(skb);
 	switch (proto) {
 	case PPP_VJC_COMP:
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
new file mode 100644
index 0000000..1985d1b
--- /dev/null
+++ b/drivers/net/ppp_mppe.c
@@ -0,0 +1,724 @@
+/*
+ * ppp_mppe.c - interface MPPE to the PPP code.
+ * This version is for use with Linux kernel 2.6.14+
+ *
+ * By Frank Cusack <fcusack@fcusack.com>.
+ * Copyright (c) 2002,2003,2004 Google, Inc.
+ * All rights reserved.
+ *
+ * License:
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ *   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
+ *
+ *
+ * Changelog:
+ *      08/12/05 - Matt Domsch <Matt_Domsch@dell.com>
+ *                 Only need extra skb padding on transmit, not receive.
+ *      06/18/04 - Matt Domsch <Matt_Domsch@dell.com>, Oleg Makarenko <mole@quadra.ru>
+ *                 Use Linux kernel 2.6 arc4 and sha1 routines rather than
+ *                 providing our own.
+ *      2/15/04 - TS: added #include <version.h> and testing for Kernel
+ *                    version before using
+ *                    MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are
+ *                    deprecated in 2.6
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/ppp_defs.h>
+#include <linux/ppp-comp.h>
+#include <asm/scatterlist.h>
+
+#include "ppp_mppe.h"
+
+MODULE_AUTHOR("Frank Cusack <fcusack@fcusack.com>");
+MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
+MODULE_VERSION("1.0.2");
+
+static void
+setup_sg(struct scatterlist *sg, const void *address, unsigned int length)
+{
+	sg[0].page = virt_to_page(address);
+	sg[0].offset = offset_in_page(address);
+	sg[0].length = length;
+}
+
+#define SHA1_PAD_SIZE 40
+
+/*
+ * kernel crypto API needs its arguments to be in kmalloc'd memory, not in the module
+ * static data area.  That means sha_pad needs to be kmalloc'd.
+ */
+
+struct sha_pad {
+	unsigned char sha_pad1[SHA1_PAD_SIZE];
+	unsigned char sha_pad2[SHA1_PAD_SIZE];
+};
+static struct sha_pad *sha_pad;
+
+static inline void sha_pad_init(struct sha_pad *shapad)
+{
+	memset(shapad->sha_pad1, 0x00, sizeof(shapad->sha_pad1));
+	memset(shapad->sha_pad2, 0xF2, sizeof(shapad->sha_pad2));
+}
+
+/*
+ * State for an MPPE (de)compressor.
+ */
+struct ppp_mppe_state {
+	struct crypto_tfm *arc4;
+	struct crypto_tfm *sha1;
+	unsigned char *sha1_digest;
+	unsigned char master_key[MPPE_MAX_KEY_LEN];
+	unsigned char session_key[MPPE_MAX_KEY_LEN];
+	unsigned keylen;	/* key length in bytes             */
+	/* NB: 128-bit == 16, 40-bit == 8! */
+	/* If we want to support 56-bit,   */
+	/* the unit has to change to bits  */
+	unsigned char bits;	/* MPPE control bits */
+	unsigned ccount;	/* 12-bit coherency count (seqno)  */
+	unsigned stateful;	/* stateful mode flag */
+	int discard;		/* stateful mode packet loss flag */
+	int sanity_errors;	/* take down LCP if too many */
+	int unit;
+	int debug;
+	struct compstat stats;
+};
+
+/* struct ppp_mppe_state.bits definitions */
+#define MPPE_BIT_A	0x80	/* Encryption table were (re)inititalized */
+#define MPPE_BIT_B	0x40	/* MPPC only (not implemented) */
+#define MPPE_BIT_C	0x20	/* MPPC only (not implemented) */
+#define MPPE_BIT_D	0x10	/* This is an encrypted frame */
+
+#define MPPE_BIT_FLUSHED	MPPE_BIT_A
+#define MPPE_BIT_ENCRYPTED	MPPE_BIT_D
+
+#define MPPE_BITS(p) ((p)[4] & 0xf0)
+#define MPPE_CCOUNT(p) ((((p)[4] & 0x0f) << 8) + (p)[5])
+#define MPPE_CCOUNT_SPACE 0x1000	/* The size of the ccount space */
+
+#define MPPE_OVHD	2	/* MPPE overhead/packet */
+#define SANITY_MAX	1600	/* Max bogon factor we will tolerate */
+
+/*
+ * Key Derivation, from RFC 3078, RFC 3079.
+ * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
+ */
+static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey)
+{
+	struct scatterlist sg[4];
+
+	setup_sg(&sg[0], state->master_key, state->keylen);
+	setup_sg(&sg[1], sha_pad->sha_pad1, sizeof(sha_pad->sha_pad1));
+	setup_sg(&sg[2], state->session_key, state->keylen);
+	setup_sg(&sg[3], sha_pad->sha_pad2, sizeof(sha_pad->sha_pad2));
+
+	crypto_digest_digest (state->sha1, sg, 4, state->sha1_digest);
+
+	memcpy(InterimKey, state->sha1_digest, state->keylen);
+}
+
+/*
+ * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3.
+ * Well, not what's written there, but rather what they meant.
+ */
+static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
+{
+	unsigned char InterimKey[MPPE_MAX_KEY_LEN];
+	struct scatterlist sg_in[1], sg_out[1];
+
+	get_new_key_from_sha(state, InterimKey);
+	if (!initial_key) {
+		crypto_cipher_setkey(state->arc4, InterimKey, state->keylen);
+		setup_sg(sg_in, InterimKey, state->keylen);
+		setup_sg(sg_out, state->session_key, state->keylen);
+		if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in,
+				      state->keylen) != 0) {
+    		    printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
+		}
+	} else {
+		memcpy(state->session_key, InterimKey, state->keylen);
+	}
+	if (state->keylen == 8) {
+		/* See RFC 3078 */
+		state->session_key[0] = 0xd1;
+		state->session_key[1] = 0x26;
+		state->session_key[2] = 0x9e;
+	}
+	crypto_cipher_setkey(state->arc4, state->session_key, state->keylen);
+}
+
+/*
+ * Allocate space for a (de)compressor.
+ */
+static void *mppe_alloc(unsigned char *options, int optlen)
+{
+	struct ppp_mppe_state *state;
+	unsigned int digestsize;
+
+	if (optlen != CILEN_MPPE + sizeof(state->master_key)
+	    || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
+		goto out;
+
+	state = (struct ppp_mppe_state *) kmalloc(sizeof(*state), GFP_KERNEL);
+	if (state == NULL)
+		goto out;
+
+	memset(state, 0, sizeof(*state));
+
+	state->arc4 = crypto_alloc_tfm("arc4", 0);
+	if (!state->arc4)
+		goto out_free;
+
+	state->sha1 = crypto_alloc_tfm("sha1", 0);
+	if (!state->sha1)
+		goto out_free;
+
+	digestsize = crypto_tfm_alg_digestsize(state->sha1);
+	if (digestsize < MPPE_MAX_KEY_LEN)
+		goto out_free;
+
+	state->sha1_digest = kmalloc(digestsize, GFP_KERNEL);
+	if (!state->sha1_digest)
+		goto out_free;
+
+	/* Save keys. */
+	memcpy(state->master_key, &options[CILEN_MPPE],
+	       sizeof(state->master_key));
+	memcpy(state->session_key, state->master_key,
+	       sizeof(state->master_key));
+
+	/*
+	 * We defer initial key generation until mppe_init(), as mppe_alloc()
+	 * is called frequently during negotiation.
+	 */
+
+	return (void *)state;
+
+	out_free:
+	    if (state->sha1_digest)
+		kfree(state->sha1_digest);
+	    if (state->sha1)
+		crypto_free_tfm(state->sha1);
+	    if (state->arc4)
+		crypto_free_tfm(state->arc4);
+	    kfree(state);
+	out:
+	return NULL;
+}
+
+/*
+ * Deallocate space for a (de)compressor.
+ */
+static void mppe_free(void *arg)
+{
+	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+	if (state) {
+	    if (state->sha1_digest)
+		kfree(state->sha1_digest);
+	    if (state->sha1)
+		crypto_free_tfm(state->sha1);
+	    if (state->arc4)
+		crypto_free_tfm(state->arc4);
+	    kfree(state);
+	}
+}
+
+/*
+ * Initialize (de)compressor state.
+ */
+static int
+mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug,
+	  const char *debugstr)
+{
+	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+	unsigned char mppe_opts;
+
+	if (optlen != CILEN_MPPE
+	    || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
+		return 0;
+
+	MPPE_CI_TO_OPTS(&options[2], mppe_opts);
+	if (mppe_opts & MPPE_OPT_128)
+		state->keylen = 16;
+	else if (mppe_opts & MPPE_OPT_40)
+		state->keylen = 8;
+	else {
+		printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr,
+		       unit);
+		return 0;
+	}
+	if (mppe_opts & MPPE_OPT_STATEFUL)
+		state->stateful = 1;
+
+	/* Generate the initial session key. */
+	mppe_rekey(state, 1);
+
+	if (debug) {
+		int i;
+		char mkey[sizeof(state->master_key) * 2 + 1];
+		char skey[sizeof(state->session_key) * 2 + 1];
+
+		printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n",
+		       debugstr, unit, (state->keylen == 16) ? 128 : 40,
+		       (state->stateful) ? "stateful" : "stateless");
+
+		for (i = 0; i < sizeof(state->master_key); i++)
+			sprintf(mkey + i * 2, "%02x", state->master_key[i]);
+		for (i = 0; i < sizeof(state->session_key); i++)
+			sprintf(skey + i * 2, "%02x", state->session_key[i]);
+		printk(KERN_DEBUG
+		       "%s[%d]: keys: master: %s initial session: %s\n",
+		       debugstr, unit, mkey, skey);
+	}
+
+	/*
+	 * Initialize the coherency count.  The initial value is not specified
+	 * in RFC 3078, but we can make a reasonable assumption that it will
+	 * start at 0.  Setting it to the max here makes the comp/decomp code
+	 * do the right thing (determined through experiment).
+	 */
+	state->ccount = MPPE_CCOUNT_SPACE - 1;
+
+	/*
+	 * Note that even though we have initialized the key table, we don't
+	 * set the FLUSHED bit.  This is contrary to RFC 3078, sec. 3.1.
+	 */
+	state->bits = MPPE_BIT_ENCRYPTED;
+
+	state->unit = unit;
+	state->debug = debug;
+
+	return 1;
+}
+
+static int
+mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit,
+	       int hdrlen, int debug)
+{
+	/* ARGSUSED */
+	return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init");
+}
+
+/*
+ * We received a CCP Reset-Request (actually, we are sending a Reset-Ack),
+ * tell the compressor to rekey.  Note that we MUST NOT rekey for
+ * every CCP Reset-Request; we only rekey on the next xmit packet.
+ * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost.
+ * So, rekeying for every CCP Reset-Request is broken as the peer will not
+ * know how many times we've rekeyed.  (If we rekey and THEN get another
+ * CCP Reset-Request, we must rekey again.)
+ */
+static void mppe_comp_reset(void *arg)
+{
+	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+
+	state->bits |= MPPE_BIT_FLUSHED;
+}
+
+/*
+ * Compress (encrypt) a packet.
+ * It's strange to call this a compressor, since the output is always
+ * MPPE_OVHD + 2 bytes larger than the input.
+ */
+static int
+mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
+	      int isize, int osize)
+{
+	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+	int proto;
+	struct scatterlist sg_in[1], sg_out[1];
+
+	/*
+	 * Check that the protocol is in the range we handle.
+	 */
+	proto = PPP_PROTOCOL(ibuf);
+	if (proto < 0x0021 || proto > 0x00fa)
+		return 0;
+
+	/* Make sure we have enough room to generate an encrypted packet. */
+	if (osize < isize + MPPE_OVHD + 2) {
+		/* Drop the packet if we should encrypt it, but can't. */
+		printk(KERN_DEBUG "mppe_compress[%d]: osize too small! "
+		       "(have: %d need: %d)\n", state->unit,
+		       osize, osize + MPPE_OVHD + 2);
+		return -1;
+	}
+
+	osize = isize + MPPE_OVHD + 2;
+
+	/*
+	 * Copy over the PPP header and set control bits.
+	 */
+	obuf[0] = PPP_ADDRESS(ibuf);
+	obuf[1] = PPP_CONTROL(ibuf);
+	obuf[2] = PPP_COMP >> 8;	/* isize + MPPE_OVHD + 1 */
+	obuf[3] = PPP_COMP;	/* isize + MPPE_OVHD + 2 */
+	obuf += PPP_HDRLEN;
+
+	state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
+	if (state->debug >= 7)
+		printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit,
+		       state->ccount);
+	obuf[0] = state->ccount >> 8;
+	obuf[1] = state->ccount & 0xff;
+
+	if (!state->stateful ||	/* stateless mode     */
+	    ((state->ccount & 0xff) == 0xff) ||	/* "flag" packet      */
+	    (state->bits & MPPE_BIT_FLUSHED)) {	/* CCP Reset-Request  */
+		/* We must rekey */
+		if (state->debug && state->stateful)
+			printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n",
+			       state->unit);
+		mppe_rekey(state, 0);
+		state->bits |= MPPE_BIT_FLUSHED;
+	}
+	obuf[0] |= state->bits;
+	state->bits &= ~MPPE_BIT_FLUSHED;	/* reset for next xmit */
+
+	obuf += MPPE_OVHD;
+	ibuf += 2;		/* skip to proto field */
+	isize -= 2;
+
+	/* Encrypt packet */
+	setup_sg(sg_in, ibuf, isize);
+	setup_sg(sg_out, obuf, osize);
+	if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in, isize) != 0) {
+		printk(KERN_DEBUG "crypto_cypher_encrypt failed\n");
+		return -1;
+	}
+
+	state->stats.unc_bytes += isize;
+	state->stats.unc_packets++;
+	state->stats.comp_bytes += osize;
+	state->stats.comp_packets++;
+
+	return osize;
+}
+
+/*
+ * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going
+ * to look bad ... and the longer the link is up the worse it will get.
+ */
+static void mppe_comp_stats(void *arg, struct compstat *stats)
+{
+	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+
+	*stats = state->stats;
+}
+
+static int
+mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit,
+		 int hdrlen, int mru, int debug)
+{
+	/* ARGSUSED */
+	return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init");
+}
+
+/*
+ * We received a CCP Reset-Ack.  Just ignore it.
+ */
+static void mppe_decomp_reset(void *arg)
+{
+	/* ARGSUSED */
+	return;
+}
+
+/*
+ * Decompress (decrypt) an MPPE packet.
+ */
+static int
+mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
+		int osize)
+{
+	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+	unsigned ccount;
+	int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
+	int sanity = 0;
+	struct scatterlist sg_in[1], sg_out[1];
+
+	if (isize <= PPP_HDRLEN + MPPE_OVHD) {
+		if (state->debug)
+			printk(KERN_DEBUG
+			       "mppe_decompress[%d]: short pkt (%d)\n",
+			       state->unit, isize);
+		return DECOMP_ERROR;
+	}
+
+	/*
+	 * Make sure we have enough room to decrypt the packet.
+	 * Note that for our test we only subtract 1 byte whereas in
+	 * mppe_compress() we added 2 bytes (+MPPE_OVHD);
+	 * this is to account for possible PFC.
+	 */
+	if (osize < isize - MPPE_OVHD - 1) {
+		printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! "
+		       "(have: %d need: %d)\n", state->unit,
+		       osize, isize - MPPE_OVHD - 1);
+		return DECOMP_ERROR;
+	}
+	osize = isize - MPPE_OVHD - 2;	/* assume no PFC */
+
+	ccount = MPPE_CCOUNT(ibuf);
+	if (state->debug >= 7)
+		printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n",
+		       state->unit, ccount);
+
+	/* sanity checks -- terminate with extreme prejudice */
+	if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) {
+		printk(KERN_DEBUG
+		       "mppe_decompress[%d]: ENCRYPTED bit not set!\n",
+		       state->unit);
+		state->sanity_errors += 100;
+		sanity = 1;
+	}
+	if (!state->stateful && !flushed) {
+		printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in "
+		       "stateless mode!\n", state->unit);
+		state->sanity_errors += 100;
+		sanity = 1;
+	}
+	if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) {
+		printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on "
+		       "flag packet!\n", state->unit);
+		state->sanity_errors += 100;
+		sanity = 1;
+	}
+
+	if (sanity) {
+		if (state->sanity_errors < SANITY_MAX)
+			return DECOMP_ERROR;
+		else
+			/*
+			 * Take LCP down if the peer is sending too many bogons.
+			 * We don't want to do this for a single or just a few
+			 * instances since it could just be due to packet corruption.
+			 */
+			return DECOMP_FATALERROR;
+	}
+
+	/*
+	 * Check the coherency count.
+	 */
+
+	if (!state->stateful) {
+		/* RFC 3078, sec 8.1.  Rekey for every packet. */
+		while (state->ccount != ccount) {
+			mppe_rekey(state, 0);
+			state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
+		}
+	} else {
+		/* RFC 3078, sec 8.2. */
+		if (!state->discard) {
+			/* normal state */
+			state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
+			if (ccount != state->ccount) {
+				/*
+				 * (ccount > state->ccount)
+				 * Packet loss detected, enter the discard state.
+				 * Signal the peer to rekey (by sending a CCP Reset-Request).
+				 */
+				state->discard = 1;
+				return DECOMP_ERROR;
+			}
+		} else {
+			/* discard state */
+			if (!flushed) {
+				/* ccp.c will be silent (no additional CCP Reset-Requests). */
+				return DECOMP_ERROR;
+			} else {
+				/* Rekey for every missed "flag" packet. */
+				while ((ccount & ~0xff) !=
+				       (state->ccount & ~0xff)) {
+					mppe_rekey(state, 0);
+					state->ccount =
+					    (state->ccount +
+					     256) % MPPE_CCOUNT_SPACE;
+				}
+
+				/* reset */
+				state->discard = 0;
+				state->ccount = ccount;
+				/*
+				 * Another problem with RFC 3078 here.  It implies that the
+				 * peer need not send a Reset-Ack packet.  But RFC 1962
+				 * requires it.  Hopefully, M$ does send a Reset-Ack; even
+				 * though it isn't required for MPPE synchronization, it is
+				 * required to reset CCP state.
+				 */
+			}
+		}
+		if (flushed)
+			mppe_rekey(state, 0);
+	}
+
+	/*
+	 * Fill in the first part of the PPP header.  The protocol field
+	 * comes from the decrypted data.
+	 */
+	obuf[0] = PPP_ADDRESS(ibuf);	/* +1 */
+	obuf[1] = PPP_CONTROL(ibuf);	/* +1 */
+	obuf += 2;
+	ibuf += PPP_HDRLEN + MPPE_OVHD;
+	isize -= PPP_HDRLEN + MPPE_OVHD;	/* -6 */
+	/* net osize: isize-4 */
+
+	/*
+	 * Decrypt the first byte in order to check if it is
+	 * a compressed or uncompressed protocol field.
+	 */
+	setup_sg(sg_in, ibuf, 1);
+	setup_sg(sg_out, obuf, 1);
+	if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, 1) != 0) {
+		printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
+		return DECOMP_ERROR;
+	}
+
+	/*
+	 * Do PFC decompression.
+	 * This would be nicer if we were given the actual sk_buff
+	 * instead of a char *.
+	 */
+	if ((obuf[0] & 0x01) != 0) {
+		obuf[1] = obuf[0];
+		obuf[0] = 0;
+		obuf++;
+		osize++;
+	}
+
+	/* And finally, decrypt the rest of the packet. */
+	setup_sg(sg_in, ibuf + 1, isize - 1);
+	setup_sg(sg_out, obuf + 1, osize - 1);
+	if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, isize - 1) != 0) {
+		printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
+		return DECOMP_ERROR;
+	}
+
+	state->stats.unc_bytes += osize;
+	state->stats.unc_packets++;
+	state->stats.comp_bytes += isize;
+	state->stats.comp_packets++;
+
+	/* good packet credit */
+	state->sanity_errors >>= 1;
+
+	return osize;
+}
+
+/*
+ * Incompressible data has arrived (this should never happen!).
+ * We should probably drop the link if the protocol is in the range
+ * of what should be encrypted.  At the least, we should drop this
+ * packet.  (How to do this?)
+ */
+static void mppe_incomp(void *arg, unsigned char *ibuf, int icnt)
+{
+	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+
+	if (state->debug &&
+	    (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa))
+		printk(KERN_DEBUG
+		       "mppe_incomp[%d]: incompressible (unencrypted) data! "
+		       "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf));
+
+	state->stats.inc_bytes += icnt;
+	state->stats.inc_packets++;
+	state->stats.unc_bytes += icnt;
+	state->stats.unc_packets++;
+}
+
+/*************************************************************
+ * Module interface table
+ *************************************************************/
+
+/*
+ * Procedures exported to if_ppp.c.
+ */
+static struct compressor ppp_mppe = {
+	.compress_proto = CI_MPPE,
+	.comp_alloc     = mppe_alloc,
+	.comp_free      = mppe_free,
+	.comp_init      = mppe_comp_init,
+	.comp_reset     = mppe_comp_reset,
+	.compress       = mppe_compress,
+	.comp_stat      = mppe_comp_stats,
+	.decomp_alloc   = mppe_alloc,
+	.decomp_free    = mppe_free,
+	.decomp_init    = mppe_decomp_init,
+	.decomp_reset   = mppe_decomp_reset,
+	.decompress     = mppe_decompress,
+	.incomp         = mppe_incomp,
+	.decomp_stat    = mppe_comp_stats,
+	.owner          = THIS_MODULE,
+	.comp_extra     = MPPE_PAD,
+};
+
+/*
+ * ppp_mppe_init()
+ *
+ * Prior to allowing load, try to load the arc4 and sha1 crypto
+ * libraries.  The actual use will be allocated later, but
+ * this way the module will fail to insmod if they aren't available.
+ */
+
+static int __init ppp_mppe_init(void)
+{
+	int answer;
+	if (!(crypto_alg_available("arc4", 0) &&
+	      crypto_alg_available("sha1", 0)))
+		return -ENODEV;
+
+	sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
+	if (!sha_pad)
+		return -ENOMEM;
+	sha_pad_init(sha_pad);
+
+	answer = ppp_register_compressor(&ppp_mppe);
+
+	if (answer == 0)
+		printk(KERN_INFO "PPP MPPE Compression module registered\n");
+	else
+		kfree(sha_pad);
+
+	return answer;
+}
+
+static void __exit ppp_mppe_cleanup(void)
+{
+	ppp_unregister_compressor(&ppp_mppe);
+	kfree(sha_pad);
+}
+
+module_init(ppp_mppe_init);
+module_exit(ppp_mppe_cleanup);
diff --git a/drivers/net/ppp_mppe.h b/drivers/net/ppp_mppe.h
new file mode 100644
index 0000000..7a14e05
--- /dev/null
+++ b/drivers/net/ppp_mppe.h
@@ -0,0 +1,86 @@
+#define MPPE_PAD                4      /* MPPE growth per frame */
+#define MPPE_MAX_KEY_LEN       16      /* largest key length (128-bit) */
+
+/* option bits for ccp_options.mppe */
+#define MPPE_OPT_40            0x01    /* 40 bit */
+#define MPPE_OPT_128           0x02    /* 128 bit */
+#define MPPE_OPT_STATEFUL      0x04    /* stateful mode */
+/* unsupported opts */
+#define MPPE_OPT_56            0x08    /* 56 bit */
+#define MPPE_OPT_MPPC          0x10    /* MPPC compression */
+#define MPPE_OPT_D             0x20    /* Unknown */
+#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D)
+#define MPPE_OPT_UNKNOWN       0x40    /* Bits !defined in RFC 3078 were set */
+
+/*
+ * This is not nice ... the alternative is a bitfield struct though.
+ * And unfortunately, we cannot share the same bits for the option
+ * names above since C and H are the same bit.  We could do a u_int32
+ * but then we have to do a htonl() all the time and/or we still need
+ * to know which octet is which.
+ */
+#define MPPE_C_BIT             0x01    /* MPPC */
+#define MPPE_D_BIT             0x10    /* Obsolete, usage unknown */
+#define MPPE_L_BIT             0x20    /* 40-bit */
+#define MPPE_S_BIT             0x40    /* 128-bit */
+#define MPPE_M_BIT             0x80    /* 56-bit, not supported */
+#define MPPE_H_BIT             0x01    /* Stateless (in a different byte) */
+
+/* Does not include H bit; used for least significant octet only. */
+#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT)
+
+/* Build a CI from mppe opts (see RFC 3078) */
+#define MPPE_OPTS_TO_CI(opts, ci)              \
+    do {                                       \
+       u_char *ptr = ci; /* u_char[4] */       \
+                                               \
+       /* H bit */                             \
+       if (opts & MPPE_OPT_STATEFUL)           \
+           *ptr++ = 0x0;                       \
+       else                                    \
+           *ptr++ = MPPE_H_BIT;                \
+       *ptr++ = 0;                             \
+       *ptr++ = 0;                             \
+                                               \
+       /* S,L bits */                          \
+       *ptr = 0;                               \
+       if (opts & MPPE_OPT_128)                \
+           *ptr |= MPPE_S_BIT;                 \
+       if (opts & MPPE_OPT_40)                 \
+           *ptr |= MPPE_L_BIT;                 \
+       /* M,D,C bits not supported */          \
+    } while (/* CONSTCOND */ 0)
+
+/* The reverse of the above */
+#define MPPE_CI_TO_OPTS(ci, opts)              \
+    do {                                       \
+       u_char *ptr = ci; /* u_char[4] */       \
+                                               \
+       opts = 0;                               \
+                                               \
+       /* H bit */                             \
+       if (!(ptr[0] & MPPE_H_BIT))             \
+           opts |= MPPE_OPT_STATEFUL;          \
+                                               \
+       /* S,L bits */                          \
+       if (ptr[3] & MPPE_S_BIT)                \
+           opts |= MPPE_OPT_128;               \
+       if (ptr[3] & MPPE_L_BIT)                \
+           opts |= MPPE_OPT_40;                \
+                                               \
+       /* M,D,C bits */                        \
+       if (ptr[3] & MPPE_M_BIT)                \
+           opts |= MPPE_OPT_56;                \
+       if (ptr[3] & MPPE_D_BIT)                \
+           opts |= MPPE_OPT_D;                 \
+       if (ptr[3] & MPPE_C_BIT)                \
+           opts |= MPPE_OPT_MPPC;              \
+                                               \
+       /* Other bits */                        \
+       if (ptr[0] & ~MPPE_H_BIT)               \
+           opts |= MPPE_OPT_UNKNOWN;           \
+       if (ptr[1] || ptr[2])                   \
+           opts |= MPPE_OPT_UNKNOWN;           \
+       if (ptr[3] & ~MPPE_ALL_BITS)            \
+           opts |= MPPE_OPT_UNKNOWN;           \
+    } while (/* CONSTCOND */ 0)
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 0745dd9..e57df8d 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -55,7 +55,6 @@
 #include <linux/timex.h>
 #include <linux/sched.h>
 #include <linux/ethtool.h>
-#include <linux/version.h>
 #include <linux/workqueue.h>
 #include <linux/if_vlan.h>
 
@@ -1532,7 +1531,7 @@
 #define LINK_UP_DOWN_INTERRUPT		1
 #define MAC_RMAC_ERR_TIMER		2
 
-int s2io_link_fault_indication(nic_t *nic)
+static int s2io_link_fault_indication(nic_t *nic)
 {
 	if (nic->intr_type != INTA)
 		return MAC_RMAC_ERR_TIMER;
@@ -1864,7 +1863,7 @@
  *
  */
 
-void fix_mac_address(nic_t * sp)
+static void fix_mac_address(nic_t * sp)
 {
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
 	u64 val64;
@@ -2160,7 +2159,7 @@
  *  SUCCESS on success or an appropriate -ve value on failure.
  */
 
-int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
+static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
 {
 	struct net_device *dev = nic->dev;
 	struct sk_buff *skb;
@@ -2831,7 +2830,7 @@
  *   SUCCESS on success and FAILURE on failure.
  */
 
-int wait_for_cmd_complete(nic_t * sp)
+static int wait_for_cmd_complete(nic_t * sp)
 {
 	XENA_dev_config_t __iomem *bar0 = sp->bar0;
 	int ret = FAILURE, cnt = 0;
@@ -3077,7 +3076,7 @@
 	return SUCCESS;
 }
 
-int wait_for_msix_trans(nic_t *nic, int i)
+static int wait_for_msix_trans(nic_t *nic, int i)
 {
 	XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
 	u64 val64;
@@ -3116,7 +3115,7 @@
 	}
 }
 
-void store_xmsi_data(nic_t *nic)
+static void store_xmsi_data(nic_t *nic)
 {
 	XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
 	u64 val64, addr, data;
@@ -3288,7 +3287,7 @@
  *   file on failure.
  */
 
-int s2io_open(struct net_device *dev)
+static int s2io_open(struct net_device *dev)
 {
 	nic_t *sp = dev->priv;
 	int err = 0;
@@ -3418,7 +3417,7 @@
  *  file on failure.
  */
 
-int s2io_close(struct net_device *dev)
+static int s2io_close(struct net_device *dev)
 {
 	nic_t *sp = dev->priv;
 	int i;
@@ -3467,7 +3466,7 @@
  *  0 on success & 1 on failure.
  */
 
-int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
+static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	nic_t *sp = dev->priv;
 	u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
@@ -3913,7 +3912,7 @@
  *  pointer to the updated net_device_stats structure.
  */
 
-struct net_device_stats *s2io_get_stats(struct net_device *dev)
+static struct net_device_stats *s2io_get_stats(struct net_device *dev)
 {
 	nic_t *sp = dev->priv;
 	mac_info_t *mac_control;
@@ -5106,19 +5105,20 @@
 	tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
 }
 
-int s2io_ethtool_get_regs_len(struct net_device *dev)
+static int s2io_ethtool_get_regs_len(struct net_device *dev)
 {
 	return (XENA_REG_SPACE);
 }
 
 
-u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
+static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
 {
 	nic_t *sp = dev->priv;
 
 	return (sp->rx_csum);
 }
-int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
+
+static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
 {
 	nic_t *sp = dev->priv;
 
@@ -5129,17 +5129,19 @@
 
 	return 0;
 }
-int s2io_get_eeprom_len(struct net_device *dev)
+
+static int s2io_get_eeprom_len(struct net_device *dev)
 {
 	return (XENA_EEPROM_SPACE);
 }
 
-int s2io_ethtool_self_test_count(struct net_device *dev)
+static int s2io_ethtool_self_test_count(struct net_device *dev)
 {
 	return (S2IO_TEST_LEN);
 }
-void s2io_ethtool_get_strings(struct net_device *dev,
-			      u32 stringset, u8 * data)
+
+static void s2io_ethtool_get_strings(struct net_device *dev,
+				     u32 stringset, u8 * data)
 {
 	switch (stringset) {
 	case ETH_SS_TEST:
@@ -5155,7 +5157,7 @@
 	return (S2IO_STAT_LEN);
 }
 
-int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
+static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
 {
 	if (data)
 		dev->features |= NETIF_F_IP_CSUM;
@@ -5208,7 +5210,7 @@
  *  function always return EOPNOTSUPPORTED
  */
 
-int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	return -EOPNOTSUPP;
 }
@@ -5224,7 +5226,7 @@
  *   file on failure.
  */
 
-int s2io_change_mtu(struct net_device *dev, int new_mtu)
+static int s2io_change_mtu(struct net_device *dev, int new_mtu)
 {
 	nic_t *sp = dev->priv;
 
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index 110e777..b2acedb 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -1,8 +1,8 @@
 /*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
- *
- * ########################################################################
+ * Copyright (C) 2000, 2005  MIPS Technologies, Inc.  All rights reserved.
+ *	Authors: Carsten Langgaard <carstenl@mips.com>
+ *		 Maciej W. Rozycki <macro@mips.com>
+ * Copyright (C) 2004 Ralf Baechle <ralf@linux-mips.org>
  *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
@@ -17,15 +17,13 @@
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  *
- * ########################################################################
- *
  * SAA9730 ethernet driver.
  *
  * Changes:
- * Angelo Dell'Aera <buffer@antifork.org> : Conversion to the new PCI API (pci_driver).
- *                                          Conversion to spinlocks.
- *                                          Error handling fixes.
- *                                           
+ * Angelo Dell'Aera <buffer@antifork.org> :	Conversion to the new PCI API
+ *						(pci_driver).
+ *						Conversion to spinlocks.
+ *						Error handling fixes.
  */
 
 #include <linux/init.h>
@@ -36,8 +34,11 @@
 #include <linux/skbuff.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <linux/types.h>
 
 #include <asm/addrspace.h>
+#include <asm/io.h>
+
 #include <asm/mips-boards/prom.h>
 
 #include "saa9730.h"
@@ -51,8 +52,8 @@
 #define DRV_MODULE_NAME "saa9730"
 
 static struct pci_device_id saa9730_pci_tbl[] = {
-	{ PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9370,
-          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ 0, }
 };
 
@@ -61,50 +62,48 @@
 /* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
 static unsigned int pci_irq_line;
 
-#define INL(a)     inl((unsigned long)a)
-#define OUTL(x,a)  outl(x,(unsigned long)a)
-
 static void evm_saa9730_enable_lan_int(struct lan_saa9730_private *lp)
 {
-	OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
+	outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
 	     &lp->evm_saa9730_regs->InterruptBlock1);
-	OUTL(INL(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT,
+	outl(readl(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT,
 	     &lp->evm_saa9730_regs->InterruptStatus1);
-	OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT |
+	outl(readl(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT |
 	     EVM_MASTER_EN, &lp->evm_saa9730_regs->InterruptEnable1);
 }
+
 static void evm_saa9730_disable_lan_int(struct lan_saa9730_private *lp)
 {
-	OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
+	outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
 	     &lp->evm_saa9730_regs->InterruptBlock1);
-	OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT,
+	outl(readl(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT,
 	     &lp->evm_saa9730_regs->InterruptEnable1);
 }
 
 static void evm_saa9730_clear_lan_int(struct lan_saa9730_private *lp)
 {
-	OUTL(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1);
+	outl(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1);
 }
 
 static void evm_saa9730_block_lan_int(struct lan_saa9730_private *lp)
 {
-	OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
+	outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
 	     &lp->evm_saa9730_regs->InterruptBlock1);
 }
 
 static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp)
 {
-	OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
+	outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
 	     &lp->evm_saa9730_regs->InterruptBlock1);
 }
 
-static void show_saa9730_regs(struct lan_saa9730_private *lp)
+static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp)
 {
 	int i, j;
-	printk("TxmBufferA = %x\n", lp->TxmBuffer[0][0]);
-	printk("TxmBufferB = %x\n", lp->TxmBuffer[1][0]);
-	printk("RcvBufferA = %x\n", lp->RcvBuffer[0][0]);
-	printk("RcvBufferB = %x\n", lp->RcvBuffer[1][0]);
+	printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]);
+	printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]);
+	printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]);
+	printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]);
 	for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
 		for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
 			printk("TxmBuffer[%d][%d] = %x\n", i, j,
@@ -120,13 +119,13 @@
 		}
 	}
 	printk("lp->evm_saa9730_regs->InterruptBlock1 = %x\n",
-	       INL(&lp->evm_saa9730_regs->InterruptBlock1));
+	       readl(&lp->evm_saa9730_regs->InterruptBlock1));
 	printk("lp->evm_saa9730_regs->InterruptStatus1 = %x\n",
-	       INL(&lp->evm_saa9730_regs->InterruptStatus1));
+	       readl(&lp->evm_saa9730_regs->InterruptStatus1));
 	printk("lp->evm_saa9730_regs->InterruptEnable1 = %x\n",
-	       INL(&lp->evm_saa9730_regs->InterruptEnable1));
+	       readl(&lp->evm_saa9730_regs->InterruptEnable1));
 	printk("lp->lan_saa9730_regs->Ok2Use = %x\n",
-	       INL(&lp->lan_saa9730_regs->Ok2Use));
+	       readl(&lp->lan_saa9730_regs->Ok2Use));
 	printk("lp->NextTxmBufferIndex = %x\n", lp->NextTxmBufferIndex);
 	printk("lp->NextTxmPacketIndex = %x\n", lp->NextTxmPacketIndex);
 	printk("lp->PendingTxmBufferIndex = %x\n",
@@ -134,23 +133,23 @@
 	printk("lp->PendingTxmPacketIndex = %x\n",
 	       lp->PendingTxmPacketIndex);
 	printk("lp->lan_saa9730_regs->LanDmaCtl = %x\n",
-	       INL(&lp->lan_saa9730_regs->LanDmaCtl));
+	       readl(&lp->lan_saa9730_regs->LanDmaCtl));
 	printk("lp->lan_saa9730_regs->DmaStatus = %x\n",
-	       INL(&lp->lan_saa9730_regs->DmaStatus));
+	       readl(&lp->lan_saa9730_regs->DmaStatus));
 	printk("lp->lan_saa9730_regs->CamCtl = %x\n",
-	       INL(&lp->lan_saa9730_regs->CamCtl));
+	       readl(&lp->lan_saa9730_regs->CamCtl));
 	printk("lp->lan_saa9730_regs->TxCtl = %x\n",
-	       INL(&lp->lan_saa9730_regs->TxCtl));
+	       readl(&lp->lan_saa9730_regs->TxCtl));
 	printk("lp->lan_saa9730_regs->TxStatus = %x\n",
-	       INL(&lp->lan_saa9730_regs->TxStatus));
+	       readl(&lp->lan_saa9730_regs->TxStatus));
 	printk("lp->lan_saa9730_regs->RxCtl = %x\n",
-	       INL(&lp->lan_saa9730_regs->RxCtl));
+	       readl(&lp->lan_saa9730_regs->RxCtl));
 	printk("lp->lan_saa9730_regs->RxStatus = %x\n",
-	       INL(&lp->lan_saa9730_regs->RxStatus));
+	       readl(&lp->lan_saa9730_regs->RxStatus));
 	for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
-		OUTL(i, &lp->lan_saa9730_regs->CamAddress);
+		outl(i, &lp->lan_saa9730_regs->CamAddress);
 		printk("lp->lan_saa9730_regs->CamData = %x\n",
-		       INL(&lp->lan_saa9730_regs->CamData));
+		       readl(&lp->lan_saa9730_regs->CamData));
 	}
 	printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets);
 	printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors);
@@ -178,17 +177,17 @@
 	       lp->stats.rx_length_errors);
 
 	printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n",
-	       INL(&lp->lan_saa9730_regs->DebugPCIMasterAddr));
+	       readl(&lp->lan_saa9730_regs->DebugPCIMasterAddr));
 	printk("lp->lan_saa9730_regs->DebugLanTxStateMachine = %x\n",
-	       INL(&lp->lan_saa9730_regs->DebugLanTxStateMachine));
+	       readl(&lp->lan_saa9730_regs->DebugLanTxStateMachine));
 	printk("lp->lan_saa9730_regs->DebugLanRxStateMachine = %x\n",
-	       INL(&lp->lan_saa9730_regs->DebugLanRxStateMachine));
+	       readl(&lp->lan_saa9730_regs->DebugLanRxStateMachine));
 	printk("lp->lan_saa9730_regs->DebugLanTxFifoPointers = %x\n",
-	       INL(&lp->lan_saa9730_regs->DebugLanTxFifoPointers));
+	       readl(&lp->lan_saa9730_regs->DebugLanTxFifoPointers));
 	printk("lp->lan_saa9730_regs->DebugLanRxFifoPointers = %x\n",
-	       INL(&lp->lan_saa9730_regs->DebugLanRxFifoPointers));
+	       readl(&lp->lan_saa9730_regs->DebugLanRxFifoPointers));
 	printk("lp->lan_saa9730_regs->DebugLanCtlStateMachine = %x\n",
-	       INL(&lp->lan_saa9730_regs->DebugLanCtlStateMachine));
+	       readl(&lp->lan_saa9730_regs->DebugLanCtlStateMachine));
 }
 
 static void lan_saa9730_buffer_init(struct lan_saa9730_private *lp)
@@ -214,98 +213,108 @@
 	}
 }
 
-static int lan_saa9730_allocate_buffers(struct lan_saa9730_private *lp)
+static void lan_saa9730_free_buffers(struct pci_dev *pdev,
+				     struct lan_saa9730_private *lp)
 {
-	unsigned int mem_size;
+	pci_free_consistent(pdev, lp->buffer_size, lp->buffer_start,
+			    lp->dma_addr);
+}
+
+static int lan_saa9730_allocate_buffers(struct pci_dev *pdev,
+					struct lan_saa9730_private *lp)
+{
 	void *Pa;
-	unsigned int i, j, RcvBufferSize, TxmBufferSize;
-	unsigned int buffer_start;
-
-	/* 
-	 * Allocate all RX and TX packets in one chunk. 
-	 * The Rx and Tx packets must be PACKET_SIZE aligned.
-	 */
-	mem_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) *
-		    LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) +
-	    LAN_SAA9730_PACKET_SIZE;
-	buffer_start =
-	    (unsigned int) kmalloc(mem_size, GFP_DMA | GFP_KERNEL);
-
-	if (!buffer_start)
-		return -ENOMEM;
-
-	/* 
-	 * Set DMA buffer to kseg1 (uncached).
-	 * Make sure to flush before using it uncached.
-	 */
-	Pa = (void *) KSEG1ADDR((buffer_start + LAN_SAA9730_PACKET_SIZE) &
-				~(LAN_SAA9730_PACKET_SIZE - 1));
-	dma_cache_wback_inv((unsigned long) Pa, mem_size);
+	unsigned int i, j, rxoffset, txoffset;
+	int ret;
 
 	/* Initialize buffer space */
-	RcvBufferSize = LAN_SAA9730_PACKET_SIZE;
-	TxmBufferSize = LAN_SAA9730_PACKET_SIZE;
 	lp->DmaRcvPackets = LAN_SAA9730_RCV_Q_SIZE;
 	lp->DmaTxmPackets = LAN_SAA9730_TXM_Q_SIZE;
 
+	/* Initialize Rx Buffer Index */
+	lp->NextRcvPacketIndex = 0;
+	lp->NextRcvBufferIndex = 0;
+
+	/* Set current buffer index & next available packet index */
+	lp->NextTxmPacketIndex = 0;
+	lp->NextTxmBufferIndex = 0;
+	lp->PendingTxmPacketIndex = 0;
+	lp->PendingTxmBufferIndex = 0;
+
+	/*
+	 * Allocate all RX and TX packets in one chunk.
+	 * The Rx and Tx packets must be PACKET_SIZE aligned.
+	 */
+	lp->buffer_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) *
+			   LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) +
+			  LAN_SAA9730_PACKET_SIZE;
+	lp->buffer_start = pci_alloc_consistent(pdev, lp->buffer_size,
+						&lp->dma_addr);
+	if (!lp->buffer_start) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	Pa = (void *)ALIGN((unsigned long)lp->buffer_start,
+			   LAN_SAA9730_PACKET_SIZE);
+
+	rxoffset = Pa - lp->buffer_start;
+
 	/* Init RX buffers */
 	for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
 		for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) {
 			*(unsigned int *) Pa =
 			    cpu_to_le32(RXSF_READY <<
 					RX_STAT_CTL_OWNER_SHF);
-			lp->RcvBuffer[i][j] = (unsigned int) Pa;
-			Pa += RcvBufferSize;
+			lp->RcvBuffer[i][j] = Pa;
+			Pa += LAN_SAA9730_PACKET_SIZE;
 		}
 	}
 
+	txoffset = Pa - lp->buffer_start;
+
 	/* Init TX buffers */
 	for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
 		for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
 			*(unsigned int *) Pa =
 			    cpu_to_le32(TXSF_EMPTY <<
 					TX_STAT_CTL_OWNER_SHF);
-			lp->TxmBuffer[i][j] = (unsigned int) Pa;
-			Pa += TxmBufferSize;
+			lp->TxmBuffer[i][j] = Pa;
+			Pa += LAN_SAA9730_PACKET_SIZE;
 		}
 	}
 
-	/* 
-	 * Set rx buffer A and rx buffer B to point to the first two buffer 
+	/*
+	 * Set rx buffer A and rx buffer B to point to the first two buffer
 	 * spaces.
 	 */
-	OUTL(PHYSADDR(lp->RcvBuffer[0][0]),
+	outl(lp->dma_addr + rxoffset,
 	     &lp->lan_saa9730_regs->RxBuffA);
-	OUTL(PHYSADDR(lp->RcvBuffer[1][0]),
+	outl(lp->dma_addr + rxoffset +
+	     LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_RCV_Q_SIZE,
 	     &lp->lan_saa9730_regs->RxBuffB);
 
-	/* Initialize Buffer Index */
-	lp->NextRcvPacketIndex = 0;
-	lp->NextRcvToUseIsA = 1;
-
-	/* Set current buffer index & next availble packet index */
-	lp->NextTxmPacketIndex = 0;
-	lp->NextTxmBufferIndex = 0;
-	lp->PendingTxmPacketIndex = 0;
-	lp->PendingTxmBufferIndex = 0;
-
-	/* 
+	/*
 	 * Set txm_buf_a and txm_buf_b to point to the first two buffer
-	 * space 
+	 * space
 	 */
-	OUTL(PHYSADDR(lp->TxmBuffer[0][0]),
+	outl(lp->dma_addr + txoffset,
 	     &lp->lan_saa9730_regs->TxBuffA);
-	OUTL(PHYSADDR(lp->TxmBuffer[1][0]),
+	outl(lp->dma_addr + txoffset +
+	     LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_TXM_Q_SIZE,
 	     &lp->lan_saa9730_regs->TxBuffB);
 
 	/* Set packet number */
-	OUTL((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) |
+	outl((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) |
 	     (lp->DmaRcvPackets << PK_COUNT_RX_B_SHF) |
 	     (lp->DmaTxmPackets << PK_COUNT_TX_A_SHF) |
 	     (lp->DmaTxmPackets << PK_COUNT_TX_B_SHF),
 	     &lp->lan_saa9730_regs->PacketCount);
 
 	return 0;
+
+out:
+	return ret;
 }
 
 static int lan_saa9730_cam_load(struct lan_saa9730_private *lp)
@@ -317,8 +326,8 @@
 
 	for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
 		/* First set address to where data is written */
-		OUTL(i, &lp->lan_saa9730_regs->CamAddress);
-		OUTL((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16)
+		outl(i, &lp->lan_saa9730_regs->CamAddress);
+		outl((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16)
 		     | (NetworkAddress[2] << 8) | NetworkAddress[3],
 		     &lp->lan_saa9730_regs->CamData);
 		NetworkAddress += 4;
@@ -328,8 +337,7 @@
 
 static int lan_saa9730_cam_init(struct net_device *dev)
 {
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 	unsigned int i;
 
 	/* Copy MAC-address into all entries. */
@@ -347,7 +355,7 @@
 
 	/* Check link status, spin here till station is not busy. */
 	i = 0;
-	while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
+	while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
 		i++;
 		if (i > 100) {
 			printk("Error: lan_saa9730_mii_init: timeout\n");
@@ -357,12 +365,12 @@
 	}
 
 	/* Now set the control and address register. */
-	OUTL(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF,
+	outl(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF,
 	     &lp->lan_saa9730_regs->StationMgmtCtl);
 
 	/* check link status, spin here till station is not busy */
 	i = 0;
-	while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
+	while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
 		i++;
 		if (i > 100) {
 			printk("Error: lan_saa9730_mii_init: timeout\n");
@@ -375,7 +383,7 @@
 	mdelay(1);
 
 	/* Check the link status. */
-	if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
+	if (readl(&lp->lan_saa9730_regs->StationMgmtData) &
 	    PHY_STATUS_LINK_UP) {
 		/* Link is up. */
 		return 0;
@@ -383,14 +391,14 @@
 		/* Link is down, reset the PHY first. */
 
 		/* set PHY address = 'CONTROL' */
-		OUTL(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL,
+		outl(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL,
 		     &lp->lan_saa9730_regs->StationMgmtCtl);
 
 		/* Wait for 1 ms. */
 		mdelay(1);
 
 		/* set 'CONTROL' = force reset and renegotiate */
-		OUTL(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG |
+		outl(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG |
 		     PHY_CONTROL_RESTART_AUTO_NEG,
 		     &lp->lan_saa9730_regs->StationMgmtData);
 
@@ -398,12 +406,12 @@
 		mdelay(50);
 
 		/* set 'BUSY' to start operation */
-		OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR |
+		outl(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR |
 		     PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl);
 
 		/* await completion */
 		i = 0;
-		while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) &
+		while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) &
 		       MD_CA_BUSY) {
 			i++;
 			if (i > 100) {
@@ -419,13 +427,13 @@
 
 		for (l = 0; l < 2; l++) {
 			/* set PHY address = 'STATUS' */
-			OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF |
+			outl(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF |
 			     PHY_STATUS,
 			     &lp->lan_saa9730_regs->StationMgmtCtl);
 
 			/* await completion */
 			i = 0;
-			while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) &
+			while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) &
 			       MD_CA_BUSY) {
 				i++;
 				if (i > 100) {
@@ -440,7 +448,7 @@
 			mdelay(3000);
 
 			/* check the link status */
-			if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
+			if (readl(&lp->lan_saa9730_regs->StationMgmtData) &
 			    PHY_STATUS_LINK_UP) {
 				/* link is up */
 				break;
@@ -454,7 +462,7 @@
 static int lan_saa9730_control_init(struct lan_saa9730_private *lp)
 {
 	/* Initialize DMA control register. */
-	OUTL((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) |
+	outl((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) |
 	     (LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) |
 	     (LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF)
 	     | DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN |
@@ -462,27 +470,27 @@
 	     &lp->lan_saa9730_regs->LanDmaCtl);
 
 	/* Initial MAC control register. */
-	OUTL((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP,
+	outl((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP,
 	     &lp->lan_saa9730_regs->MacCtl);
 
 	/* Initialize CAM control register. */
-	OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC,
+	outl(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC,
 	     &lp->lan_saa9730_regs->CamCtl);
 
-	/* 
+	/*
 	 * Initialize CAM enable register, only turn on first entry, should
-	 * contain own addr. 
+	 * contain own addr.
 	 */
-	OUTL(0x0001, &lp->lan_saa9730_regs->CamEnable);
+	outl(0x0001, &lp->lan_saa9730_regs->CamEnable);
 
 	/* Initialize Tx control register */
-	OUTL(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl);
+	outl(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl);
 
 	/* Initialize Rcv control register */
-	OUTL(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl);
+	outl(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl);
 
 	/* Reset DMA engine */
-	OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
+	outl(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
 
 	return 0;
 }
@@ -492,21 +500,21 @@
 	int i;
 
 	/* Stop DMA first */
-	OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) &
+	outl(readl(&lp->lan_saa9730_regs->LanDmaCtl) &
 	     ~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA),
 	     &lp->lan_saa9730_regs->LanDmaCtl);
 
 	/* Set the SW Reset bits in DMA and MAC control registers */
-	OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
-	OUTL(INL(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET,
+	outl(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
+	outl(readl(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET,
 	     &lp->lan_saa9730_regs->MacCtl);
 
-	/* 
+	/*
 	 * Wait for MAC reset to have finished. The reset bit is auto cleared
 	 * when the reset is done.
 	 */
 	i = 0;
-	while (INL(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) {
+	while (readl(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) {
 		i++;
 		if (i > 100) {
 			printk
@@ -524,7 +532,7 @@
 	/* Stop lan controller. */
 	lan_saa9730_stop(lp);
 
-	OUTL(LAN_SAA9730_DEFAULT_TIME_OUT_CNT,
+	outl(LAN_SAA9730_DEFAULT_TIME_OUT_CNT,
 	     &lp->lan_saa9730_regs->Timeout);
 
 	return 0;
@@ -536,28 +544,27 @@
 
 	/* Initialize Rx Buffer Index */
 	lp->NextRcvPacketIndex = 0;
-	lp->NextRcvToUseIsA = 1;
+	lp->NextRcvBufferIndex = 0;
 
-	/* Set current buffer index & next availble packet index */
+	/* Set current buffer index & next available packet index */
 	lp->NextTxmPacketIndex = 0;
 	lp->NextTxmBufferIndex = 0;
 	lp->PendingTxmPacketIndex = 0;
 	lp->PendingTxmBufferIndex = 0;
 
-	OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA |
+	outl(readl(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA |
 	     DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl);
 
 	/* For Tx, turn on MAC then DMA */
-	OUTL(INL(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN,
+	outl(readl(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN,
 	     &lp->lan_saa9730_regs->TxCtl);
 
 	/* For Rx, turn on DMA then MAC */
-	OUTL(INL(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN,
+	outl(readl(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN,
 	     &lp->lan_saa9730_regs->RxCtl);
 
-	/* Set Ok2Use to let hardware owns the buffers */
-	OUTL(OK2USE_RX_A | OK2USE_RX_B | OK2USE_TX_A | OK2USE_TX_B,
-	     &lp->lan_saa9730_regs->Ok2Use);
+	/* Set Ok2Use to let hardware own the buffers.	*/
+	outl(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use);
 
 	return 0;
 }
@@ -572,8 +579,7 @@
 
 static int lan_saa9730_tx(struct net_device *dev)
 {
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 	unsigned int *pPacket;
 	unsigned int tx_status;
 
@@ -581,13 +587,11 @@
 		printk("lan_saa9730_tx interrupt\n");
 
 	/* Clear interrupt. */
-	OUTL(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus);
+	outl(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus);
 
 	while (1) {
-		pPacket =
-		    (unsigned int *) lp->TxmBuffer[lp->
-						   PendingTxmBufferIndex]
-		    [lp->PendingTxmPacketIndex];
+		pPacket = lp->TxmBuffer[lp->PendingTxmBufferIndex]
+				       [lp->PendingTxmPacketIndex];
 
 		/* Get status of first packet transmitted. */
 		tx_status = le32_to_cpu(*pPacket);
@@ -605,23 +609,22 @@
 			lp->stats.tx_errors++;
 			if (tx_status &
 			    (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF))
-				    lp->stats.tx_aborted_errors++;
+				lp->stats.tx_aborted_errors++;
 			if (tx_status &
-			    (TX_STATUS_LATE_COLL <<
-			     TX_STAT_CTL_STATUS_SHF)) lp->stats.
-	     tx_window_errors++;
+			    (TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF))
+				lp->stats.tx_window_errors++;
 			if (tx_status &
 			    (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF))
-				    lp->stats.tx_carrier_errors++;
+				lp->stats.tx_carrier_errors++;
 			if (tx_status &
 			    (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF))
-				    lp->stats.tx_fifo_errors++;
+				lp->stats.tx_fifo_errors++;
 			if (tx_status &
 			    (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF))
-				    lp->stats.tx_heartbeat_errors++;
+				lp->stats.tx_heartbeat_errors++;
 
 			lp->stats.collisions +=
-			    tx_status & TX_STATUS_TX_COLL_MSK;
+				tx_status & TX_STATUS_TX_COLL_MSK;
 		}
 
 		/* Free buffer. */
@@ -636,21 +639,15 @@
 		}
 	}
 
-	/* Make sure A and B are available to hardware. */
-	OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use);
-
-	if (netif_queue_stopped(dev)) {
-		/* The tx buffer is no longer full. */
-		netif_wake_queue(dev);
-	}
+	/* The tx buffer is no longer full. */
+	netif_wake_queue(dev);
 
 	return 0;
 }
 
 static int lan_saa9730_rx(struct net_device *dev)
 {
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 	int len = 0;
 	struct sk_buff *skb = 0;
 	unsigned int rx_status;
@@ -663,16 +660,13 @@
 		printk("lan_saa9730_rx interrupt\n");
 
 	/* Clear receive interrupts. */
-	OUTL(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
+	outl(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
 	     DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus);
 
 	/* Address next packet */
-	if (lp->NextRcvToUseIsA)
-		BufferIndex = 0;
-	else
-		BufferIndex = 1;
+	BufferIndex = lp->NextRcvBufferIndex;
 	PacketIndex = lp->NextRcvPacketIndex;
-	pPacket = (unsigned int *) lp->RcvBuffer[BufferIndex][PacketIndex];
+	pPacket = lp->RcvBuffer[BufferIndex][PacketIndex];
 	rx_status = le32_to_cpu(*pPacket);
 
 	/* Process each packet. */
@@ -715,51 +709,39 @@
 			lp->stats.rx_errors++;
 			if (rx_status &
 			    (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF))
-				    lp->stats.rx_crc_errors++;
+				lp->stats.rx_crc_errors++;
 			if (rx_status &
-			    (RX_STATUS_ALIGN_ERR <<
-			     RX_STAT_CTL_STATUS_SHF)) lp->stats.
-	     rx_frame_errors++;
+			    (RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF))
+				lp->stats.rx_frame_errors++;
 			if (rx_status &
 			    (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF))
-				    lp->stats.rx_fifo_errors++;
+				lp->stats.rx_fifo_errors++;
 			if (rx_status &
 			    (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF))
-				    lp->stats.rx_length_errors++;
+				lp->stats.rx_length_errors++;
 		}
 
 		/* Indicate we have processed the buffer. */
-		*pPacket =
-		    cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF);
+		*pPacket = cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF);
+
+		/* Make sure A or B is available to hardware as appropriate. */
+		outl(BufferIndex ? OK2USE_RX_B : OK2USE_RX_A,
+		     &lp->lan_saa9730_regs->Ok2Use);
 
 		/* Go to next packet in sequence. */
 		lp->NextRcvPacketIndex++;
 		if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) {
 			lp->NextRcvPacketIndex = 0;
-			if (BufferIndex) {
-				lp->NextRcvToUseIsA = 1;
-			} else {
-				lp->NextRcvToUseIsA = 0;
-			}
+			lp->NextRcvBufferIndex ^= 1;
 		}
-		OUTL(OK2USE_RX_A | OK2USE_RX_B,
-		     &lp->lan_saa9730_regs->Ok2Use);
 
 		/* Address next packet */
-		if (lp->NextRcvToUseIsA)
-			BufferIndex = 0;
-		else
-			BufferIndex = 1;
+		BufferIndex = lp->NextRcvBufferIndex;
 		PacketIndex = lp->NextRcvPacketIndex;
-		pPacket =
-		    (unsigned int *) lp->
-		    RcvBuffer[BufferIndex][PacketIndex];
+		pPacket = lp->RcvBuffer[BufferIndex][PacketIndex];
 		rx_status = le32_to_cpu(*pPacket);
 	}
 
-	/* Make sure A and B are available to hardware. */
-	OUTL(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use);
-
 	return 0;
 }
 
@@ -767,8 +749,7 @@
 				  struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 
 	if (lan_saa9730_debug > 5)
 		printk("lan_saa9730_interrupt\n");
@@ -780,11 +761,11 @@
 	evm_saa9730_clear_lan_int(lp);
 
 	/* Service pending transmit interrupts. */
-	if (INL(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT)
+	if (readl(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT)
 		lan_saa9730_tx(dev);
 
 	/* Service pending receive interrupts. */
-	if (INL(&lp->lan_saa9730_regs->DmaStatus) &
+	if (readl(&lp->lan_saa9730_regs->DmaStatus) &
 	    (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
 	     DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev);
 
@@ -794,15 +775,9 @@
 	return IRQ_HANDLED;
 }
 
-static int lan_saa9730_open_fail(struct net_device *dev)
-{
-	return -ENODEV;
-}
-
 static int lan_saa9730_open(struct net_device *dev)
 {
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 
 	/* Associate IRQ with lan_saa9730_interrupt */
 	if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth",
@@ -834,15 +809,13 @@
 	int PacketIndex;
 
 	if (lan_saa9730_debug > 5)
-		printk("lan_saa9730_write: skb=%08x\n",
-		       (unsigned int) skb);
+		printk("lan_saa9730_write: skb=%p\n", skb);
 
 	BufferIndex = lp->NextTxmBufferIndex;
 	PacketIndex = lp->NextTxmPacketIndex;
 
-	tx_status =
-	    le32_to_cpu(*(unsigned int *) lp->
-			TxmBuffer[BufferIndex][PacketIndex]);
+	tx_status = le32_to_cpu(*(unsigned int *)lp->TxmBuffer[BufferIndex]
+							      [PacketIndex]);
 	if ((tx_status & TX_STAT_CTL_OWNER_MSK) !=
 	    (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) {
 		if (lan_saa9730_debug > 4)
@@ -858,29 +831,29 @@
 		lp->NextTxmBufferIndex ^= 1;
 	}
 
-	pbPacketData =
-	    (unsigned char *) lp->TxmBuffer[BufferIndex][PacketIndex];
+	pbPacketData = lp->TxmBuffer[BufferIndex][PacketIndex];
 	pbPacketData += 4;
 
 	/* copy the bits */
 	memcpy(pbPacketData, pbData, len);
 
 	/* Set transmit status for hardware */
-	*(unsigned int *) lp->TxmBuffer[BufferIndex][PacketIndex] =
-	    cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) |
-			(TX_STAT_CTL_INT_AFTER_TX << TX_STAT_CTL_FRAME_SHF)
-			| (len << TX_STAT_CTL_LENGTH_SHF));
+	*(unsigned int *)lp->TxmBuffer[BufferIndex][PacketIndex] =
+		cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) |
+			    (TX_STAT_CTL_INT_AFTER_TX <<
+			     TX_STAT_CTL_FRAME_SHF) |
+			    (len << TX_STAT_CTL_LENGTH_SHF));
 
-	/* Set hardware tx buffer. */
-	OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use);
+	/* Make sure A or B is available to hardware as appropriate. */
+	outl(BufferIndex ? OK2USE_TX_B : OK2USE_TX_A,
+	     &lp->lan_saa9730_regs->Ok2Use);
 
 	return 0;
 }
 
 static void lan_saa9730_tx_timeout(struct net_device *dev)
 {
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 
 	/* Transmitter timeout, serious problems */
 	lp->stats.tx_errors++;
@@ -889,20 +862,19 @@
 	lan_saa9730_restart(lp);
 
 	dev->trans_start = jiffies;
-	netif_start_queue(dev);
+	netif_wake_queue(dev);
 }
 
 static int lan_saa9730_start_xmit(struct sk_buff *skb,
 				  struct net_device *dev)
 {
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 	unsigned long flags;
 	int skblen;
 	int len;
 
 	if (lan_saa9730_debug > 4)
-		printk("Send packet: skb=%08x\n", (unsigned int) skb);
+		printk("Send packet: skb=%p\n", skb);
 
 	skblen = skb->len;
 
@@ -912,8 +884,7 @@
 
 	if (lan_saa9730_write(lp, skb, skblen)) {
 		spin_unlock_irqrestore(&lp->lock, flags);
-		printk("Error when writing packet to controller: skb=%08x\n",
-		     (unsigned int) skb);
+		printk("Error when writing packet to controller: skb=%p\n", skb);
 		netif_stop_queue(dev);
 		return -1;
 	}
@@ -922,7 +893,7 @@
 	lp->stats.tx_packets++;
 
 	dev->trans_start = jiffies;
-	netif_start_queue(dev);
+	netif_wake_queue(dev);
 	dev_kfree_skb(skb);
 
 	spin_unlock_irqrestore(&lp->lock, flags);
@@ -932,8 +903,7 @@
 
 static int lan_saa9730_close(struct net_device *dev)
 {
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 
 	if (lan_saa9730_debug > 1)
 		printk("lan_saa9730_close:\n");
@@ -955,33 +925,31 @@
 static struct net_device_stats *lan_saa9730_get_stats(struct net_device
 						      *dev)
 {
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 
 	return &lp->stats;
 }
 
 static void lan_saa9730_set_multicast(struct net_device *dev)
 {
-	struct lan_saa9730_private *lp =
-	    (struct lan_saa9730_private *) dev->priv;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 
 	/* Stop the controller */
 	lan_saa9730_stop(lp);
 
 	if (dev->flags & IFF_PROMISC) {
 		/* accept all packets */
-		OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC |
+		outl(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC |
 		     CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC,
 		     &lp->lan_saa9730_regs->CamCtl);
 	} else {
 		if (dev->flags & IFF_ALLMULTI) {
 			/* accept all multicast packets */
-			OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
+			outl(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
 			     CAM_CONTROL_BROAD_ACC,
 			     &lp->lan_saa9730_regs->CamCtl);
 		} else {
-			/* 
+			/*
 			 * Will handle the multicast stuff later. -carstenl
 			 */
 		}
@@ -993,91 +961,86 @@
 
 static void __devexit saa9730_remove_one(struct pci_dev *pdev)
 {
-        struct net_device *dev = pci_get_drvdata(pdev);
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 
-        if (dev) {
-                unregister_netdev(dev);
-		kfree(dev->priv);
-                free_netdev(dev);
-                pci_release_regions(pdev);
-                pci_disable_device(pdev);
-                pci_set_drvdata(pdev, NULL);
-        }
+	if (dev) {
+		unregister_netdev(dev);
+		lan_saa9730_free_buffers(pdev, lp);
+		iounmap(lp->lan_saa9730_regs);
+		iounmap(lp->evm_saa9730_regs);
+		free_netdev(dev);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
 }
 
 
-static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq)
+static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev,
+	unsigned long ioaddr, int irq)
 {
-	struct lan_saa9730_private *lp;
+	struct lan_saa9730_private *lp = netdev_priv(dev);
 	unsigned char ethernet_addr[6];
-	int ret = 0;
+	int ret;
 
-	dev->open = lan_saa9730_open_fail;
+	if (get_ethernet_addr(ethernet_addr)) {
+		ret = -ENODEV;
+		goto out;
+	}
 
-	if (get_ethernet_addr(ethernet_addr))
-		return -ENODEV;
-	
 	memcpy(dev->dev_addr, ethernet_addr, 6);
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
-	
-	/* 
-	 * Make certain the data structures used by the controller are aligned 
-	 * and DMAble. 
-	 */
-	/*
-	 *  XXX: that is obviously broken - kfree() won't be happy with us.
-	 */
-	lp = (struct lan_saa9730_private *) (((unsigned long)
-					      kmalloc(sizeof(*lp) + 7,
-						      GFP_DMA | GFP_KERNEL)
-					      + 7) & ~7);
 
-	if (!lp)
-		return -ENOMEM;
-
-	dev->priv = lp;
-	memset(lp, 0, sizeof(*lp));
+	lp->pci_dev = pdev;
 
 	/* Set SAA9730 LAN base address. */
-	lp->lan_saa9730_regs = (t_lan_saa9730_regmap *) (ioaddr +
-							 SAA9730_LAN_REGS_ADDR);
+	lp->lan_saa9730_regs = ioremap(ioaddr + SAA9730_LAN_REGS_ADDR,
+				       SAA9730_LAN_REGS_SIZE);
+	if (!lp->lan_saa9730_regs) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
 	/* Set SAA9730 EVM base address. */
-	lp->evm_saa9730_regs = (t_evm_saa9730_regmap *) (ioaddr +
-							 SAA9730_EVM_REGS_ADDR);
+	lp->evm_saa9730_regs = ioremap(ioaddr + SAA9730_EVM_REGS_ADDR,
+				       SAA9730_EVM_REGS_SIZE);
+	if (!lp->evm_saa9730_regs) {
+		ret = -ENOMEM;
+		goto out_iounmap_lan;
+	}
 
 	/* Allocate LAN RX/TX frame buffer space. */
-	/* FIXME: a leak */
-	if ((ret = lan_saa9730_allocate_buffers(lp)))
-		goto out;
+	if ((ret = lan_saa9730_allocate_buffers(pdev, lp)))
+		goto out_iounmap;
 
 	/* Stop LAN controller. */
-	if ((ret = lan_saa9730_stop(lp))) 
-		goto out;
-	
+	if ((ret = lan_saa9730_stop(lp)))
+		goto out_free_consistent;
+
 	/* Initialize CAM registers. */
 	if ((ret = lan_saa9730_cam_init(dev)))
-		goto out;
+		goto out_free_consistent;
 
 	/* Initialize MII registers. */
 	if ((ret = lan_saa9730_mii_init(lp)))
-		goto out;
+		goto out_free_consistent;
 
 	/* Initialize control registers. */
-	if ((ret = lan_saa9730_control_init(lp))) 
-		goto out;
-        
+	if ((ret = lan_saa9730_control_init(lp)))
+		goto out_free_consistent;
+
 	/* Load CAM registers. */
-	if ((ret = lan_saa9730_cam_load(lp))) 
-		goto out;
-	
+	if ((ret = lan_saa9730_cam_load(lp)))
+		goto out_free_consistent;
+
 	/* Initialize DMA context registers. */
 	if ((ret = lan_saa9730_dma_init(lp)))
-		goto out;
-	
+		goto out_free_consistent;
+
 	spin_lock_init(&lp->lock);
-		
+
 	dev->open = lan_saa9730_open;
 	dev->hard_start_xmit = lan_saa9730_start_xmit;
 	dev->stop = lan_saa9730_close;
@@ -1086,44 +1049,43 @@
 	dev->tx_timeout = lan_saa9730_tx_timeout;
 	dev->watchdog_timeo = (HZ >> 1);
 	dev->dma = 0;
-	
-	ret = register_netdev(dev);
+
+	ret = register_netdev (dev);
 	if (ret)
-		goto out;
+		goto out_free_consistent;
+
 	return 0;
 
- out:
-	kfree(dev->priv);
+out_free_consistent:
+	lan_saa9730_free_buffers(pdev, lp);
+out_iounmap:
+	iounmap(lp->evm_saa9730_regs);
+out_iounmap_lan:
+	iounmap(lp->lan_saa9730_regs);
+out:
 	return ret;
 }
 
 
 static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	struct net_device *dev;
-	unsigned int pci_ioaddr;
+	struct net_device *dev = NULL;
+	unsigned long pci_ioaddr;
 	int err;
 
 	if (lan_saa9730_debug > 1)
 		printk("saa9730.c: PCI bios is present, checking for devices...\n");
 
-	err = -ENOMEM;
-	dev = alloc_etherdev(0);
-	if (!dev)
-		goto out;
-
-	SET_MODULE_OWNER(dev);
-
 	err = pci_enable_device(pdev);
-        if (err) {
-                printk(KERN_ERR "Cannot enable PCI device, aborting.\n");
-                goto out1;
-        }
+	if (err) {
+		printk(KERN_ERR "Cannot enable PCI device, aborting.\n");
+		goto out;
+	}
 
 	err = pci_request_regions(pdev, DRV_MODULE_NAME);
 	if (err) {
 		printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n");
-		goto out2;
+		goto out_disable_pdev;
 	}
 
 	pci_irq_line = pdev->irq;
@@ -1132,49 +1094,54 @@
 	pci_ioaddr = pci_resource_start(pdev, 1);
 	pci_set_master(pdev);
 
-	printk("Found SAA9730 (PCI) at %#x, irq %d.\n",
+	printk("Found SAA9730 (PCI) at %lx, irq %d.\n",
 	       pci_ioaddr, pci_irq_line);
 
-	err = lan_saa9730_init(dev, pci_ioaddr, pci_irq_line);
+	dev = alloc_etherdev(sizeof(struct lan_saa9730_private));
+	if (!dev)
+		goto out_disable_pdev;
+
+	err = lan_saa9730_init(dev, pdev, pci_ioaddr, pci_irq_line);
 	if (err) {
-		printk("Lan init failed");
-		goto out2;
+		printk("LAN init failed");
+		goto out_free_netdev;
 	}
 
 	pci_set_drvdata(pdev, dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	return 0;
-	
-out2:
-	pci_disable_device(pdev);
-out1:
+
+out_free_netdev:
 	free_netdev(dev);
+out_disable_pdev:
+	pci_disable_device(pdev);
 out:
+	pci_set_drvdata(pdev, NULL);
 	return err;
 }
 
 
 static struct pci_driver saa9730_driver = {
-	.name           = DRV_MODULE_NAME,
-	.id_table       = saa9730_pci_tbl,
-	.probe          = saa9730_init_one,
-	.remove         = __devexit_p(saa9730_remove_one),
+	.name		= DRV_MODULE_NAME,
+	.id_table	= saa9730_pci_tbl,
+	.probe		= saa9730_init_one,
+	.remove		= __devexit_p(saa9730_remove_one),
 };
 
 
 static int __init saa9730_init(void)
 {
-        return pci_module_init(&saa9730_driver);
+	return pci_module_init(&saa9730_driver);
 }
 
 static void __exit saa9730_cleanup(void)
 {
-        pci_unregister_driver(&saa9730_driver);
+	pci_unregister_driver(&saa9730_driver);
 }
 
 module_init(saa9730_init);
 module_exit(saa9730_cleanup);
 
-
-
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+MODULE_DESCRIPTION("Philips SAA9730 ethernet driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
index 308440b..91b8d4f 100644
--- a/drivers/net/sk98lin/h/skdrv1st.h
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -39,9 +39,6 @@
 #ifndef __INC_SKDRV1ST_H
 #define __INC_SKDRV1ST_H
 
-/* Check kernel version */
-#include <linux/version.h>
-
 typedef struct s_AC	SK_AC;
 
 /* Set card versions */
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
index 4c56b8d..e5d6d95 100644
--- a/drivers/net/sk_mca.c
+++ b/drivers/net/sk_mca.c
@@ -93,7 +93,6 @@
 #include <linux/mca-legacy.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
index 7e7c995..d6fa182 100644
--- a/drivers/net/sk_mca.h
+++ b/drivers/net/sk_mca.h
@@ -1,5 +1,3 @@
-#include <linux/version.h>
-
 #ifndef _SK_MCA_INCLUDE_
 #define _SK_MCA_INCLUDE_
 
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 572f121..596c93b 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -37,12 +37,13 @@
 #include <linux/delay.h>
 #include <linux/crc32.h>
 #include <linux/dma-mapping.h>
+#include <linux/mii.h>
 #include <asm/irq.h>
 
 #include "skge.h"
 
 #define DRV_NAME		"skge"
-#define DRV_VERSION		"1.1"
+#define DRV_VERSION		"1.2"
 #define PFX			DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE	128
@@ -88,8 +89,8 @@
 static int skge_up(struct net_device *dev);
 static int skge_down(struct net_device *dev);
 static void skge_tx_clean(struct skge_port *skge);
-static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
-static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
 static void genesis_get_stats(struct skge_port *skge, u64 *data);
 static void yukon_get_stats(struct skge_port *skge, u64 *data);
 static void yukon_init(struct skge_hw *hw, int port);
@@ -129,7 +130,7 @@
 		      regs->len - B3_RI_WTO_R1);
 }
 
-/* Wake on Lan only supported on Yukon chps with rev 1 or above */
+/* Wake on Lan only supported on Yukon chips with rev 1 or above */
 static int wol_supported(const struct skge_hw *hw)
 {
 	return !((hw->chip_id == CHIP_ID_GENESIS ||
@@ -169,8 +170,8 @@
 	return 0;
 }
 
-/* Determine supported/adverised modes based on hardware.
- * Note: ethtoool ADVERTISED_xxx == SUPPORTED_xxx
+/* Determine supported/advertised modes based on hardware.
+ * Note: ethtool ADVERTISED_xxx == SUPPORTED_xxx
  */
 static u32 skge_supported_modes(const struct skge_hw *hw)
 {
@@ -531,13 +532,13 @@
 		return 78215; /* or:  78.125 MHz */
 }
 
-/* Chip hz to microseconds */
+/* Chip HZ to microseconds */
 static inline u32 skge_clk2usec(const struct skge_hw *hw, u32 ticks)
 {
 	return (ticks * 1000) / hwkhz(hw);
 }
 
-/* Microseconds to chip hz */
+/* Microseconds to chip HZ */
 static inline u32 skge_usecs2clk(const struct skge_hw *hw, u32 usec)
 {
 	return hwkhz(hw) * usec / 1000;
@@ -883,32 +884,37 @@
 		printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
 }
 
-static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
+static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
 {
 	int i;
-	u16 v;
 
 	xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
-	v = xm_read16(hw, port, XM_PHY_DATA);
+	xm_read16(hw, port, XM_PHY_DATA);
 
 	/* Need to wait for external PHY */
 	for (i = 0; i < PHY_RETRIES; i++) {
 		udelay(1);
-		if (xm_read16(hw, port, XM_MMU_CMD)
-		    & XM_MMU_PHY_RDY)
+		if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY)
 			goto ready;
 	}
 
-	printk(KERN_WARNING PFX "%s: phy read timed out\n",
-	       hw->dev[port]->name);
-	return 0;
+	return -ETIMEDOUT;
  ready:
-	v = xm_read16(hw, port, XM_PHY_DATA);
+	*val = xm_read16(hw, port, XM_PHY_DATA);
 
+	return 0;
+}
+
+static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
+{
+	u16 v = 0;
+	if (__xm_phy_read(hw, port, reg, &v))
+		printk(KERN_WARNING PFX "%s: phy read timed out\n",
+		       hw->dev[port]->name);
 	return v;
 }
 
-static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
 {
 	int i;
 
@@ -918,19 +924,11 @@
 			goto ready;
 		udelay(1);
 	}
-	printk(KERN_WARNING PFX "%s: phy write failed to come ready\n",
-	       hw->dev[port]->name);
-
+	return -EIO;
 
  ready:
 	xm_write16(hw, port, XM_PHY_DATA, val);
-	for (i = 0; i < PHY_RETRIES; i++) {
-		udelay(1);
-		if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
-			return;
-	}
-	printk(KERN_WARNING PFX "%s: phy write timed out\n",
-		       hw->dev[port]->name);
+	return 0;
 }
 
 static void genesis_init(struct skge_hw *hw)
@@ -1165,7 +1163,7 @@
 	xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext);
 	xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl);
 
-	/* Use link status change interrrupt */
+	/* Use link status change interrupt */
 	xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
 
 	bcom_check_link(hw, port);
@@ -1205,7 +1203,7 @@
 	skge_write32(hw, B2_GP_IO, r);
 	skge_read32(hw, B2_GP_IO);
 
-	/* Enable GMII interfac */
+	/* Enable GMII interface */
 	xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
 
 	bcom_phy_init(skge, jumbo);
@@ -1256,7 +1254,7 @@
 	 * that jumbo frames larger than 8192 bytes will be
 	 * truncated. Disabling all bad frame filtering causes
 	 * the RX FIFO to operate in streaming mode, in which
-	 * case the XMAC will start transfering frames out of the
+	 * case the XMAC will start transferring frames out of the
 	 * RX FIFO as soon as the FIFO threshold is reached.
 	 */
 	xm_write32(hw, port, XM_MODE, XM_DEF_MODE);
@@ -1323,7 +1321,7 @@
 		     port == 0 ? PA_CLR_TO_TX1 : PA_CLR_TO_TX2);
 
 	/*
-	 * If the transfer stucks at the MAC the STOP command will not
+	 * If the transfer sticks at the MAC the STOP command will not
 	 * terminate if we don't flush the XMAC's transmit FIFO !
 	 */
 	xm_write32(hw, port, XM_MODE,
@@ -1400,42 +1398,6 @@
 	}
 }
 
-static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
-{
-	int i;
-
-	gma_write16(hw, port, GM_SMI_DATA, val);
-	gma_write16(hw, port, GM_SMI_CTRL,
-			 GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg));
-	for (i = 0; i < PHY_RETRIES; i++) {
-		udelay(1);
-
-		if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
-			break;
-	}
-}
-
-static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
-{
-	int i;
-
-	gma_write16(hw, port, GM_SMI_CTRL,
-			 GM_SMI_CT_PHY_AD(hw->phy_addr)
-			 | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
-
-	for (i = 0; i < PHY_RETRIES; i++) {
-		udelay(1);
-		if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
-			goto ready;
-	}
-
-	printk(KERN_WARNING PFX "%s: phy read timeout\n",
-	       hw->dev[port]->name);
-	return 0;
- ready:
-	return gma_read16(hw, port, GM_SMI_DATA);
-}
-
 static void genesis_link_up(struct skge_port *skge)
 {
 	struct skge_hw *hw = skge->hw;
@@ -1549,7 +1511,55 @@
 
 }
 
-/* Marvell Phy Initailization */
+static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+{
+	int i;
+
+	gma_write16(hw, port, GM_SMI_DATA, val);
+	gma_write16(hw, port, GM_SMI_CTRL,
+			 GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg));
+	for (i = 0; i < PHY_RETRIES; i++) {
+		udelay(1);
+
+		if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
+			return 0;
+	}
+
+	printk(KERN_WARNING PFX "%s: phy write timeout\n",
+	       hw->dev[port]->name);
+	return -EIO;
+}
+
+static int __gm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
+{
+	int i;
+
+	gma_write16(hw, port, GM_SMI_CTRL,
+			 GM_SMI_CT_PHY_AD(hw->phy_addr)
+			 | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
+
+	for (i = 0; i < PHY_RETRIES; i++) {
+		udelay(1);
+		if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
+			goto ready;
+	}
+
+	return -ETIMEDOUT;
+ ready:
+	*val = gma_read16(hw, port, GM_SMI_DATA);
+	return 0;
+}
+
+static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
+{
+	u16 v = 0;
+	if (__gm_phy_read(hw, port, reg, &v))
+		printk(KERN_WARNING PFX "%s: phy read timeout\n",
+	       hw->dev[port]->name);
+	return v;
+}
+
+/* Marvell Phy Initialization */
 static void yukon_init(struct skge_hw *hw, int port)
 {
 	struct skge_port *skge = netdev_priv(hw->dev[port]);
@@ -1794,6 +1804,25 @@
 	skge_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
 }
 
+/* Go into power down mode */
+static void yukon_suspend(struct skge_hw *hw, int port)
+{
+	u16 ctrl;
+
+	ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+	ctrl |= PHY_M_PC_POL_R_DIS;
+	gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+	ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
+	ctrl |= PHY_CT_RESET;
+	gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+
+	/* switch IEEE compatible power down mode on */
+	ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
+	ctrl |= PHY_CT_PDOWN;
+	gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+}
+
 static void yukon_stop(struct skge_port *skge)
 {
 	struct skge_hw *hw = skge->hw;
@@ -1807,14 +1836,7 @@
 			 & ~(GM_GPCR_TX_ENA|GM_GPCR_RX_ENA));
 	gma_read16(hw, port, GM_GP_CTRL);
 
-	if (hw->chip_id == CHIP_ID_YUKON_LITE &&
-	    hw->chip_rev >= CHIP_REV_YU_LITE_A3) {
-		u32 io = skge_read32(hw, B2_GP_IO);
-
-		io |= GP_DIR_9 | GP_IO_9;
-		skge_write32(hw, B2_GP_IO, io);
-		skge_read32(hw, B2_GP_IO);
-	}
+	yukon_suspend(hw, port);
 
 	/* set GPHY Control reset */
 	skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
@@ -1997,6 +2019,51 @@
 	/* XXX restart autonegotiation? */
 }
 
+/* Basic MII support */
+static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mii_ioctl_data *data = if_mii(ifr);
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int err = -EOPNOTSUPP;
+
+	if (!netif_running(dev))
+		return -ENODEV;	/* Phy still in reset */
+
+	switch(cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = hw->phy_addr;
+
+		/* fallthru */
+	case SIOCGMIIREG: {
+		u16 val = 0;
+		spin_lock_bh(&hw->phy_lock);
+		if (hw->chip_id == CHIP_ID_GENESIS)
+			err = __xm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val);
+		else
+			err = __gm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val);
+		spin_unlock_bh(&hw->phy_lock);
+		data->val_out = val;
+		break;
+	}
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		spin_lock_bh(&hw->phy_lock);
+		if (hw->chip_id == CHIP_ID_GENESIS)
+			err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f,
+				   data->val_in);
+		else
+			err = gm_phy_write(hw, skge->port, data->reg_num & 0x1f,
+				   data->val_in);
+		spin_unlock_bh(&hw->phy_lock);
+		break;
+	}
+	return err;
+}
+
 static void skge_ramset(struct skge_hw *hw, u16 q, u32 start, size_t len)
 {
 	u32 end;
@@ -2089,7 +2156,7 @@
 	hw->intr_mask |= portirqmask[port];
 	skge_write32(hw, B0_IMSK, hw->intr_mask);
 
-	/* Initialze MAC */
+	/* Initialize MAC */
 	spin_lock_bh(&hw->phy_lock);
 	if (hw->chip_id == CHIP_ID_GENESIS)
 		genesis_mac_init(hw, port);
@@ -2409,7 +2476,7 @@
 	reg = gma_read16(hw, port, GM_RX_CTRL);
 	reg |= GM_RXCR_UCF_ENA;
 
-	if (dev->flags & IFF_PROMISC) 		/* promiscious */
+	if (dev->flags & IFF_PROMISC) 		/* promiscuous */
 		reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
 	else if (dev->flags & IFF_ALLMULTI)	/* all multicast */
 		memset(filter, 0xff, sizeof(filter));
@@ -2560,7 +2627,7 @@
 	unsigned int to_do = min(dev->quota, *budget);
 	unsigned int work_done = 0;
 
-	for (e = ring->to_clean; work_done < to_do; e = e->next) {
+	for (e = ring->to_clean; prefetch(e->next), work_done < to_do; e = e->next) {
 		struct skge_rx_desc *rd = e->desc;
 		struct sk_buff *skb;
 		u32 control;
@@ -2593,11 +2660,11 @@
 	if (work_done >=  to_do)
 		return 1; /* not done */
 
-	local_irq_disable();
-	__netif_rx_complete(dev);
+	netif_rx_complete(dev);
 	hw->intr_mask |= portirqmask[skge->port];
 	skge_write32(hw, B0_IMSK, hw->intr_mask);
-	local_irq_enable();
+	skge_read32(hw, B0_IMSK);
+
 	return 0;
 }
 
@@ -2609,7 +2676,7 @@
 	struct skge_element *e;
 
 	spin_lock(&skge->tx_lock);
-	for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+	for (e = ring->to_clean; prefetch(e->next), e != ring->to_use; e = e->next) {
 		struct skge_tx_desc *td = e->desc;
 		u32 control;
 
@@ -2732,7 +2799,7 @@
 }
 
 /*
- * Interrrupt from PHY are handled in tasklet (soft irq)
+ * Interrupt from PHY are handled in tasklet (soft irq)
  * because accessing phy registers requires spin wait which might
  * cause excess interrupt latency.
  */
@@ -2762,6 +2829,14 @@
 	local_irq_enable();
 }
 
+static inline void skge_wakeup(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	prefetch(skge->rx_ring.to_clean);
+	netif_rx_schedule(dev);
+}
+
 static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct skge_hw *hw = dev_id;
@@ -2773,12 +2848,12 @@
 	status &= hw->intr_mask;
 	if (status & IS_R1_F) {
 		hw->intr_mask &= ~IS_R1_F;
-		netif_rx_schedule(hw->dev[0]);
+		skge_wakeup(hw->dev[0]);
 	}
 
 	if (status & IS_R2_F) {
 		hw->intr_mask &= ~IS_R2_F;
-		netif_rx_schedule(hw->dev[1]);
+		skge_wakeup(hw->dev[1]);
 	}
 
 	if (status & IS_XA1_F)
@@ -2893,6 +2968,7 @@
  */
 static int skge_reset(struct skge_hw *hw)
 {
+	u32 reg;
 	u16 ctst;
 	u8 t8, mac_cfg, pmd_type, phy_type;
 	int i;
@@ -2971,6 +3047,7 @@
 		/* switch power to VCC (WA for VAUX problem) */
 		skge_write8(hw, B0_POWER_CTRL,
 			    PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
+
 		/* 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)) {
@@ -2978,6 +3055,14 @@
 			hw->intr_mask &= ~IS_HW_ERR;
 		}
 
+		/* Clear PHY COMA */
+		skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+		pci_read_config_dword(hw->pdev, PCI_DEV_REG1, &reg);
+		reg &= ~PCI_PHY_COMA;
+		pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg);
+		skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+
 		for (i = 0; i < hw->ports; i++) {
 			skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
 			skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
@@ -3048,6 +3133,7 @@
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
 	dev->open = skge_up;
 	dev->stop = skge_down;
+	dev->do_ioctl = skge_ioctl;
 	dev->hard_start_xmit = skge_xmit_frame;
 	dev->get_stats = skge_get_stats;
 	if (hw->chip_id == CHIP_ID_GENESIS)
@@ -3147,7 +3233,7 @@
 	}
 
 #ifdef __BIG_ENDIAN
-	/* byte swap decriptors in hardware */
+	/* byte swap descriptors in hardware */
 	{
 		u32 reg;
 
@@ -3158,14 +3244,13 @@
 #endif
 
 	err = -ENOMEM;
-	hw = kmalloc(sizeof(*hw), GFP_KERNEL);
+	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
 	if (!hw) {
 		printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
 		       pci_name(pdev));
 		goto err_out_free_regions;
 	}
 
-	memset(hw, 0, sizeof(*hw));
 	hw->pdev = pdev;
 	spin_lock_init(&hw->phy_lock);
 	tasklet_init(&hw->ext_tasklet, skge_extirq, (unsigned long) hw);
@@ -3188,7 +3273,7 @@
 	if (err)
 		goto err_out_free_irq;
 
-	printk(KERN_INFO PFX "addr 0x%lx irq %d chip %s rev %d\n",
+	printk(KERN_INFO PFX DRV_VERSION " addr 0x%lx irq %d chip %s rev %d\n",
 	       pci_resource_start(pdev, 0), pdev->irq,
 	       skge_board_name(hw), hw->chip_rev);
 
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 72c175b..ee123c1 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -6,6 +6,8 @@
 
 /* PCI config registers */
 #define PCI_DEV_REG1	0x40
+#define  PCI_PHY_COMA	0x8000000
+#define  PCI_VIO	0x2000000
 #define PCI_DEV_REG2	0x44
 #define  PCI_REV_DESC	 0x4
 
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 74d5f1a..c91e2e8 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -2183,9 +2183,8 @@
  *	0 --> there is a device
  *	anything else, error
  */
-static int smc_drv_probe(struct device *dev)
+static int smc_drv_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct net_device *ndev;
 	struct resource *res;
 	unsigned int __iomem *addr;
@@ -2212,7 +2211,7 @@
 		goto out_release_io;
 	}
 	SET_MODULE_OWNER(ndev);
-	SET_NETDEV_DEV(ndev, dev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	ndev->dma = (unsigned char)-1;
 	ndev->irq = platform_get_irq(pdev, 0);
@@ -2233,7 +2232,7 @@
 		goto out_release_attrib;
 	}
 
-	dev_set_drvdata(dev, ndev);
+	platform_set_drvdata(pdev, ndev);
 	ret = smc_probe(ndev, addr);
 	if (ret != 0)
 		goto out_iounmap;
@@ -2249,7 +2248,7 @@
 	return 0;
 
  out_iounmap:
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 	iounmap(addr);
  out_release_attrib:
 	smc_release_attrib(pdev);
@@ -2263,14 +2262,13 @@
 	return ret;
 }
 
-static int smc_drv_remove(struct device *dev)
+static int smc_drv_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct net_device *ndev = dev_get_drvdata(dev);
+	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct smc_local *lp = netdev_priv(ndev);
 	struct resource *res;
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	unregister_netdev(ndev);
 
@@ -2295,9 +2293,9 @@
 	return 0;
 }
 
-static int smc_drv_suspend(struct device *dev, pm_message_t state)
+static int smc_drv_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct net_device *ndev = dev_get_drvdata(dev);
+	struct net_device *ndev = platform_get_drvdata(dev);
 
 	if (ndev) {
 		if (netif_running(ndev)) {
@@ -2309,14 +2307,13 @@
 	return 0;
 }
 
-static int smc_drv_resume(struct device *dev)
+static int smc_drv_resume(struct platform_device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct net_device *ndev = dev_get_drvdata(dev);
+	struct net_device *ndev = platform_get_drvdata(dev);
 
 	if (ndev) {
 		struct smc_local *lp = netdev_priv(ndev);
-		smc_enable_device(pdev);
+		smc_enable_device(dev);
 		if (netif_running(ndev)) {
 			smc_reset(ndev);
 			smc_enable(ndev);
@@ -2328,13 +2325,14 @@
 	return 0;
 }
 
-static struct device_driver smc_driver = {
-	.name		= CARDNAME,
-	.bus		= &platform_bus_type,
+static struct platform_driver smc_driver = {
 	.probe		= smc_drv_probe,
 	.remove		= smc_drv_remove,
 	.suspend	= smc_drv_suspend,
 	.resume		= smc_drv_resume,
+	.driver		= {
+		.name	= CARDNAME,
+	},
 };
 
 static int __init smc_init(void)
@@ -2348,12 +2346,12 @@
 #endif
 #endif
 
-	return driver_register(&smc_driver);
+	return platform_driver_register(&smc_driver);
 }
 
 static void __exit smc_cleanup(void)
 {
-	driver_unregister(&smc_driver);
+	platform_driver_unregister(&smc_driver);
 }
 
 module_init(smc_init);
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 817f200..a10cd18 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -289,6 +289,38 @@
 #define RPC_LSA_DEFAULT		RPC_LED_TX_RX
 #define RPC_LSB_DEFAULT		RPC_LED_100_10
 
+#elif defined(CONFIG_SOC_AU1X00)
+
+#include <au1xxx.h>
+
+/* We can only do 16-bit reads and writes in the static memory space. */
+#define SMC_CAN_USE_8BIT	0
+#define SMC_CAN_USE_16BIT	1
+#define SMC_CAN_USE_32BIT	0
+#define SMC_IO_SHIFT		0
+#define SMC_NOWAIT		1
+
+#define SMC_inw(a, r)		au_readw((unsigned long)((a) + (r)))
+#define SMC_insw(a, r, p, l)	\
+	do {	\
+		unsigned long _a = (unsigned long)((a) + (r)); \
+		int _l = (l); \
+		u16 *_p = (u16 *)(p); \
+		while (_l-- > 0) \
+			*_p++ = au_readw(_a); \
+	} while(0)
+#define SMC_outw(v, a, r)	au_writew(v, (unsigned long)((a) + (r)))
+#define SMC_outsw(a, r, p, l)	\
+	do {	\
+		unsigned long _a = (unsigned long)((a) + (r)); \
+		int _l = (l); \
+		const u16 *_p = (const u16 *)(p); \
+		while (_l-- > 0) \
+			au_writew(*_p++ , _a); \
+	} while(0)
+
+#define set_irq_type(irq, type) do {} while (0)
+
 #else
 
 #define SMC_CAN_USE_8BIT	1
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index c796f41..0d765f1 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -2290,7 +2290,6 @@
 }
 
 static struct pci_driver spider_net_driver = {
-	.owner		= THIS_MODULE,
 	.name		= spider_net_driver_name,
 	.id_table	= spider_net_pci_tbl,
 	.probe		= spider_net_probe,
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 38b2b0a..d167ded 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -147,7 +147,6 @@
 #define DRV_RELDATE	"October 3, 2005"
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index d04c918..4f75696 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -344,9 +344,10 @@
 
 static struct platform_device *proteon_dev[ISATR_MAX_ADAPTERS];
 
-static struct device_driver proteon_driver = {
-	.name		= "proteon",
-	.bus		= &platform_bus_type,
+static struct platform_driver proteon_driver = {
+	.driver		= {
+		.name	= "proteon",
+	},
 };
 
 static int __init proteon_init(void)
@@ -355,7 +356,7 @@
 	struct platform_device *pdev;
 	int i, num = 0, err = 0;
 
-	err = driver_register(&proteon_driver);
+	err = platform_driver_register(&proteon_driver);
 	if (err)
 		return err;
 
@@ -372,7 +373,7 @@
 		err = setup_card(dev, &pdev->dev);
 		if (!err) {
 			proteon_dev[i] = pdev;
-			dev_set_drvdata(&pdev->dev, dev);
+			platform_set_drvdata(pdev, dev);
 			++num;
 		} else {
 			platform_device_unregister(pdev);
@@ -399,17 +400,17 @@
 		
 		if (!pdev)
 			continue;
-		dev = dev_get_drvdata(&pdev->dev);
+		dev = platform_get_drvdata(pdev);
 		unregister_netdev(dev);
 		release_region(dev->base_addr, PROTEON_IO_EXTENT);
 		free_irq(dev->irq, dev);
 		free_dma(dev->dma);
 		tmsdev_term(dev);
 		free_netdev(dev);
-		dev_set_drvdata(&pdev->dev, NULL);
+		platform_set_drvdata(pdev, NULL);
 		platform_device_unregister(pdev);
 	}
-	driver_unregister(&proteon_driver);
+	platform_driver_unregister(&proteon_driver);
 }
 
 module_init(proteon_init);
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
index 72cf708..d6ba41c 100644
--- a/drivers/net/tokenring/skisa.c
+++ b/drivers/net/tokenring/skisa.c
@@ -354,9 +354,10 @@
 
 static struct platform_device *sk_isa_dev[ISATR_MAX_ADAPTERS];
 
-static struct device_driver sk_isa_driver = {
-	.name		= "skisa",
-	.bus		= &platform_bus_type,
+static struct platform_driver sk_isa_driver = {
+	.driver		= {
+		.name	= "skisa",
+	},
 };
 
 static int __init sk_isa_init(void)
@@ -365,7 +366,7 @@
 	struct platform_device *pdev;
 	int i, num = 0, err = 0;
 
-	err = driver_register(&sk_isa_driver);
+	err = platform_driver_register(&sk_isa_driver);
 	if (err)
 		return err;
 
@@ -382,7 +383,7 @@
 		err = setup_card(dev, &pdev->dev);
 		if (!err) {
 			sk_isa_dev[i] = pdev;
-			dev_set_drvdata(&sk_isa_dev[i]->dev, dev);
+			platform_set_drvdata(sk_isa_dev[i], dev);
 			++num;
 		} else {
 			platform_device_unregister(pdev);
@@ -409,17 +410,17 @@
 
 		if (!pdev)
 			continue;
-		dev = dev_get_drvdata(&pdev->dev);
+		dev = platform_get_drvdata(pdev);
 		unregister_netdev(dev);
 		release_region(dev->base_addr, SK_ISA_IO_EXTENT);
 		free_irq(dev->irq, dev);
 		free_dma(dev->dma);
 		tmsdev_term(dev);
 		free_netdev(dev);
-		dev_set_drvdata(&pdev->dev, NULL);
+		platform_set_drvdata(pdev, NULL);
 		platform_device_unregister(pdev);
 	}
-	driver_unregister(&sk_isa_driver);
+	platform_driver_unregister(&sk_isa_driver);
 }
 
 module_init(sk_isa_init);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index a368d08..82c6b75 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -61,7 +61,6 @@
 #include <linux/timer.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/wait.h>
 #include <asm/io.h>
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 7187958..00e5516 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -330,7 +330,7 @@
 
 config ATMEL
       tristate "Atmel at76c50x chipset  802.11b support"
-      depends on NET_RADIO && EXPERIMENTAL
+      depends on NET_RADIO
       select FW_LOADER
       select CRC32
        ---help---
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 6afc6e5d..340ab4e 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -4535,9 +4535,8 @@
 	StatusRid status_rid;
 	int i;
 
-	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	memset(file->private_data, 0, sizeof(struct proc_data));
 	data = (struct proc_data *)file->private_data;
 	if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
@@ -4615,9 +4614,8 @@
 	int i, j;
 	u32 *vals = stats.vals;
 
-	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	memset(file->private_data, 0, sizeof(struct proc_data));
 	data = (struct proc_data *)file->private_data;
 	if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
@@ -4881,20 +4879,18 @@
 	struct airo_info *ai = dev->priv;
 	int i;
 
-	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	memset(file->private_data, 0, sizeof(struct proc_data));
 	data = (struct proc_data *)file->private_data;
 	if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
 		return -ENOMEM;
 	}
-	if ((data->wbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
+	if ((data->wbuffer = kzalloc( 2048, GFP_KERNEL )) == NULL) {
 		kfree (data->rbuffer);
 		kfree (file->private_data);
 		return -ENOMEM;
 	}
-	memset( data->wbuffer, 0, 2048 );
 	data->maxwritelen = 2048;
 	data->on_close = proc_config_on_close;
 
@@ -5155,24 +5151,21 @@
 	int j=0;
 	int rc;
 
-	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	memset(file->private_data, 0, sizeof(struct proc_data));
 	memset(&wkr, 0, sizeof(wkr));
 	data = (struct proc_data *)file->private_data;
-	if ((data->rbuffer = kmalloc( 180, GFP_KERNEL )) == NULL) {
+	if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
 		return -ENOMEM;
 	}
-	memset(data->rbuffer, 0, 180);
 	data->writelen = 0;
 	data->maxwritelen = 80;
-	if ((data->wbuffer = kmalloc( 80, GFP_KERNEL )) == NULL) {
+	if ((data->wbuffer = kzalloc( 80, GFP_KERNEL )) == NULL) {
 		kfree (data->rbuffer);
 		kfree (file->private_data);
 		return -ENOMEM;
 	}
-	memset( data->wbuffer, 0, 80 );
 	data->on_close = proc_wepkey_on_close;
 
 	ptr = data->rbuffer;
@@ -5203,9 +5196,8 @@
 	char *ptr;
 	SsidRid SSID_rid;
 
-	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	memset(file->private_data, 0, sizeof(struct proc_data));
 	data = (struct proc_data *)file->private_data;
 	if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
@@ -5213,12 +5205,11 @@
 	}
 	data->writelen = 0;
 	data->maxwritelen = 33*3;
-	if ((data->wbuffer = kmalloc( 33*3, GFP_KERNEL )) == NULL) {
+	if ((data->wbuffer = kzalloc( 33*3, GFP_KERNEL )) == NULL) {
 		kfree (data->rbuffer);
 		kfree (file->private_data);
 		return -ENOMEM;
 	}
-	memset( data->wbuffer, 0, 33*3 );
 	data->on_close = proc_SSID_on_close;
 
 	readSsidRid(ai, &SSID_rid);
@@ -5247,9 +5238,8 @@
 	char *ptr;
 	APListRid APList_rid;
 
-	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	memset(file->private_data, 0, sizeof(struct proc_data));
 	data = (struct proc_data *)file->private_data;
 	if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
@@ -5257,12 +5247,11 @@
 	}
 	data->writelen = 0;
 	data->maxwritelen = 4*6*3;
-	if ((data->wbuffer = kmalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
+	if ((data->wbuffer = kzalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
 		kfree (data->rbuffer);
 		kfree (file->private_data);
 		return -ENOMEM;
 	}
-	memset( data->wbuffer, 0, data->maxwritelen );
 	data->on_close = proc_APList_on_close;
 
 	readAPListRid(ai, &APList_rid);
@@ -5297,9 +5286,8 @@
 	/* If doLoseSync is not 1, we won't do a Lose Sync */
 	int doLoseSync = -1;
 
-	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	memset(file->private_data, 0, sizeof(struct proc_data));
 	data = (struct proc_data *)file->private_data;
 	if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
 		kfree (file->private_data);
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index 96ed8da..e328547 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -170,12 +170,11 @@
 	DEBUG(0, "airo_attach()\n");
 
 	/* Initialize the dev_link_t structure */
-	link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+	link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
 	if (!link) {
 		printk(KERN_ERR "airo_cs: no memory for new device\n");
 		return NULL;
 	}
-	memset(link, 0, sizeof(struct dev_link_t));
 	
 	/* Interrupt setup */
 	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
@@ -194,13 +193,12 @@
 	link->conf.IntType = INT_MEMORY_AND_IO;
 	
 	/* Allocate space for private device-specific data */
-	local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+	local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
 	if (!local) {
 		printk(KERN_ERR "airo_cs: no memory for new device\n");
 		kfree (link);
 		return NULL;
 	}
-	memset(local, 0, sizeof(local_info_t));
 	link->priv = local;
 	
 	/* Register with Card Services */
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 1fbe027..5e53c52 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -72,7 +72,7 @@
 #include "atmel.h"
 
 #define DRIVER_MAJOR 0
-#define DRIVER_MINOR 96
+#define DRIVER_MINOR 98
 
 MODULE_AUTHOR("Simon Kelley");
 MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
@@ -1504,7 +1504,7 @@
         return len;
 }
 
-struct net_device *init_atmel_card( unsigned short irq, int port, const AtmelFWType fw_type,  
+struct net_device *init_atmel_card( unsigned short irq, unsigned long port, const AtmelFWType fw_type,  
 				    struct device *sys_dev, int (*card_present)(void *), void *card)
 {
 	struct net_device *dev;
@@ -1605,8 +1605,8 @@
 		goto err_out_free;
 	}
 
-	if (priv->bus_type == BUS_TYPE_PCI &&
-	    !request_region( dev->base_addr, 64, dev->name )) {
+	if (!request_region(dev->base_addr, 32, 
+			    priv->bus_type == BUS_TYPE_PCCARD ?  "atmel_cs" : "atmel_pci")) {
 		goto err_out_irq;
 	}
 	
@@ -1622,15 +1622,16 @@
 	
 	create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv);	
 	
-	printk(KERN_INFO "%s: Atmel at76c50x wireless. Version %d.%d simon@thekelleys.org.uk\n",
-	       dev->name, DRIVER_MAJOR, DRIVER_MINOR);
+	printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+	       dev->name, DRIVER_MAJOR, DRIVER_MINOR,
+	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
 	
 	SET_MODULE_OWNER(dev);
 	return dev;
 	
  err_out_res:
-	if (priv->bus_type == BUS_TYPE_PCI)
-	        release_region( dev->base_addr, 64 );
+	release_region( dev->base_addr, 32);
  err_out_irq:
 	free_irq(dev->irq, dev);
  err_out_free:
@@ -1640,7 +1641,7 @@
 
 EXPORT_SYMBOL(init_atmel_card);
 
-void stop_atmel_card(struct net_device *dev, int freeres)
+void stop_atmel_card(struct net_device *dev)
 {
 	struct atmel_private *priv = netdev_priv(dev);
 		
@@ -1654,10 +1655,7 @@
 	remove_proc_entry("driver/atmel", NULL);
 	free_irq(dev->irq, dev);
 	kfree(priv->firmware);
-	if (freeres) {
-		/* PCMCIA frees this stuff, so only for PCI */
-	        release_region(dev->base_addr, 64);
-        }
+	release_region(dev->base_addr, 32);
 	free_netdev(dev);
 }
 
@@ -1810,9 +1808,9 @@
 	}
 	if(dwrq->flags & IW_ENCODE_RESTRICTED)
 		priv->exclude_unencrypted = 1;
-	if(dwrq->flags & IW_ENCODE_OPEN)
+       	if(dwrq->flags & IW_ENCODE_OPEN) 
 		priv->exclude_unencrypted = 0;
-	
+       
 	return -EINPROGRESS;		/* Call commit handler */
 }
 
@@ -1827,11 +1825,12 @@
 	
 	if (!priv->wep_is_on)
 		dwrq->flags = IW_ENCODE_DISABLED;
-	else if (priv->exclude_unencrypted)
-		dwrq->flags = IW_ENCODE_RESTRICTED;
-	else
-		dwrq->flags = IW_ENCODE_OPEN;
-		
+	else {
+		if (priv->exclude_unencrypted)
+			dwrq->flags = IW_ENCODE_RESTRICTED;
+		else
+			dwrq->flags = IW_ENCODE_OPEN;
+	}
 		/* Which key do we want ? -1 -> tx index */
 	if (index < 0 || index >= 4)
 		index = priv->default_key;
@@ -2217,7 +2216,7 @@
 	int k,i,j;
 
 	dwrq->length = sizeof(struct iw_range);
-	memset(range, 0, sizeof(range));
+	memset(range, 0, sizeof(struct iw_range));
 	range->min_nwid = 0x0000;
 	range->max_nwid = 0x0000;
 	range->num_channels = 0;
@@ -2645,8 +2644,8 @@
 	} 
 }
 
- 
-static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len)
+
+static void send_authentication_request(struct atmel_private *priv, u16 system, u8 *challenge, int challenge_len)
 {
 	struct ieee80211_hdr_4addr header;
 	struct auth_body auth;
@@ -2658,14 +2657,11 @@
 	memcpy(header.addr2, priv->dev->dev_addr, 6);
 	memcpy(header.addr3, priv->CurrentBSSID, 6);
 	
-	if (priv->wep_is_on) {
-		auth.alg = cpu_to_le16(C80211_MGMT_AAN_SHAREDKEY); 
+	if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) 
 		/* no WEP for authentication frames with TrSeqNo 1 */
-		if (priv->CurrentAuthentTransactionSeqNum != 1)
-			header.frame_ctl |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-	} else {
-		auth.alg = cpu_to_le16(C80211_MGMT_AAN_OPENSYSTEM);
-	}
+                header.frame_ctl |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+	
+	auth.alg = cpu_to_le16(system); 
 
 	auth.status = 0;
 	auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum);
@@ -2834,6 +2830,7 @@
 	struct auth_body *auth = (struct auth_body *)priv->rx_buf;
 	u16 status = le16_to_cpu(auth->status);
 	u16 trans_seq_no = le16_to_cpu(auth->trans_seq);
+	u16 system = le16_to_cpu(auth->alg);
 	
 	if (status == C80211_MGMT_SC_Success && !priv->wep_is_on) { 
 		/* no WEP */
@@ -2855,7 +2852,7 @@
 				
 		if (trans_seq_no == 0x0002 &&
 		    auth->el_id == C80211_MGMT_ElementID_ChallengeText) {
-			send_authentication_request(priv, auth->chall_text, auth->chall_text_len);
+			send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len);
 			return;
 		}
 		
@@ -2872,14 +2869,20 @@
 		}
 	}			
 	
-	if (status == C80211_MGMT_SC_AuthAlgNotSupported && priv->connect_to_any_BSS) {
-		int bss_index;
-		
-		priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
-		
-		if ((bss_index  = retrieve_bss(priv)) != -1) {
-			atmel_join_bss(priv, bss_index);
-			return;
+	if (status == C80211_MGMT_SC_AuthAlgNotSupported) {
+		/* Do opensystem first, then try sharedkey */
+		if (system ==  C80211_MGMT_AAN_OPENSYSTEM) {
+			priv->CurrentAuthentTransactionSeqNum = 0x001;
+			send_authentication_request(priv, C80211_MGMT_AAN_SHAREDKEY, NULL, 0);
+		} else if (priv->connect_to_any_BSS) {
+			int bss_index;
+			
+			priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
+			
+			if ((bss_index  = retrieve_bss(priv)) != -1) {
+				atmel_join_bss(priv, bss_index);
+				return;
+			}
 		}
 	}
 	
@@ -3205,7 +3208,7 @@
 		  priv->AuthenticationRequestRetryCnt++;
 		  priv->CurrentAuthentTransactionSeqNum = 0x0001;
 		  mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
-		  send_authentication_request(priv, NULL, 0);
+		  send_authentication_request(priv, C80211_MGMT_AAN_OPENSYSTEM, NULL, 0);
 	  }
 	  
 	  break;
@@ -3312,7 +3315,7 @@
 				
 				mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
 				priv->CurrentAuthentTransactionSeqNum = 0x0001;
-				send_authentication_request(priv, NULL, 0);
+				send_authentication_request(priv, C80211_MGMT_AAN_SHAREDKEY, NULL, 0);
 			}
 			return;
 		}
@@ -3482,11 +3485,6 @@
 			printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name);
 			memcpy(dev->dev_addr, default_mac, 6);
 		}
-		printk(KERN_INFO "%s: MAC address %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-		       dev->name,
-		       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 rc;
diff --git a/drivers/net/wireless/atmel.h b/drivers/net/wireless/atmel.h
index 825000e..b9b3e5b 100644
--- a/drivers/net/wireless/atmel.h
+++ b/drivers/net/wireless/atmel.h
@@ -35,9 +35,9 @@
 	ATMEL_FW_TYPE_506
 } AtmelFWType;
 
-struct net_device *init_atmel_card(unsigned short, int, const AtmelFWType, struct device *, 
+struct net_device *init_atmel_card(unsigned short, unsigned long, const AtmelFWType, struct device *, 
 				    int (*present_func)(void *), void * );
-void stop_atmel_card( struct net_device *, int );
+void stop_atmel_card( struct net_device *);
 int atmel_open( struct net_device * );
 
 #endif
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 195cb36..17d1fd9 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -63,6 +63,7 @@
    be present but disabled -- but it can then be enabled for specific
    modules at load time with a 'pc_debug=#' option to insmod.
 */
+
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
 module_param(pc_debug, int, 0);
@@ -180,12 +181,11 @@
 	DEBUG(0, "atmel_attach()\n");
 
 	/* Initialize the dev_link_t structure */
-	link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+	link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
 	if (!link) {
 		printk(KERN_ERR "atmel_cs: no memory for new device\n");
 		return NULL;
 	}
-	memset(link, 0, sizeof(struct dev_link_t));
 	
 	/* Interrupt setup */
 	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
@@ -204,13 +204,12 @@
 	link->conf.IntType = INT_MEMORY_AND_IO;
 	
 	/* Allocate space for private device-specific data */
-	local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+	local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
 	if (!local) {
 		printk(KERN_ERR "atmel_cs: no memory for new device\n");
 		kfree (link);
 		return NULL;
 	}
-	memset(local, 0, sizeof(local_info_t));
 	link->priv = local;
 	
 	/* Register with Card Services */
@@ -287,41 +286,6 @@
 	return 0;
 }
 
-/* list of cards we know about and their firmware requirements.
-   Go either by Manfid or version strings.
-   Cards not in this list will need a firmware parameter to the module
-   in all probability. Note that the SMC 2632 V2 and V3 have the same
-   manfids, so we ignore those and use the version1 strings. */
-
-static struct { 
-	int manf, card;
-	char *ver1;
-	AtmelFWType firmware;
-	char *name;
-} card_table[] = {
-	{ 0, 0, "WLAN/802.11b PC CARD", ATMEL_FW_TYPE_502D, "Actiontec 802CAT1" },  
-	{ 0, 0, "ATMEL/AT76C502AR", ATMEL_FW_TYPE_502, "NoName-RFMD" }, 
-	{ 0, 0, "ATMEL/AT76C502AR_D", ATMEL_FW_TYPE_502D, "NoName-revD" }, 
-	{ 0, 0, "ATMEL/AT76C502AR_E", ATMEL_FW_TYPE_502E, "NoName-revE" },
-	{ 0, 0, "ATMEL/AT76C504", ATMEL_FW_TYPE_504, "NoName-504" },
-	{ 0, 0, "ATMEL/AT76C504A", ATMEL_FW_TYPE_504A_2958, "NoName-504a-2958" },
-	{ 0, 0, "ATMEL/AT76C504_R", ATMEL_FW_TYPE_504_2958, "NoName-504-2958" },
-	{ MANFID_3COM, 0x0620, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRWE62092B" }, 
-	{ MANFID_3COM, 0x0696, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRSHPW196" }, 
-	{ 0, 0, "SMC/2632W-V2", ATMEL_FW_TYPE_502, "SMC 2632W-V2" },
-	{ 0, 0, "SMC/2632W", ATMEL_FW_TYPE_502D, "SMC 2632W-V3" },
-	{ 0xd601, 0x0007, NULL, ATMEL_FW_TYPE_502, "Sitecom WLAN-011" }, 
-	{ 0x01bf, 0x3302, NULL, ATMEL_FW_TYPE_502E, "Belkin F5D6020-V2" }, 
-	{ 0, 0, "BT/Voyager 1020 Laptop Adapter", ATMEL_FW_TYPE_502, "BT Voyager 1020" },
-	{ 0, 0, "IEEE 802.11b/Wireless LAN PC Card", ATMEL_FW_TYPE_502, "Siemens Gigaset PC Card II" },
-	{ 0, 0, "IEEE 802.11b/Wireless LAN Card S", ATMEL_FW_TYPE_504_2958, "Siemens Gigaset PC Card II" },
-	{ 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", ATMEL_FW_TYPE_502E, "CNet CNWLC-811ARL" },
-	{ 0, 0, "Wireless/PC_CARD", ATMEL_FW_TYPE_502D, "Planet WL-3552" },
-	{ 0, 0, "OEM/11Mbps Wireless LAN PC Card V-3", ATMEL_FW_TYPE_502, "OEM 11Mbps WLAN PCMCIA Card" },
-	{ 0, 0, "11WAVE/11WP611AL-E", ATMEL_FW_TYPE_502E, "11WAVE WaveBuddy" },
-	{ 0, 0, "LG/LW2100N", ATMEL_FW_TYPE_502E, "LG LW2100N 11Mbps WLAN PCMCIA Card" },
-};
-
 static void atmel_config(dev_link_t *link)
 {
 	client_handle_t handle;
@@ -330,10 +294,11 @@
 	local_info_t *dev;
 	int last_fn, last_ret;
 	u_char buf[64];
-	int card_index = -1, done = 0;
-	
+	struct pcmcia_device_id *did;
+
 	handle = link->handle;
 	dev = link->priv;
+	did = handle_to_dev(handle).driver_data;
 
 	DEBUG(0, "atmel_config(0x%p)\n", link);
 	
@@ -342,59 +307,6 @@
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
 	
-	tuple.DesiredTuple = CISTPL_MANFID;
-	if (pcmcia_get_first_tuple(handle, &tuple) == 0) {
-		int i;
-		cistpl_manfid_t *manfid;
-		CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-		CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-		manfid = &(parse.manfid);
-		for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
-			if (!card_table[i].ver1 &&
-			    manfid->manf == card_table[i].manf &&
-			    manfid->card == card_table[i].card) {
-				card_index = i;
-				done = 1;
-			}
-		}
-	}
-
-	tuple.DesiredTuple = CISTPL_VERS_1;
-	if (!done && (pcmcia_get_first_tuple(handle, &tuple) == 0)) {
-		int i, j, k;
-		cistpl_vers_1_t *ver1;
-		CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-		CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-		ver1 = &(parse.version_1);
-		
-		for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
-			for (j = 0; j < ver1->ns; j++) {
-				char *p = card_table[i].ver1;
-				char *q = &ver1->str[ver1->ofs[j]];
-				if (!p)
-					goto mismatch;
-				for (k = 0; k < j; k++) {
-					while ((*p != '\0') && (*p != '/')) p++;
-					if (*p == '\0') {
-						if (*q != '\0')
-							goto mismatch;
-					} else {
-						p++;
-					}
-				}
-				while((*q != '\0') && (*p != '\0') && 
-				      (*p != '/') && (*p == *q)) p++, q++;
-				if (((*p != '\0') && *p != '/') || *q != '\0')
-					goto mismatch;
-			}
-			card_index = i;
-			break;	/* done */
-			
-		mismatch:
-			j = 0; /* dummy stmt to shut up compiler */
-		}
-	}		
-
 	/*
 	  This reads the card's CONFIG tuple to find its configuration
 	  registers.
@@ -511,12 +423,13 @@
 	((local_info_t*)link->priv)->eth_dev = 
 		init_atmel_card(link->irq.AssignedIRQ,
 				link->io.BasePort1,
-				card_index == -1 ? ATMEL_FW_TYPE_NONE :  card_table[card_index].firmware,
+				did ? did->driver_info : ATMEL_FW_TYPE_NONE,
 				&handle_to_dev(handle),
 				card_present, 
 				link);
 	if (!((local_info_t*)link->priv)->eth_dev) 
-		goto cs_failed;
+			goto cs_failed;
+	
 	
 	/*
 	  At this point, the dev_node_t structure(s) need to be
@@ -525,26 +438,7 @@
 	strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
 	dev->node.major = dev->node.minor = 0;
 	link->dev = &dev->node;
-	
-	/* Finally, report what we've done */
-	printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d",
-	       dev->node.dev_name,
-	       card_index == -1 ? "" :  card_table[card_index].name,
-	       card_index == -1 ? "" : " ",
-	       link->conf.ConfigIndex,
-	       link->conf.Vcc/10, link->conf.Vcc%10);
-	if (link->conf.Vpp1)
-		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
-	if (link->conf.Attributes & CONF_ENABLE_IRQ)
-		printk(", irq %d", link->irq.AssignedIRQ);
-	if (link->io.NumPorts1)
-		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
-		       link->io.BasePort1+link->io.NumPorts1-1);
-	if (link->io.NumPorts2)
-		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
-		       link->io.BasePort2+link->io.NumPorts2-1);
-	printk("\n");
-	
+			
 	link->state &= ~DEV_CONFIG_PENDING;
 	return;
 	
@@ -571,7 +465,7 @@
 	link->dev = NULL;
 	
 	if (dev) 
-		stop_atmel_card(dev, 0);
+		stop_atmel_card(dev);
 	((local_info_t*)link->priv)->eth_dev = NULL; 
 	
 	/* Don't bother checking to see if these succeed or not */
@@ -639,25 +533,47 @@
 } /* atmel_event */
 
 /*====================================================================*/
+/* We use the driver_info field to store the correct firmware type for a card. */
+
+#define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \
+	.match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+			PCMCIA_DEV_ID_MATCH_CARD_ID, \
+	.manf_id = (manf), \
+	.card_id = (card), \
+        .driver_info = (kernel_ulong_t)(info), }
+
+#define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \
+	.match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+			PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+	.prod_id = { (v1), (v2), NULL, NULL }, \
+	.prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+        .driver_info = (kernel_ulong_t)(info), }
+
 static struct pcmcia_device_id atmel_ids[] = {
-	PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0620),
-	PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0696),
-	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3302),
-	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0007),
-	PCMCIA_DEVICE_PROD_ID12("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9),
-	PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f),
-	PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504", 0xabda4164, 0x5040670a),
-	PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f),
-	PCMCIA_DEVICE_PROD_ID12("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5),
-	PCMCIA_DEVICE_PROD_ID12("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b),
-	PCMCIA_DEVICE_PROD_ID12("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6),
-	PCMCIA_DEVICE_PROD_ID12("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68),
-	PCMCIA_DEVICE_PROD_ID12("SMC", "2632W", 0xc4f8b18b, 0x30f38774),
-	PCMCIA_DEVICE_PROD_ID12("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377),
-	PCMCIA_DEVICE_PROD_ID12("Wireless", "PC", 0xa407ecdd, 0x556e4d7e),
-	PCMCIA_DEVICE_PROD_ID12("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4),
+	PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
+	PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
+	PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
+	PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502),
+	PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E),
+	PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502),
+	PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D),
+	PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E),
+	PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958),
+	PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504),
+	PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958),
+	PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502),
+	PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E),
+	PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502),
+	PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958),
+	PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502),
+	PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D),
+	PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502),
+	PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D),
+	PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D),
+	PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E),
 	PCMCIA_DEVICE_NULL
 };
+
 MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
 
 static struct pcmcia_driver atmel_driver = {
diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c
index 2eb00a9..a61b3bc 100644
--- a/drivers/net/wireless/atmel_pci.c
+++ b/drivers/net/wireless/atmel_pci.c
@@ -72,7 +72,7 @@
 
 static void __devexit atmel_pci_remove(struct pci_dev *pdev)
 {
-	stop_atmel_card(pci_get_drvdata(pdev), 1);
+	stop_atmel_card(pci_get_drvdata(pdev));
 }
 
 static int __init atmel_init_module(void)
diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c
index 6a96cd9..3d2ea61 100644
--- a/drivers/net/wireless/hostap/hostap.c
+++ b/drivers/net/wireless/hostap/hostap.c
@@ -13,7 +13,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 59fc155..abfae7f 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -31,7 +31,6 @@
 
 
 #include <linux/config.h>
-#include <linux/version.h>
 
 #include <asm/delay.h>
 #include <asm/uaccess.h>
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index da0c80f..2e85bdc 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -5,7 +5,6 @@
  * Andy Warner <andyw@pobox.com> */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/if.h>
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index 78d67b408..94fe244 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -8,7 +8,6 @@
 
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/if.h>
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index ad7f8cd..a2e6214 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -167,17 +167,16 @@
 
 #include "ipw2100.h"
 
-#define IPW2100_VERSION "1.1.0"
+#define IPW2100_VERSION "1.1.3"
 
 #define DRV_NAME	"ipw2100"
 #define DRV_VERSION	IPW2100_VERSION
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2100 Network Driver"
-#define DRV_COPYRIGHT	"Copyright(c) 2003-2004 Intel Corporation"
-
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2005 Intel Corporation"
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW_DEBUG
-#define CONFIG_IPW2100_RX_DEBUG   /* Reception debugging */
+#define CONFIG_IPW2100_RX_DEBUG	/* Reception debugging */
 #endif
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -220,18 +219,18 @@
 } while (0)
 #else
 #define IPW_DEBUG(level, message...) do {} while (0)
-#endif /* CONFIG_IPW_DEBUG */
+#endif				/* CONFIG_IPW_DEBUG */
 
 #ifdef CONFIG_IPW_DEBUG
 static const char *command_types[] = {
 	"undefined",
-	"unused", /* HOST_ATTENTION */
+	"unused",		/* HOST_ATTENTION */
 	"HOST_COMPLETE",
-	"unused", /* SLEEP */
-	"unused", /* HOST_POWER_DOWN */
+	"unused",		/* SLEEP */
+	"unused",		/* HOST_POWER_DOWN */
 	"unused",
 	"SYSTEM_CONFIG",
-	"unused", /* SET_IMR */
+	"unused",		/* SET_IMR */
 	"SSID",
 	"MANDATORY_BSSID",
 	"AUTHENTICATION_TYPE",
@@ -277,17 +276,16 @@
 	"GROUP_ORDINALS",
 	"SHORT_RETRY_LIMIT",
 	"LONG_RETRY_LIMIT",
-	"unused", /* SAVE_CALIBRATION */
-	"unused", /* RESTORE_CALIBRATION */
+	"unused",		/* SAVE_CALIBRATION */
+	"unused",		/* RESTORE_CALIBRATION */
 	"undefined",
 	"undefined",
 	"undefined",
 	"HOST_PRE_POWER_DOWN",
-	"unused", /* HOST_INTERRUPT_COALESCING */
+	"unused",		/* HOST_INTERRUPT_COALESCING */
 	"undefined",
 	"CARD_DISABLE_PHY_OFF",
-	"MSDU_TX_RATES"
-	"undefined",
+	"MSDU_TX_RATES" "undefined",
 	"undefined",
 	"SET_STATION_STAT_BITS",
 	"CLEAR_STATIONS_STAT_BITS",
@@ -298,7 +296,6 @@
 };
 #endif
 
-
 /* Pre-decl until we get the code solid and then we can clean it up */
 static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
 static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
@@ -321,11 +318,10 @@
 static int ipw2100_ucode_download(struct ipw2100_priv *priv,
 				  struct ipw2100_fw *fw);
 static void ipw2100_wx_event_work(struct ipw2100_priv *priv);
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev);
+static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
 static struct iw_handler_def ipw2100_wx_handler_def;
 
-
-static inline void read_register(struct net_device *dev, u32 reg, u32 *val)
+static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
 {
 	*val = readl((void __iomem *)(dev->base_addr + reg));
 	IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
@@ -337,13 +333,14 @@
 	IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
 }
 
-static inline void read_register_word(struct net_device *dev, u32 reg, u16 *val)
+static inline void read_register_word(struct net_device *dev, u32 reg,
+				      u16 * val)
 {
 	*val = readw((void __iomem *)(dev->base_addr + reg));
 	IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
 }
 
-static inline void read_register_byte(struct net_device *dev, u32 reg, u8 *val)
+static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
 {
 	*val = readb((void __iomem *)(dev->base_addr + reg));
 	IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
@@ -355,14 +352,13 @@
 	IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
 }
 
-
 static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
 {
 	writeb(val, (void __iomem *)(dev->base_addr + reg));
 	IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
 }
 
-static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 *val)
+static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val)
 {
 	write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
 		       addr & IPW_REG_INDIRECT_ADDR_MASK);
@@ -376,7 +372,7 @@
 	write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
 }
 
-static inline void read_nic_word(struct net_device *dev, u32 addr, u16 *val)
+static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val)
 {
 	write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
 		       addr & IPW_REG_INDIRECT_ADDR_MASK);
@@ -390,7 +386,7 @@
 	write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
 }
 
-static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 *val)
+static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val)
 {
 	write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
 		       addr & IPW_REG_INDIRECT_ADDR_MASK);
@@ -416,7 +412,7 @@
 }
 
 static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
-				    const u8 *buf)
+				    const u8 * buf)
 {
 	u32 aligned_addr;
 	u32 aligned_len;
@@ -431,32 +427,30 @@
 		write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
 			       aligned_addr);
 		for (i = dif_len; i < 4; i++, buf++)
-			write_register_byte(
-				dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
-				*buf);
+			write_register_byte(dev,
+					    IPW_REG_INDIRECT_ACCESS_DATA + i,
+					    *buf);
 
 		len -= dif_len;
 		aligned_addr += 4;
 	}
 
 	/* read DWs through autoincrement registers */
-	write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
-		       aligned_addr);
+	write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
 	aligned_len = len & (~0x3);
 	for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
-		write_register(
-			dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *)buf);
+		write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf);
 
 	/* copy the last nibble */
 	dif_len = len - aligned_len;
 	write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
 	for (i = 0; i < dif_len; i++, buf++)
-		write_register_byte(
-			dev, IPW_REG_INDIRECT_ACCESS_DATA + i, *buf);
+		write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
+				    *buf);
 }
 
 static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
-				   u8 *buf)
+				   u8 * buf)
 {
 	u32 aligned_addr;
 	u32 aligned_len;
@@ -471,39 +465,38 @@
 		write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
 			       aligned_addr);
 		for (i = dif_len; i < 4; i++, buf++)
-			read_register_byte(
-				dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
+			read_register_byte(dev,
+					   IPW_REG_INDIRECT_ACCESS_DATA + i,
+					   buf);
 
 		len -= dif_len;
 		aligned_addr += 4;
 	}
 
 	/* read DWs through autoincrement registers */
-	write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
-		       aligned_addr);
+	write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
 	aligned_len = len & (~0x3);
 	for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
-		read_register(dev, IPW_REG_AUTOINCREMENT_DATA,
-			      (u32 *)buf);
+		read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);
 
 	/* copy the last nibble */
 	dif_len = len - aligned_len;
-	write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
-		       aligned_addr);
+	write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
 	for (i = 0; i < dif_len; i++, buf++)
-		read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA +
-				   i, buf);
+		read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
 }
 
 static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev)
 {
 	return (dev->base_addr &&
-		(readl((void __iomem *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START))
+		(readl
+		 ((void __iomem *)(dev->base_addr +
+				   IPW_REG_DOA_DEBUG_AREA_START))
 		 == IPW_DATA_DOA_DEBUG_VALUE));
 }
 
 static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
-			       void *val, u32 *len)
+			       void *val, u32 * len)
 {
 	struct ipw2100_ordinals *ordinals = &priv->ordinals;
 	u32 addr;
@@ -529,8 +522,8 @@
 			return -EINVAL;
 		}
 
-		read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2),
-			       &addr);
+		read_nic_dword(priv->net_dev,
+			       ordinals->table1_addr + (ord << 2), &addr);
 		read_nic_dword(priv->net_dev, addr, val);
 
 		*len = IPW_ORD_TAB_1_ENTRY_SIZE;
@@ -543,8 +536,8 @@
 		ord -= IPW_START_ORD_TAB_2;
 
 		/* get the address of statistic */
-		read_nic_dword(priv->net_dev, ordinals->table2_addr + (ord << 3),
-			       &addr);
+		read_nic_dword(priv->net_dev,
+			       ordinals->table2_addr + (ord << 3), &addr);
 
 		/* get the second DW of statistics ;
 		 * two 16-bit words - first is length, second is count */
@@ -553,10 +546,10 @@
 			       &field_info);
 
 		/* get each entry length */
-		field_len = *((u16 *)&field_info);
+		field_len = *((u16 *) & field_info);
 
 		/* get number of entries */
-		field_count = *(((u16 *)&field_info) + 1);
+		field_count = *(((u16 *) & field_info) + 1);
 
 		/* abort if no enought memory */
 		total_length = field_len * field_count;
@@ -581,8 +574,8 @@
 	return -EINVAL;
 }
 
-static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val,
-			       u32 *len)
+static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,
+			       u32 * len)
 {
 	struct ipw2100_ordinals *ordinals = &priv->ordinals;
 	u32 addr;
@@ -594,8 +587,8 @@
 			return -EINVAL;
 		}
 
-		read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2),
-			       &addr);
+		read_nic_dword(priv->net_dev,
+			       ordinals->table1_addr + (ord << 2), &addr);
 
 		write_nic_dword(priv->net_dev, addr, *val);
 
@@ -612,7 +605,7 @@
 }
 
 static char *snprint_line(char *buf, size_t count,
-			  const u8 *data, u32 len, u32 ofs)
+			  const u8 * data, u32 len, u32 ofs)
 {
 	int out, i, j, l;
 	char c;
@@ -646,7 +639,7 @@
 	return buf;
 }
 
-static void printk_buf(int level, const u8 *data, u32 len)
+static void printk_buf(int level, const u8 * data, u32 len)
 {
 	char line[81];
 	u32 ofs = 0;
@@ -662,8 +655,6 @@
 	}
 }
 
-
-
 #define MAX_RESET_BACKOFF 10
 
 static inline void schedule_reset(struct ipw2100_priv *priv)
@@ -703,7 +694,7 @@
 
 #define HOST_COMPLETE_TIMEOUT (2 * HZ)
 static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
-				   struct host_command * cmd)
+				   struct host_command *cmd)
 {
 	struct list_head *element;
 	struct ipw2100_tx_packet *packet;
@@ -713,25 +704,28 @@
 	IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
 		     command_types[cmd->host_command], cmd->host_command,
 		     cmd->host_command_length);
-	printk_buf(IPW_DL_HC, (u8*)cmd->host_command_parameters,
+	printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,
 		   cmd->host_command_length);
 
 	spin_lock_irqsave(&priv->low_lock, flags);
 
 	if (priv->fatal_error) {
-		IPW_DEBUG_INFO("Attempt to send command while hardware in fatal error condition.\n");
+		IPW_DEBUG_INFO
+		    ("Attempt to send command while hardware in fatal error condition.\n");
 		err = -EIO;
 		goto fail_unlock;
 	}
 
 	if (!(priv->status & STATUS_RUNNING)) {
-		IPW_DEBUG_INFO("Attempt to send command while hardware is not running.\n");
+		IPW_DEBUG_INFO
+		    ("Attempt to send command while hardware is not running.\n");
 		err = -EIO;
 		goto fail_unlock;
 	}
 
 	if (priv->status & STATUS_CMD_ACTIVE) {
-		IPW_DEBUG_INFO("Attempt to send command while another command is pending.\n");
+		IPW_DEBUG_INFO
+		    ("Attempt to send command while another command is pending.\n");
 		err = -EBUSY;
 		goto fail_unlock;
 	}
@@ -752,7 +746,8 @@
 	/* initialize the firmware command packet */
 	packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
 	packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
-	packet->info.c_struct.cmd->host_command_len_reg = cmd->host_command_length;
+	packet->info.c_struct.cmd->host_command_len_reg =
+	    cmd->host_command_length;
 	packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
 
 	memcpy(packet->info.c_struct.cmd->host_command_params_reg,
@@ -776,13 +771,15 @@
 	 * then there is a problem.
 	 */
 
-	err = wait_event_interruptible_timeout(
-		priv->wait_command_queue, !(priv->status & STATUS_CMD_ACTIVE),
-		HOST_COMPLETE_TIMEOUT);
+	err =
+	    wait_event_interruptible_timeout(priv->wait_command_queue,
+					     !(priv->
+					       status & STATUS_CMD_ACTIVE),
+					     HOST_COMPLETE_TIMEOUT);
 
 	if (err == 0) {
 		IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
-			       HOST_COMPLETE_TIMEOUT / (HZ / 100));
+			       1000 * (HOST_COMPLETE_TIMEOUT / HZ));
 		priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
 		priv->status &= ~STATUS_CMD_ACTIVE;
 		schedule_reset(priv);
@@ -804,13 +801,12 @@
 
 	return 0;
 
- fail_unlock:
+      fail_unlock:
 	spin_unlock_irqrestore(&priv->low_lock, flags);
 
 	return err;
 }
 
-
 /*
  * Verify the values and data access of the hardware
  * No locks needed or used.  No functions called.
@@ -825,8 +821,7 @@
 
 	/* Domain 0 check - all values should be DOA_DEBUG */
 	for (address = IPW_REG_DOA_DEBUG_AREA_START;
-	     address < IPW_REG_DOA_DEBUG_AREA_END;
-	     address += sizeof(u32)) {
+	     address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {
 		read_register(priv->net_dev, address, &data1);
 		if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
 			return -EIO;
@@ -898,7 +893,6 @@
 	return -EIO;
 }
 
-
 /*********************************************************************
     Procedure   :   sw_reset_and_clock
     Purpose     :   Asserts s/w reset, asserts clock initialization
@@ -975,17 +969,16 @@
 
 	if (priv->fatal_error) {
 		IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
-		       "fatal error %d.  Interface must be brought down.\n",
-		       priv->net_dev->name, priv->fatal_error);
+				"fatal error %d.  Interface must be brought down.\n",
+				priv->net_dev->name, priv->fatal_error);
 		return -EINVAL;
 	}
-
 #ifdef CONFIG_PM
 	if (!ipw2100_firmware.version) {
 		err = ipw2100_get_firmware(priv, &ipw2100_firmware);
 		if (err) {
 			IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
-			       priv->net_dev->name, err);
+					priv->net_dev->name, err);
 			priv->fatal_error = IPW2100_ERR_FW_LOAD;
 			goto fail;
 		}
@@ -994,7 +987,7 @@
 	err = ipw2100_get_firmware(priv, &ipw2100_firmware);
 	if (err) {
 		IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
-		       priv->net_dev->name, err);
+				priv->net_dev->name, err);
 		priv->fatal_error = IPW2100_ERR_FW_LOAD;
 		goto fail;
 	}
@@ -1005,21 +998,20 @@
 	err = sw_reset_and_clock(priv);
 	if (err) {
 		IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
-		       priv->net_dev->name, err);
+				priv->net_dev->name, err);
 		goto fail;
 	}
 
 	err = ipw2100_verify(priv);
 	if (err) {
 		IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
-		       priv->net_dev->name, err);
+				priv->net_dev->name, err);
 		goto fail;
 	}
 
 	/* Hold ARC */
 	write_nic_dword(priv->net_dev,
-			IPW_INTERNAL_REGISTER_HALT_AND_RESET,
-			0x80000000);
+			IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000);
 
 	/* allow ARC to run */
 	write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
@@ -1034,13 +1026,13 @@
 
 	/* release ARC */
 	write_nic_dword(priv->net_dev,
-			IPW_INTERNAL_REGISTER_HALT_AND_RESET,
-			0x00000000);
+			IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000);
 
 	/* s/w reset and clock stabilization (again!!!) */
 	err = sw_reset_and_clock(priv);
 	if (err) {
-		printk(KERN_ERR DRV_NAME ": %s: sw_reset_and_clock failed: %d\n",
+		printk(KERN_ERR DRV_NAME
+		       ": %s: sw_reset_and_clock failed: %d\n",
 		       priv->net_dev->name, err);
 		goto fail;
 	}
@@ -1049,10 +1041,9 @@
 	err = ipw2100_fw_download(priv, &ipw2100_firmware);
 	if (err) {
 		IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
-		       priv->net_dev->name, err);
+				priv->net_dev->name, err);
 		goto fail;
 	}
-
 #ifndef CONFIG_PM
 	/*
 	 * When the .resume method of the driver is called, the other
@@ -1084,7 +1075,7 @@
 
 	return 0;
 
- fail:
+      fail:
 	ipw2100_release_firmware(priv, &ipw2100_firmware);
 	return err;
 }
@@ -1105,7 +1096,6 @@
 	write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
 }
 
-
 static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
 {
 	struct ipw2100_ordinals *ord = &priv->ordinals;
@@ -1177,11 +1167,10 @@
 	 * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
 	 */
 	len = sizeof(addr);
-	if (ipw2100_get_ordinal(
-		    priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
-		    &addr, &len)) {
+	if (ipw2100_get_ordinal
+	    (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) {
 		IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
-		       __LINE__);
+			       __LINE__);
 		return -EIO;
 	}
 
@@ -1194,7 +1183,7 @@
 	priv->eeprom_version = (val >> 24) & 0xFF;
 	IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
 
-        /*
+	/*
 	 *  HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
 	 *
 	 *  notice that the EEPROM bit is reverse polarity, i.e.
@@ -1206,8 +1195,7 @@
 		priv->hw_features |= HW_FEATURE_RFKILL;
 
 	IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
-			   (priv->hw_features & HW_FEATURE_RFKILL) ?
-			   "" : "not ");
+		       (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not ");
 
 	return 0;
 }
@@ -1234,7 +1222,8 @@
 	 * fw & dino ucode
 	 */
 	if (ipw2100_download_firmware(priv)) {
-		printk(KERN_ERR DRV_NAME ": %s: Failed to power on the adapter.\n",
+		printk(KERN_ERR DRV_NAME
+		       ": %s: Failed to power on the adapter.\n",
 		       priv->net_dev->name);
 		return -EIO;
 	}
@@ -1293,7 +1282,8 @@
 		     i ? "SUCCESS" : "FAILED");
 
 	if (!i) {
-		printk(KERN_WARNING DRV_NAME ": %s: Firmware did not initialize.\n",
+		printk(KERN_WARNING DRV_NAME
+		       ": %s: Firmware did not initialize.\n",
 		       priv->net_dev->name);
 		return -EIO;
 	}
@@ -1326,7 +1316,6 @@
 	priv->fatal_error = 0;
 }
 
-
 /* NOTE: Our interrupt is disabled when this method is called */
 static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
 {
@@ -1350,19 +1339,19 @@
 
 		if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
 			break;
-	}  while(i--);
+	} while (i--);
 
 	priv->status &= ~STATUS_RESET_PENDING;
 
 	if (!i) {
-		IPW_DEBUG_INFO("exit - waited too long for master assert stop\n");
+		IPW_DEBUG_INFO
+		    ("exit - waited too long for master assert stop\n");
 		return -EIO;
 	}
 
 	write_register(priv->net_dev, IPW_REG_RESET_REG,
 		       IPW_AUX_HOST_RESET_REG_SW_RESET);
 
-
 	/* Reset any fatal_error conditions */
 	ipw2100_reset_fatalerror(priv);
 
@@ -1415,7 +1404,6 @@
 	return -EIO;
 }
 
-
 static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
 {
 	struct host_command cmd = {
@@ -1445,9 +1433,8 @@
 
 	err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
 	if (err) {
-		IPW_DEBUG_INFO(
-		       "%s: card not responding to init command.\n",
-		       priv->net_dev->name);
+		IPW_DEBUG_INFO("%s: card not responding to init command.\n",
+			       priv->net_dev->name);
 		goto fail_up;
 	}
 
@@ -1456,7 +1443,7 @@
 		queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
 	}
 
-fail_up:
+      fail_up:
 	up(&priv->adapter_sem);
 	return err;
 }
@@ -1488,7 +1475,8 @@
 
 		err = ipw2100_hw_phy_off(priv);
 		if (err)
-			printk(KERN_WARNING DRV_NAME ": Error disabling radio %d\n", err);
+			printk(KERN_WARNING DRV_NAME
+			       ": Error disabling radio %d\n", err);
 
 		/*
 		 * If in D0-standby mode going directly to D3 may cause a
@@ -1566,7 +1554,6 @@
 	return 0;
 }
 
-
 static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
 {
 	struct host_command cmd = {
@@ -1593,19 +1580,21 @@
 
 	err = ipw2100_hw_send_command(priv, &cmd);
 	if (err) {
-		printk(KERN_WARNING DRV_NAME ": exit - failed to send CARD_DISABLE command\n");
+		printk(KERN_WARNING DRV_NAME
+		       ": exit - failed to send CARD_DISABLE command\n");
 		goto fail_up;
 	}
 
 	err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
 	if (err) {
-		printk(KERN_WARNING DRV_NAME ": exit - card failed to change to DISABLED\n");
+		printk(KERN_WARNING DRV_NAME
+		       ": exit - card failed to change to DISABLED\n");
 		goto fail_up;
 	}
 
 	IPW_DEBUG_INFO("TODO: implement scan state machine\n");
 
-fail_up:
+      fail_up:
 	up(&priv->adapter_sem);
 	return err;
 }
@@ -1627,7 +1616,7 @@
 
 	if (!(priv->config & CFG_ASSOCIATE))
 		cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
-	if ((priv->sec.flags & SEC_ENABLED) && priv->sec.enabled)
+	if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled)
 		cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
 	if (priv->config & CFG_PASSIVE_SCAN)
 		cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
@@ -1709,8 +1698,9 @@
 	    (priv->status & STATUS_RESET_PENDING)) {
 		/* Power cycle the card ... */
 		if (ipw2100_power_cycle_adapter(priv)) {
-			printk(KERN_WARNING DRV_NAME ": %s: Could not cycle adapter.\n",
-					  priv->net_dev->name);
+			printk(KERN_WARNING DRV_NAME
+			       ": %s: Could not cycle adapter.\n",
+			       priv->net_dev->name);
 			rc = 1;
 			goto exit;
 		}
@@ -1719,8 +1709,9 @@
 
 	/* Load the firmware, start the clocks, etc. */
 	if (ipw2100_start_adapter(priv)) {
-	       	printk(KERN_ERR DRV_NAME ": %s: Failed to start the firmware.\n",
-				priv->net_dev->name);
+		printk(KERN_ERR DRV_NAME
+		       ": %s: Failed to start the firmware.\n",
+		       priv->net_dev->name);
 		rc = 1;
 		goto exit;
 	}
@@ -1729,16 +1720,18 @@
 
 	/* Determine capabilities of this particular HW configuration */
 	if (ipw2100_get_hw_features(priv)) {
-		printk(KERN_ERR DRV_NAME ": %s: Failed to determine HW features.\n",
-				priv->net_dev->name);
+		printk(KERN_ERR DRV_NAME
+		       ": %s: Failed to determine HW features.\n",
+		       priv->net_dev->name);
 		rc = 1;
 		goto exit;
 	}
 
 	lock = LOCK_NONE;
 	if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
-		printk(KERN_ERR DRV_NAME ": %s: Failed to clear ordinal lock.\n",
-				priv->net_dev->name);
+		printk(KERN_ERR DRV_NAME
+		       ": %s: Failed to clear ordinal lock.\n",
+		       priv->net_dev->name);
 		rc = 1;
 		goto exit;
 	}
@@ -1764,7 +1757,7 @@
 	 * HOST_COMPLETE */
 	if (ipw2100_adapter_setup(priv)) {
 		printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
-				priv->net_dev->name);
+		       priv->net_dev->name);
 		rc = 1;
 		goto exit;
 	}
@@ -1773,20 +1766,19 @@
 		/* Enable the adapter - sends HOST_COMPLETE */
 		if (ipw2100_enable_adapter(priv)) {
 			printk(KERN_ERR DRV_NAME ": "
-				"%s: failed in call to enable adapter.\n",
-				priv->net_dev->name);
+			       "%s: failed in call to enable adapter.\n",
+			       priv->net_dev->name);
 			ipw2100_hw_stop_adapter(priv);
 			rc = 1;
 			goto exit;
 		}
 
-
 		/* Start a scan . . . */
 		ipw2100_set_scan_options(priv);
 		ipw2100_start_scan(priv);
 	}
 
- exit:
+      exit:
 	return rc;
 }
 
@@ -1802,8 +1794,7 @@
 	unsigned long flags;
 	union iwreq_data wrqu = {
 		.ap_addr = {
-			.sa_family = ARPHRD_ETHER
-		}
+			    .sa_family = ARPHRD_ETHER}
 	};
 	int associated = priv->status & STATUS_ASSOCIATED;
 
@@ -1842,7 +1833,7 @@
 
 #ifdef ACPI_CSTATE_LIMIT_DEFINED
 	if (priv->config & CFG_C3_DISABLED) {
-		IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n");
+		IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
 		acpi_set_cstate_limit(priv->cstate_limit);
 		priv->config &= ~CFG_C3_DISABLED;
 	}
@@ -1862,14 +1853,12 @@
 	unsigned long flags;
 	union iwreq_data wrqu = {
 		.ap_addr = {
-			.sa_family = ARPHRD_ETHER
-		}
+			    .sa_family = ARPHRD_ETHER}
 	};
 	int associated = priv->status & STATUS_ASSOCIATED;
 
 	spin_lock_irqsave(&priv->low_lock, flags);
-	IPW_DEBUG_INFO(DRV_NAME ": %s: Restarting adapter.\n",
-		       priv->net_dev->name);
+	IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
 	priv->resets++;
 	priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
 	priv->status |= STATUS_SECURITY_UPDATED;
@@ -1894,7 +1883,6 @@
 
 }
 
-
 static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
 {
 
@@ -1904,7 +1892,7 @@
 	u32 txrate;
 	u32 chan;
 	char *txratename;
- 	u8 bssid[ETH_ALEN];
+	u8 bssid[ETH_ALEN];
 
 	/*
 	 * TBD: BSSID is usually 00:00:00:00:00:00 here and not
@@ -1918,16 +1906,15 @@
 				  essid, &essid_len);
 	if (ret) {
 		IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
-				   __LINE__);
+			       __LINE__);
 		return;
 	}
 
 	len = sizeof(u32);
-	ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE,
-				  &txrate, &len);
+	ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
 	if (ret) {
 		IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
-				   __LINE__);
+			       __LINE__);
 		return;
 	}
 
@@ -1935,19 +1922,18 @@
 	ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
 	if (ret) {
 		IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
-				   __LINE__);
+			       __LINE__);
 		return;
 	}
 	len = ETH_ALEN;
-        ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid,  &len);
+	ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
 	if (ret) {
 		IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
-				   __LINE__);
+			       __LINE__);
 		return;
 	}
 	memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
 
-
 	switch (txrate) {
 	case TX_RATE_1_MBIT:
 		txratename = "1Mbps";
@@ -1974,7 +1960,7 @@
 
 	/* now we copy read ssid into dev */
 	if (!(priv->config & CFG_STATIC_ESSID)) {
-		priv->essid_len = min((u8)essid_len, (u8)IW_ESSID_MAX_SIZE);
+		priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
 		memcpy(priv->essid, essid, priv->essid_len);
 	}
 	priv->channel = chan;
@@ -1986,7 +1972,6 @@
 	queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10);
 }
 
-
 static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
 			     int length, int batch_mode)
 {
@@ -2001,8 +1986,7 @@
 	IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len));
 
 	if (ssid_len)
-		memcpy((char*)cmd.host_command_parameters,
-		       essid, ssid_len);
+		memcpy(cmd.host_command_parameters, essid, ssid_len);
 
 	if (!batch_mode) {
 		err = ipw2100_disable_adapter(priv);
@@ -2014,7 +1998,7 @@
 	 * disable auto association -- so we cheat by setting a bogus SSID */
 	if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
 		int i;
-		u8 *bogus = (u8*)cmd.host_command_parameters;
+		u8 *bogus = (u8 *) cmd.host_command_parameters;
 		for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
 			bogus[i] = 0x18 + i;
 		cmd.host_command_length = IW_ESSID_MAX_SIZE;
@@ -2025,8 +2009,7 @@
 
 	err = ipw2100_hw_send_command(priv, &cmd);
 	if (!err) {
-		memset(priv->essid + ssid_len, 0,
-		       IW_ESSID_MAX_SIZE - ssid_len);
+		memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
 		memcpy(priv->essid, essid, ssid_len);
 		priv->essid_len = ssid_len;
 	}
@@ -2071,14 +2054,14 @@
 static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
 {
 	IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
-	       priv->net_dev->name);
+		       priv->net_dev->name);
 
 	/* RF_KILL is now enabled (else we wouldn't be here) */
 	priv->status |= STATUS_RF_KILL_HW;
 
 #ifdef ACPI_CSTATE_LIMIT_DEFINED
 	if (priv->config & CFG_C3_DISABLED) {
-		IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n");
+		IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
 		acpi_set_cstate_limit(priv->cstate_limit);
 		priv->config &= ~CFG_C3_DISABLED;
 	}
@@ -2102,16 +2085,16 @@
 #define IPW2100_HANDLER(v, f) { v, f, # v }
 struct ipw2100_status_indicator {
 	int status;
-	void (*cb)(struct ipw2100_priv *priv, u32 status);
+	void (*cb) (struct ipw2100_priv * priv, u32 status);
 	char *name;
 };
 #else
 #define IPW2100_HANDLER(v, f) { v, f }
 struct ipw2100_status_indicator {
 	int status;
-	void (*cb)(struct ipw2100_priv *priv, u32 status);
+	void (*cb) (struct ipw2100_priv * priv, u32 status);
 };
-#endif /* CONFIG_IPW_DEBUG */
+#endif				/* CONFIG_IPW_DEBUG */
 
 static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
 {
@@ -2135,7 +2118,6 @@
 	IPW2100_HANDLER(-1, NULL)
 };
 
-
 static void isr_status_change(struct ipw2100_priv *priv, int status)
 {
 	int i;
@@ -2153,7 +2135,7 @@
 	for (i = 0; status_handlers[i].status != -1; i++) {
 		if (status == status_handlers[i].status) {
 			IPW_DEBUG_NOTIF("Status change: %s\n",
-					 status_handlers[i].name);
+					status_handlers[i].name);
 			if (status_handlers[i].cb)
 				status_handlers[i].cb(priv, status);
 			priv->wstats.status = status;
@@ -2164,9 +2146,8 @@
 	IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
 }
 
-static void isr_rx_complete_command(
-	struct ipw2100_priv *priv,
-	struct ipw2100_cmd_header *cmd)
+static void isr_rx_complete_command(struct ipw2100_priv *priv,
+				    struct ipw2100_cmd_header *cmd)
 {
 #ifdef CONFIG_IPW_DEBUG
 	if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
@@ -2196,10 +2177,8 @@
 };
 #endif
 
-
-static inline int ipw2100_alloc_skb(
-	struct ipw2100_priv *priv,
-	struct ipw2100_rx_packet *packet)
+static inline int ipw2100_alloc_skb(struct ipw2100_priv *priv,
+				    struct ipw2100_rx_packet *packet)
 {
 	packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
 	if (!packet->skb)
@@ -2215,7 +2194,6 @@
 	return 0;
 }
 
-
 #define SEARCH_ERROR   0xffffffff
 #define SEARCH_FAIL    0xfffffffe
 #define SEARCH_SUCCESS 0xfffffff0
@@ -2229,10 +2207,10 @@
 	if (priv->snapshot[0])
 		return 1;
 	for (i = 0; i < 0x30; i++) {
-		priv->snapshot[i] = (u8*)kmalloc(0x1000, GFP_ATOMIC);
+		priv->snapshot[i] = (u8 *) kmalloc(0x1000, GFP_ATOMIC);
 		if (!priv->snapshot[i]) {
 			IPW_DEBUG_INFO("%s: Error allocating snapshot "
-			       "buffer %d\n", priv->net_dev->name, i);
+				       "buffer %d\n", priv->net_dev->name, i);
 			while (i > 0)
 				kfree(priv->snapshot[--i]);
 			priv->snapshot[0] = NULL;
@@ -2253,7 +2231,7 @@
 	priv->snapshot[0] = NULL;
 }
 
-static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf,
+static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
 				    size_t len, int mode)
 {
 	u32 i, j;
@@ -2270,9 +2248,9 @@
 	for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
 		read_nic_dword(priv->net_dev, i, &tmp);
 		if (mode == SEARCH_SNAPSHOT)
-			*(u32 *)SNAPSHOT_ADDR(i) = tmp;
+			*(u32 *) SNAPSHOT_ADDR(i) = tmp;
 		if (ret == SEARCH_FAIL) {
-			d = (u8*)&tmp;
+			d = (u8 *) & tmp;
 			for (j = 0; j < 4; j++) {
 				if (*s != *d) {
 					s = in_buf;
@@ -2310,8 +2288,7 @@
 static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
 #endif
 
-static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv,
-					       int i)
+static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 {
 #ifdef CONFIG_IPW_DEBUG_C3
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
@@ -2322,11 +2299,11 @@
 	int limit;
 #endif
 
-	IPW_DEBUG_INFO(DRV_NAME ": PCI latency error detected at "
-		       "0x%04zX.\n", i * sizeof(struct ipw2100_status));
+	IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
+		       i * sizeof(struct ipw2100_status));
 
 #ifdef ACPI_CSTATE_LIMIT_DEFINED
-	IPW_DEBUG_INFO(DRV_NAME ": Disabling C3 transitions.\n");
+	IPW_DEBUG_INFO(": Disabling C3 transitions.\n");
 	limit = acpi_get_cstate_limit();
 	if (limit > 2) {
 		priv->cstate_limit = limit;
@@ -2346,9 +2323,9 @@
 
 		if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
 			break;
-	}  while (j--);
+	} while (j--);
 
-	match = ipw2100_match_buf(priv, (u8*)status,
+	match = ipw2100_match_buf(priv, (u8 *) status,
 				  sizeof(struct ipw2100_status),
 				  SEARCH_SNAPSHOT);
 	if (match < SEARCH_SUCCESS)
@@ -2360,7 +2337,7 @@
 		IPW_DEBUG_INFO("%s: No DMA status match in "
 			       "Firmware.\n", priv->net_dev->name);
 
-	printk_buf((u8*)priv->status_queue.drv,
+	printk_buf((u8 *) priv->status_queue.drv,
 		   sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
 #endif
 
@@ -2392,26 +2369,26 @@
 		IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
 		return;
 	}
-
+#ifdef CONFIG_IPW2100_MONITOR
 	if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR &&
+		     priv->config & CFG_CRC_CHECK &&
 		     status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
 		IPW_DEBUG_RX("CRC error in packet.  Dropping.\n");
 		priv->ieee->stats.rx_errors++;
 		return;
 	}
+#endif
 
 	if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
-		!(priv->status & STATUS_ASSOCIATED))) {
+		     !(priv->status & STATUS_ASSOCIATED))) {
 		IPW_DEBUG_DROP("Dropping packet while not associated.\n");
 		priv->wstats.discard.misc++;
 		return;
 	}
 
-
 	pci_unmap_single(priv->pci_dev,
 			 packet->dma_addr,
-			 sizeof(struct ipw2100_rx),
-			 PCI_DMA_FROMDEVICE);
+			 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
 
 	skb_put(packet->skb, status->frame_size);
 
@@ -2438,8 +2415,8 @@
 	/* We need to allocate a new SKB and attach it to the RDB. */
 	if (unlikely(ipw2100_alloc_skb(priv, packet))) {
 		printk(KERN_WARNING DRV_NAME ": "
-			"%s: Unable to allocate SKB onto RBD ring - disabling "
-			"adapter.\n", priv->net_dev->name);
+		       "%s: Unable to allocate SKB onto RBD ring - disabling "
+		       "adapter.\n", priv->net_dev->name);
 		/* TODO: schedule adapter shutdown */
 		IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
 	}
@@ -2534,11 +2511,11 @@
 
 		/* Sync the DMA for the STATUS buffer so CPU is sure to get
 		 * the correct values */
-		pci_dma_sync_single_for_cpu(
-			priv->pci_dev,
-			sq->nic + sizeof(struct ipw2100_status) * i,
-			sizeof(struct ipw2100_status),
-			PCI_DMA_FROMDEVICE);
+		pci_dma_sync_single_for_cpu(priv->pci_dev,
+					    sq->nic +
+					    sizeof(struct ipw2100_status) * i,
+					    sizeof(struct ipw2100_status),
+					    PCI_DMA_FROMDEVICE);
 
 		/* Sync the DMA for the RX buffer so CPU is sure to get
 		 * the correct values */
@@ -2552,8 +2529,7 @@
 		}
 
 		u = packet->rxp;
-		frame_type = sq->drv[i].status_fields &
-			STATUS_TYPE_MASK;
+		frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
 		stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
 		stats.len = sq->drv[i].frame_size;
 
@@ -2562,16 +2538,14 @@
 			stats.mask |= IEEE80211_STATMASK_RSSI;
 		stats.freq = IEEE80211_24GHZ_BAND;
 
-		IPW_DEBUG_RX(
-			"%s: '%s' frame type received (%d).\n",
-			priv->net_dev->name, frame_types[frame_type],
-			stats.len);
+		IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
+			     priv->net_dev->name, frame_types[frame_type],
+			     stats.len);
 
 		switch (frame_type) {
 		case COMMAND_STATUS_VAL:
 			/* Reset Rx watchdog */
-			isr_rx_complete_command(
-				priv, &u->rx_data.command);
+			isr_rx_complete_command(priv, &u->rx_data.command);
 			break;
 
 		case STATUS_CHANGE_VAL:
@@ -2588,12 +2562,10 @@
 #endif
 			if (stats.len < sizeof(u->rx_data.header))
 				break;
-			switch (WLAN_FC_GET_TYPE(u->rx_data.header.
-						 frame_ctl)) {
+			switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) {
 			case IEEE80211_FTYPE_MGMT:
 				ieee80211_rx_mgt(priv->ieee,
-						 &u->rx_data.header,
-						 &stats);
+						 &u->rx_data.header, &stats);
 				break;
 
 			case IEEE80211_FTYPE_CTL:
@@ -2607,7 +2579,7 @@
 			break;
 		}
 
-	increment:
+	      increment:
 		/* clear status field associated with this RBD */
 		rxq->drv[i].status.info.field = 0;
 
@@ -2619,12 +2591,10 @@
 		rxq->next = (i ? i : rxq->entries) - 1;
 
 		write_register(priv->net_dev,
-			       IPW_MEM_HOST_SHARED_RX_WRITE_INDEX,
-			       rxq->next);
+			       IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
 	}
 }
 
-
 /*
  * __ipw2100_tx_process
  *
@@ -2667,7 +2637,7 @@
 static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
 {
 	struct ipw2100_bd_queue *txq = &priv->tx_queue;
-        struct ipw2100_bd *tbd;
+	struct ipw2100_bd *tbd;
 	struct list_head *element;
 	struct ipw2100_tx_packet *packet;
 	int descriptors_used;
@@ -2680,7 +2650,7 @@
 	element = priv->fw_pend_list.next;
 
 	packet = list_entry(element, struct ipw2100_tx_packet, list);
-        tbd = &txq->drv[packet->index];
+	tbd = &txq->drv[packet->index];
 
 	/* Determine how many TBD entries must be finished... */
 	switch (packet->type) {
@@ -2693,14 +2663,14 @@
 	case DATA:
 		/* DATA uses two slots; advance and loop position. */
 		descriptors_used = tbd->num_fragments;
-                frag_num = tbd->num_fragments - 1;
+		frag_num = tbd->num_fragments - 1;
 		e = txq->oldest + frag_num;
 		e %= txq->entries;
 		break;
 
 	default:
 		printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
-				   priv->net_dev->name);
+		       priv->net_dev->name);
 		return 0;
 	}
 
@@ -2716,13 +2686,12 @@
 		printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
 		       priv->net_dev->name);
 
-        /*
+	/*
 	 * txq->next is the index of the last packet written txq->oldest is
 	 * the index of the r is the index of the next packet to be read by
 	 * firmware
 	 */
 
-
 	/*
 	 * Quick graphic to help you visualize the following
 	 * if / else statement
@@ -2750,23 +2719,20 @@
 #ifdef CONFIG_IPW_DEBUG
 	{
 		int i = txq->oldest;
-		IPW_DEBUG_TX(
-			"TX%d V=%p P=%04X T=%04X L=%d\n", i,
-			&txq->drv[i],
-			(u32)(txq->nic + i * sizeof(struct ipw2100_bd)),
-			txq->drv[i].host_addr,
-			txq->drv[i].buf_length);
+		IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
+			     &txq->drv[i],
+			     (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
+			     txq->drv[i].host_addr, txq->drv[i].buf_length);
 
 		if (packet->type == DATA) {
 			i = (i + 1) % txq->entries;
 
-			IPW_DEBUG_TX(
-				"TX%d V=%p P=%04X T=%04X L=%d\n", i,
-				&txq->drv[i],
-				(u32)(txq->nic + i *
-				sizeof(struct ipw2100_bd)),
-				(u32)txq->drv[i].host_addr,
-				txq->drv[i].buf_length);
+			IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
+				     &txq->drv[i],
+				     (u32) (txq->nic + i *
+					    sizeof(struct ipw2100_bd)),
+				     (u32) txq->drv[i].host_addr,
+				     txq->drv[i].buf_length);
 		}
 	}
 #endif
@@ -2780,23 +2746,18 @@
 			       priv->net_dev->name, txq->oldest, packet->index);
 
 		/* DATA packet; we have to unmap and free the SKB */
-		priv->ieee->stats.tx_packets++;
 		for (i = 0; i < frag_num; i++) {
-			tbd = &txq->drv[(packet->index + 1 + i) %
-					txq->entries];
+			tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
 
-			IPW_DEBUG_TX(
-				"TX%d P=%08x L=%d\n",
-				(packet->index + 1 + i) % txq->entries,
-				tbd->host_addr, tbd->buf_length);
+			IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
+				     (packet->index + 1 + i) % txq->entries,
+				     tbd->host_addr, tbd->buf_length);
 
 			pci_unmap_single(priv->pci_dev,
 					 tbd->host_addr,
-					 tbd->buf_length,
-					 PCI_DMA_TODEVICE);
+					 tbd->buf_length, PCI_DMA_TODEVICE);
 		}
 
-		priv->ieee->stats.tx_bytes += packet->info.d_struct.txb->payload_size;
 		ieee80211_txb_free(packet->info.d_struct.txb);
 		packet->info.d_struct.txb = NULL;
 
@@ -2805,13 +2766,8 @@
 
 		/* We have a free slot in the Tx queue, so wake up the
 		 * transmit layer if it is stopped. */
-		if (priv->status & STATUS_ASSOCIATED &&
-		    netif_queue_stopped(priv->net_dev)) {
-			IPW_DEBUG_INFO(KERN_INFO
-					   "%s: Waking net queue.\n",
-					   priv->net_dev->name);
+		if (priv->status & STATUS_ASSOCIATED)
 			netif_wake_queue(priv->net_dev);
-		}
 
 		/* A packet was processed by the hardware, so update the
 		 * watchdog */
@@ -2829,11 +2785,12 @@
 #ifdef CONFIG_IPW_DEBUG
 		if (packet->info.c_struct.cmd->host_command_reg <
 		    sizeof(command_types) / sizeof(*command_types))
-			IPW_DEBUG_TX(
-				"Command '%s (%d)' processed: %d.\n",
-				command_types[packet->info.c_struct.cmd->host_command_reg],
-				packet->info.c_struct.cmd->host_command_reg,
-				packet->info.c_struct.cmd->cmd_status_reg);
+			IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
+				     command_types[packet->info.c_struct.cmd->
+						   host_command_reg],
+				     packet->info.c_struct.cmd->
+				     host_command_reg,
+				     packet->info.c_struct.cmd->cmd_status_reg);
 #endif
 
 		list_add_tail(element, &priv->msg_free_list);
@@ -2848,17 +2805,17 @@
 	SET_STAT(&priv->txq_stat, txq->available);
 
 	IPW_DEBUG_TX("packet latency (send to process)  %ld jiffies\n",
-			 jiffies - packet->jiffy_start);
+		     jiffies - packet->jiffy_start);
 
 	return (!list_empty(&priv->fw_pend_list));
 }
 
-
 static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
 {
 	int i = 0;
 
-	while (__ipw2100_tx_process(priv) && i < 200) i++;
+	while (__ipw2100_tx_process(priv) && i < 200)
+		i++;
 
 	if (i == 200) {
 		printk(KERN_WARNING DRV_NAME ": "
@@ -2867,7 +2824,6 @@
 	}
 }
 
-
 static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
 {
 	struct list_head *element;
@@ -2892,13 +2848,12 @@
 		list_del(element);
 		DEC_STAT(&priv->msg_pend_stat);
 
-		packet = list_entry(element,
-				    struct ipw2100_tx_packet, list);
+		packet = list_entry(element, struct ipw2100_tx_packet, list);
 
 		IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
-				 &txq->drv[txq->next],
-				 (void*)(txq->nic + txq->next *
-					 sizeof(struct ipw2100_bd)));
+			     &txq->drv[txq->next],
+			     (void *)(txq->nic + txq->next *
+				      sizeof(struct ipw2100_bd)));
 
 		packet->index = txq->next;
 
@@ -2911,8 +2866,8 @@
 		 * with f/w debug version */
 		tbd->num_fragments = 1;
 		tbd->status.info.field =
-			IPW_BD_STATUS_TX_FRAME_COMMAND |
-			IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
+		    IPW_BD_STATUS_TX_FRAME_COMMAND |
+		    IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
 
 		/* update TBD queue counters */
 		txq->next++;
@@ -2934,7 +2889,6 @@
 	}
 }
 
-
 /*
  * ipw2100_tx_send_data
  *
@@ -2946,7 +2900,7 @@
 	struct ipw2100_bd_queue *txq = &priv->tx_queue;
 	struct ipw2100_bd *tbd;
 	int next = txq->next;
-        int i = 0;
+	int i = 0;
 	struct ipw2100_data_header *ipw_hdr;
 	struct ieee80211_hdr_3addr *hdr;
 
@@ -2958,20 +2912,18 @@
 		 *       maintained between the r and w indexes
 		 */
 		element = priv->tx_pend_list.next;
-                packet = list_entry(element, struct ipw2100_tx_packet, list);
+		packet = list_entry(element, struct ipw2100_tx_packet, list);
 
 		if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
 			     IPW_MAX_BDS)) {
 			/* TODO: Support merging buffers if more than
 			 * IPW_MAX_BDS are used */
-			IPW_DEBUG_INFO(
-			       "%s: Maximum BD theshold exceeded.  "
-			       "Increase fragmentation level.\n",
-			       priv->net_dev->name);
+			IPW_DEBUG_INFO("%s: Maximum BD theshold exceeded.  "
+				       "Increase fragmentation level.\n",
+				       priv->net_dev->name);
 		}
 
-		if (txq->available <= 3 +
-		    packet->info.d_struct.txb->nr_frags) {
+		if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
 			IPW_DEBUG_TX("no room in tx_queue\n");
 			break;
 		}
@@ -2985,7 +2937,7 @@
 
 		ipw_hdr = packet->info.d_struct.data;
 		hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb->
-			fragments[0]->data;
+		    fragments[0]->data;
 
 		if (priv->ieee->iw_mode == IW_MODE_INFRA) {
 			/* To DS: Addr1 = BSSID, Addr2 = SA,
@@ -3007,7 +2959,8 @@
 		ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
 		if (packet->info.d_struct.txb->nr_frags > 1)
 			ipw_hdr->fragment_size =
-				packet->info.d_struct.txb->frag_size - IEEE80211_3ADDR_LEN;
+			    packet->info.d_struct.txb->frag_size -
+			    IEEE80211_3ADDR_LEN;
 		else
 			ipw_hdr->fragment_size = 0;
 
@@ -3015,54 +2968,53 @@
 		tbd->buf_length = sizeof(struct ipw2100_data_header);
 		tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
 		tbd->status.info.field =
-			IPW_BD_STATUS_TX_FRAME_802_3 |
-			IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
+		    IPW_BD_STATUS_TX_FRAME_802_3 |
+		    IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
 		txq->next++;
 		txq->next %= txq->entries;
 
-		IPW_DEBUG_TX(
-			"data header tbd TX%d P=%08x L=%d\n",
-			packet->index, tbd->host_addr,
-			tbd->buf_length);
+		IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
+			     packet->index, tbd->host_addr, tbd->buf_length);
 #ifdef CONFIG_IPW_DEBUG
 		if (packet->info.d_struct.txb->nr_frags > 1)
 			IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
 				       packet->info.d_struct.txb->nr_frags);
 #endif
 
-                for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
-		        tbd = &txq->drv[txq->next];
+		for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
+			tbd = &txq->drv[txq->next];
 			if (i == packet->info.d_struct.txb->nr_frags - 1)
 				tbd->status.info.field =
-					IPW_BD_STATUS_TX_FRAME_802_3 |
-					IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
+				    IPW_BD_STATUS_TX_FRAME_802_3 |
+				    IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
 			else
 				tbd->status.info.field =
-					IPW_BD_STATUS_TX_FRAME_802_3 |
-					IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
+				    IPW_BD_STATUS_TX_FRAME_802_3 |
+				    IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
 
 			tbd->buf_length = packet->info.d_struct.txb->
-				fragments[i]->len - IEEE80211_3ADDR_LEN;
+			    fragments[i]->len - IEEE80211_3ADDR_LEN;
 
-                        tbd->host_addr = pci_map_single(
-				priv->pci_dev,
-				packet->info.d_struct.txb->fragments[i]->data +
-				IEEE80211_3ADDR_LEN,
-				tbd->buf_length,
-				PCI_DMA_TODEVICE);
+			tbd->host_addr = pci_map_single(priv->pci_dev,
+							packet->info.d_struct.
+							txb->fragments[i]->
+							data +
+							IEEE80211_3ADDR_LEN,
+							tbd->buf_length,
+							PCI_DMA_TODEVICE);
 
-			IPW_DEBUG_TX(
-				"data frag tbd TX%d P=%08x L=%d\n",
-				txq->next, tbd->host_addr, tbd->buf_length);
+			IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
+				     txq->next, tbd->host_addr,
+				     tbd->buf_length);
 
-			pci_dma_sync_single_for_device(
-				priv->pci_dev, tbd->host_addr,
-				tbd->buf_length,
-				PCI_DMA_TODEVICE);
+			pci_dma_sync_single_for_device(priv->pci_dev,
+						       tbd->host_addr,
+						       tbd->buf_length,
+						       PCI_DMA_TODEVICE);
 
 			txq->next++;
 			txq->next %= txq->entries;
-                }
+		}
 
 		txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
 		SET_STAT(&priv->txq_stat, txq->available);
@@ -3078,7 +3030,7 @@
 			       IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
 			       txq->next);
 	}
-        return;
+	return;
 }
 
 static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
@@ -3106,11 +3058,9 @@
 
 	if (inta & IPW2100_INTA_FATAL_ERROR) {
 		printk(KERN_WARNING DRV_NAME
-				  ": Fatal interrupt. Scheduling firmware restart.\n");
+		       ": Fatal interrupt. Scheduling firmware restart.\n");
 		priv->inta_other++;
-		write_register(
-			dev, IPW_REG_INTA,
-			IPW2100_INTA_FATAL_ERROR);
+		write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
 
 		read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
 		IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
@@ -3125,11 +3075,10 @@
 	}
 
 	if (inta & IPW2100_INTA_PARITY_ERROR) {
-		printk(KERN_ERR DRV_NAME ": ***** PARITY ERROR INTERRUPT !!!! \n");
+		printk(KERN_ERR DRV_NAME
+		       ": ***** PARITY ERROR INTERRUPT !!!! \n");
 		priv->inta_other++;
-		write_register(
-			dev, IPW_REG_INTA,
-			IPW2100_INTA_PARITY_ERROR);
+		write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
 	}
 
 	if (inta & IPW2100_INTA_RX_TRANSFER) {
@@ -3137,9 +3086,7 @@
 
 		priv->rx_interrupts++;
 
-		write_register(
-			dev, IPW_REG_INTA,
-			IPW2100_INTA_RX_TRANSFER);
+		write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
 
 		__ipw2100_rx_process(priv);
 		__ipw2100_tx_complete(priv);
@@ -3150,8 +3097,7 @@
 
 		priv->tx_interrupts++;
 
-		write_register(dev, IPW_REG_INTA,
-			       IPW2100_INTA_TX_TRANSFER);
+		write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
 
 		__ipw2100_tx_complete(priv);
 		ipw2100_tx_send_commands(priv);
@@ -3161,9 +3107,7 @@
 	if (inta & IPW2100_INTA_TX_COMPLETE) {
 		IPW_DEBUG_ISR("TX complete\n");
 		priv->inta_other++;
-		write_register(
-			dev, IPW_REG_INTA,
-			IPW2100_INTA_TX_COMPLETE);
+		write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
 
 		__ipw2100_tx_complete(priv);
 	}
@@ -3171,9 +3115,7 @@
 	if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
 		/* ipw2100_handle_event(dev); */
 		priv->inta_other++;
-		write_register(
-			dev, IPW_REG_INTA,
-			IPW2100_INTA_EVENT_INTERRUPT);
+		write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
 	}
 
 	if (inta & IPW2100_INTA_FW_INIT_DONE) {
@@ -3183,30 +3125,25 @@
 		read_register(dev, IPW_REG_INTA, &tmp);
 		if (tmp & (IPW2100_INTA_FATAL_ERROR |
 			   IPW2100_INTA_PARITY_ERROR)) {
-			write_register(
-				dev, IPW_REG_INTA,
-				IPW2100_INTA_FATAL_ERROR |
-				IPW2100_INTA_PARITY_ERROR);
+			write_register(dev, IPW_REG_INTA,
+				       IPW2100_INTA_FATAL_ERROR |
+				       IPW2100_INTA_PARITY_ERROR);
 		}
 
-		write_register(dev, IPW_REG_INTA,
-			       IPW2100_INTA_FW_INIT_DONE);
+		write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
 	}
 
 	if (inta & IPW2100_INTA_STATUS_CHANGE) {
 		IPW_DEBUG_ISR("Status change interrupt\n");
 		priv->inta_other++;
-		write_register(
-			dev, IPW_REG_INTA,
-			IPW2100_INTA_STATUS_CHANGE);
+		write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
 	}
 
 	if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
 		IPW_DEBUG_ISR("slave host mode interrupt\n");
 		priv->inta_other++;
-		write_register(
-			dev, IPW_REG_INTA,
-			IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
+		write_register(dev, IPW_REG_INTA,
+			       IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
 	}
 
 	priv->in_isr--;
@@ -3217,9 +3154,7 @@
 	IPW_DEBUG_ISR("exit\n");
 }
 
-
-static irqreturn_t ipw2100_interrupt(int irq, void *data,
-				     struct pt_regs *regs)
+static irqreturn_t ipw2100_interrupt(int irq, void *data, struct pt_regs *regs)
 {
 	struct ipw2100_priv *priv = data;
 	u32 inta, inta_mask;
@@ -3227,7 +3162,7 @@
 	if (!data)
 		return IRQ_NONE;
 
- 	spin_lock(&priv->low_lock);
+	spin_lock(&priv->low_lock);
 
 	/* We check to see if we should be ignoring interrupts before
 	 * we touch the hardware.  During ucode load if we try and handle
@@ -3261,10 +3196,10 @@
 	ipw2100_disable_interrupts(priv);
 
 	tasklet_schedule(&priv->irq_tasklet);
- 	spin_unlock(&priv->low_lock);
+	spin_unlock(&priv->low_lock);
 
 	return IRQ_HANDLED;
- none:
+      none:
 	spin_unlock(&priv->low_lock);
 	return IRQ_NONE;
 }
@@ -3294,10 +3229,8 @@
 
 	packet->info.d_struct.txb = txb;
 
-	IPW_DEBUG_TX("Sending fragment (%d bytes):\n",
-			 txb->fragments[0]->len);
-	printk_buf(IPW_DL_TX, txb->fragments[0]->data,
-		   txb->fragments[0]->len);
+	IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
+	printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
 
 	packet->jiffy_start = jiffies;
 
@@ -3312,22 +3245,23 @@
 	spin_unlock_irqrestore(&priv->low_lock, flags);
 	return 0;
 
- fail_unlock:
+      fail_unlock:
 	netif_stop_queue(dev);
 	spin_unlock_irqrestore(&priv->low_lock, flags);
 	return 1;
 }
 
-
 static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
 {
 	int i, j, err = -EINVAL;
 	void *v;
 	dma_addr_t p;
 
-	priv->msg_buffers = (struct ipw2100_tx_packet *)kmalloc(
-		IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
-		GFP_KERNEL);
+	priv->msg_buffers =
+	    (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE *
+						sizeof(struct
+						       ipw2100_tx_packet),
+						GFP_KERNEL);
 	if (!priv->msg_buffers) {
 		printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
 		       "buffers.\n", priv->net_dev->name);
@@ -3335,15 +3269,12 @@
 	}
 
 	for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
-		v = pci_alloc_consistent(
-			priv->pci_dev,
-			sizeof(struct ipw2100_cmd_header),
-			&p);
+		v = pci_alloc_consistent(priv->pci_dev,
+					 sizeof(struct ipw2100_cmd_header), &p);
 		if (!v) {
 			printk(KERN_ERR DRV_NAME ": "
 			       "%s: PCI alloc failed for msg "
-			       "buffers.\n",
-			       priv->net_dev->name);
+			       "buffers.\n", priv->net_dev->name);
 			err = -ENOMEM;
 			break;
 		}
@@ -3352,7 +3283,7 @@
 
 		priv->msg_buffers[i].type = COMMAND;
 		priv->msg_buffers[i].info.c_struct.cmd =
-			(struct ipw2100_cmd_header*)v;
+		    (struct ipw2100_cmd_header *)v;
 		priv->msg_buffers[i].info.c_struct.cmd_phys = p;
 	}
 
@@ -3360,11 +3291,11 @@
 		return 0;
 
 	for (j = 0; j < i; j++) {
-		pci_free_consistent(
-			priv->pci_dev,
-			sizeof(struct ipw2100_cmd_header),
-			priv->msg_buffers[j].info.c_struct.cmd,
-			priv->msg_buffers[j].info.c_struct.cmd_phys);
+		pci_free_consistent(priv->pci_dev,
+				    sizeof(struct ipw2100_cmd_header),
+				    priv->msg_buffers[j].info.c_struct.cmd,
+				    priv->msg_buffers[j].info.c_struct.
+				    cmd_phys);
 	}
 
 	kfree(priv->msg_buffers);
@@ -3398,7 +3329,8 @@
 		pci_free_consistent(priv->pci_dev,
 				    sizeof(struct ipw2100_cmd_header),
 				    priv->msg_buffers[i].info.c_struct.cmd,
-				    priv->msg_buffers[i].info.c_struct.cmd_phys);
+				    priv->msg_buffers[i].info.c_struct.
+				    cmd_phys);
 	}
 
 	kfree(priv->msg_buffers);
@@ -3424,6 +3356,7 @@
 
 	return out - buf;
 }
+
 static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL);
 
 static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
@@ -3432,209 +3365,269 @@
 	struct ipw2100_priv *p = d->driver_data;
 	return sprintf(buf, "0x%08x\n", (int)p->config);
 }
+
 static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
 
 static ssize_t show_status(struct device *d, struct device_attribute *attr,
-			char *buf)
+			   char *buf)
 {
 	struct ipw2100_priv *p = d->driver_data;
 	return sprintf(buf, "0x%08x\n", (int)p->status);
 }
+
 static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
 
 static ssize_t show_capability(struct device *d, struct device_attribute *attr,
-				char *buf)
+			       char *buf)
 {
 	struct ipw2100_priv *p = d->driver_data;
 	return sprintf(buf, "0x%08x\n", (int)p->capability);
 }
-static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
 
+static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
 
 #define IPW2100_REG(x) { IPW_ ##x, #x }
 static const struct {
 	u32 addr;
 	const char *name;
 } hw_data[] = {
-	IPW2100_REG(REG_GP_CNTRL),
-	IPW2100_REG(REG_GPIO),
-	IPW2100_REG(REG_INTA),
-	IPW2100_REG(REG_INTA_MASK),
-	IPW2100_REG(REG_RESET_REG),
-};
+IPW2100_REG(REG_GP_CNTRL),
+	    IPW2100_REG(REG_GPIO),
+	    IPW2100_REG(REG_INTA),
+	    IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),};
 #define IPW2100_NIC(x, s) { x, #x, s }
 static const struct {
 	u32 addr;
 	const char *name;
 	size_t size;
 } nic_data[] = {
-	IPW2100_NIC(IPW2100_CONTROL_REG, 2),
-	IPW2100_NIC(0x210014, 1),
-	IPW2100_NIC(0x210000, 1),
-};
+IPW2100_NIC(IPW2100_CONTROL_REG, 2),
+	    IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),};
 #define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
 static const struct {
 	u8 index;
 	const char *name;
 	const char *desc;
 } ord_data[] = {
-	IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
-	IPW2100_ORD(STAT_TX_HOST_COMPLETE, "successful Host Tx's (MSDU)"),
-	IPW2100_ORD(STAT_TX_DIR_DATA,	   "successful Directed Tx's (MSDU)"),
-	IPW2100_ORD(STAT_TX_DIR_DATA1,	   "successful Directed Tx's (MSDU) @ 1MB"),
-	IPW2100_ORD(STAT_TX_DIR_DATA2,	   "successful Directed Tx's (MSDU) @ 2MB"),
-	IPW2100_ORD(STAT_TX_DIR_DATA5_5,   "successful Directed Tx's (MSDU) @ 5_5MB"),
-	IPW2100_ORD(STAT_TX_DIR_DATA11,	   "successful Directed Tx's (MSDU) @ 11MB"),
-	IPW2100_ORD(STAT_TX_NODIR_DATA1,   "successful Non_Directed Tx's (MSDU) @ 1MB"),
-	IPW2100_ORD(STAT_TX_NODIR_DATA2,   "successful Non_Directed Tx's (MSDU) @ 2MB"),
-	IPW2100_ORD(STAT_TX_NODIR_DATA5_5, "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
-	IPW2100_ORD(STAT_TX_NODIR_DATA11,  "successful Non_Directed Tx's (MSDU) @ 11MB"),
-	IPW2100_ORD(STAT_NULL_DATA,	   "successful NULL data Tx's"),
-	IPW2100_ORD(STAT_TX_RTS,	   "successful Tx RTS"),
-	IPW2100_ORD(STAT_TX_CTS,	   "successful Tx CTS"),
-	IPW2100_ORD(STAT_TX_ACK,	   "successful Tx ACK"),
-	IPW2100_ORD(STAT_TX_ASSN,	   "successful Association Tx's"),
-	IPW2100_ORD(STAT_TX_ASSN_RESP,	   "successful Association response Tx's"),
-	IPW2100_ORD(STAT_TX_REASSN,	   "successful Reassociation Tx's"),
-	IPW2100_ORD(STAT_TX_REASSN_RESP,   "successful Reassociation response Tx's"),
-	IPW2100_ORD(STAT_TX_PROBE,	   "probes successfully transmitted"),
-	IPW2100_ORD(STAT_TX_PROBE_RESP,	   "probe responses successfully transmitted"),
-	IPW2100_ORD(STAT_TX_BEACON,	   "tx beacon"),
-	IPW2100_ORD(STAT_TX_ATIM,	   "Tx ATIM"),
-	IPW2100_ORD(STAT_TX_DISASSN,	   "successful Disassociation TX"),
-	IPW2100_ORD(STAT_TX_AUTH,	   "successful Authentication Tx"),
-	IPW2100_ORD(STAT_TX_DEAUTH,	   "successful Deauthentication TX"),
-	IPW2100_ORD(STAT_TX_TOTAL_BYTES,   "Total successful Tx data bytes"),
-	IPW2100_ORD(STAT_TX_RETRIES,       "Tx retries"),
-	IPW2100_ORD(STAT_TX_RETRY1,        "Tx retries at 1MBPS"),
-	IPW2100_ORD(STAT_TX_RETRY2,        "Tx retries at 2MBPS"),
-	IPW2100_ORD(STAT_TX_RETRY5_5,	   "Tx retries at 5.5MBPS"),
-	IPW2100_ORD(STAT_TX_RETRY11,	   "Tx retries at 11MBPS"),
-	IPW2100_ORD(STAT_TX_FAILURES,	   "Tx Failures"),
-	IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,"times max tries in a hop failed"),
-	IPW2100_ORD(STAT_TX_DISASSN_FAIL,	"times disassociation failed"),
-	IPW2100_ORD(STAT_TX_ERR_CTS,         "missed/bad CTS frames"),
-	IPW2100_ORD(STAT_TX_ERR_ACK,	"tx err due to acks"),
-	IPW2100_ORD(STAT_RX_HOST,	"packets passed to host"),
-	IPW2100_ORD(STAT_RX_DIR_DATA,	"directed packets"),
-	IPW2100_ORD(STAT_RX_DIR_DATA1,	"directed packets at 1MB"),
-	IPW2100_ORD(STAT_RX_DIR_DATA2,	"directed packets at 2MB"),
-	IPW2100_ORD(STAT_RX_DIR_DATA5_5,	"directed packets at 5.5MB"),
-	IPW2100_ORD(STAT_RX_DIR_DATA11,	"directed packets at 11MB"),
-	IPW2100_ORD(STAT_RX_NODIR_DATA,"nondirected packets"),
-	IPW2100_ORD(STAT_RX_NODIR_DATA1,	"nondirected packets at 1MB"),
-	IPW2100_ORD(STAT_RX_NODIR_DATA2,	"nondirected packets at 2MB"),
-	IPW2100_ORD(STAT_RX_NODIR_DATA5_5,	"nondirected packets at 5.5MB"),
-	IPW2100_ORD(STAT_RX_NODIR_DATA11,	"nondirected packets at 11MB"),
-	IPW2100_ORD(STAT_RX_NULL_DATA,	"null data rx's"),
-	IPW2100_ORD(STAT_RX_RTS,	"Rx RTS"),
-	IPW2100_ORD(STAT_RX_CTS,	"Rx CTS"),
-	IPW2100_ORD(STAT_RX_ACK,	"Rx ACK"),
-	IPW2100_ORD(STAT_RX_CFEND,	"Rx CF End"),
-	IPW2100_ORD(STAT_RX_CFEND_ACK,	"Rx CF End + CF Ack"),
-	IPW2100_ORD(STAT_RX_ASSN,	"Association Rx's"),
-	IPW2100_ORD(STAT_RX_ASSN_RESP,	"Association response Rx's"),
-	IPW2100_ORD(STAT_RX_REASSN,	"Reassociation Rx's"),
-	IPW2100_ORD(STAT_RX_REASSN_RESP,	"Reassociation response Rx's"),
-	IPW2100_ORD(STAT_RX_PROBE,	"probe Rx's"),
-	IPW2100_ORD(STAT_RX_PROBE_RESP,	"probe response Rx's"),
-	IPW2100_ORD(STAT_RX_BEACON,	"Rx beacon"),
-	IPW2100_ORD(STAT_RX_ATIM,	"Rx ATIM"),
-	IPW2100_ORD(STAT_RX_DISASSN,	"disassociation Rx"),
-	IPW2100_ORD(STAT_RX_AUTH,	"authentication Rx"),
-	IPW2100_ORD(STAT_RX_DEAUTH,	"deauthentication Rx"),
-	IPW2100_ORD(STAT_RX_TOTAL_BYTES,"Total rx data bytes received"),
-	IPW2100_ORD(STAT_RX_ERR_CRC,	 "packets with Rx CRC error"),
-	IPW2100_ORD(STAT_RX_ERR_CRC1,	 "Rx CRC errors at 1MB"),
-	IPW2100_ORD(STAT_RX_ERR_CRC2,	 "Rx CRC errors at 2MB"),
-	IPW2100_ORD(STAT_RX_ERR_CRC5_5,	 "Rx CRC errors at 5.5MB"),
-	IPW2100_ORD(STAT_RX_ERR_CRC11,	 "Rx CRC errors at 11MB"),
-	IPW2100_ORD(STAT_RX_DUPLICATE1, "duplicate rx packets at 1MB"),
-	IPW2100_ORD(STAT_RX_DUPLICATE2,	 "duplicate rx packets at 2MB"),
-	IPW2100_ORD(STAT_RX_DUPLICATE5_5,	 "duplicate rx packets at 5.5MB"),
-	IPW2100_ORD(STAT_RX_DUPLICATE11,	 "duplicate rx packets at 11MB"),
-	IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
-	IPW2100_ORD(PERS_DB_LOCK,	"locking fw permanent  db"),
-	IPW2100_ORD(PERS_DB_SIZE,	"size of fw permanent  db"),
-	IPW2100_ORD(PERS_DB_ADDR,	"address of fw permanent  db"),
-	IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,	"rx frames with invalid protocol"),
-	IPW2100_ORD(SYS_BOOT_TIME,	"Boot time"),
-	IPW2100_ORD(STAT_RX_NO_BUFFER,	"rx frames rejected due to no buffer"),
-	IPW2100_ORD(STAT_RX_MISSING_FRAG,	"rx frames dropped due to missing fragment"),
-	IPW2100_ORD(STAT_RX_ORPHAN_FRAG,	"rx frames dropped due to non-sequential fragment"),
-	IPW2100_ORD(STAT_RX_ORPHAN_FRAME,	"rx frames dropped due to unmatched 1st frame"),
-	IPW2100_ORD(STAT_RX_FRAG_AGEOUT,	"rx frames dropped due to uncompleted frame"),
-	IPW2100_ORD(STAT_RX_ICV_ERRORS,	"ICV errors during decryption"),
-	IPW2100_ORD(STAT_PSP_SUSPENSION,"times adapter suspended"),
-	IPW2100_ORD(STAT_PSP_BCN_TIMEOUT,	"beacon timeout"),
-	IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,	"poll response timeouts"),
-	IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT, "timeouts waiting for last {broad,multi}cast pkt"),
-	IPW2100_ORD(STAT_PSP_RX_DTIMS,	"PSP DTIMs received"),
-	IPW2100_ORD(STAT_PSP_RX_TIMS,	"PSP TIMs received"),
-	IPW2100_ORD(STAT_PSP_STATION_ID,"PSP Station ID"),
-	IPW2100_ORD(LAST_ASSN_TIME,	"RTC time of last association"),
-	IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,"current calculation of % missed beacons"),
-	IPW2100_ORD(STAT_PERCENT_RETRIES,"current calculation of % missed tx retries"),
-	IPW2100_ORD(ASSOCIATED_AP_PTR,	"0 if not associated, else pointer to AP table entry"),
-	IPW2100_ORD(AVAILABLE_AP_CNT,	"AP's decsribed in the AP table"),
-	IPW2100_ORD(AP_LIST_PTR,	"Ptr to list of available APs"),
-	IPW2100_ORD(STAT_AP_ASSNS,	"associations"),
-	IPW2100_ORD(STAT_ASSN_FAIL,	"association failures"),
-	IPW2100_ORD(STAT_ASSN_RESP_FAIL,"failures due to response fail"),
-	IPW2100_ORD(STAT_FULL_SCANS,	"full scans"),
-	IPW2100_ORD(CARD_DISABLED,	"Card Disabled"),
-	IPW2100_ORD(STAT_ROAM_INHIBIT,	"times roaming was inhibited due to activity"),
-	IPW2100_ORD(RSSI_AT_ASSN,	"RSSI of associated AP at time of association"),
-	IPW2100_ORD(STAT_ASSN_CAUSE1,	"reassociation: no probe response or TX on hop"),
-	IPW2100_ORD(STAT_ASSN_CAUSE2,	"reassociation: poor tx/rx quality"),
-	IPW2100_ORD(STAT_ASSN_CAUSE3,	"reassociation: tx/rx quality (excessive AP load"),
-	IPW2100_ORD(STAT_ASSN_CAUSE4,	"reassociation: AP RSSI level"),
-	IPW2100_ORD(STAT_ASSN_CAUSE5,	"reassociations due to load leveling"),
-	IPW2100_ORD(STAT_AUTH_FAIL,	"times authentication failed"),
-	IPW2100_ORD(STAT_AUTH_RESP_FAIL,"times authentication response failed"),
-	IPW2100_ORD(STATION_TABLE_CNT,	"entries in association table"),
-	IPW2100_ORD(RSSI_AVG_CURR,	"Current avg RSSI"),
-	IPW2100_ORD(POWER_MGMT_MODE,	"Power mode - 0=CAM, 1=PSP"),
-	IPW2100_ORD(COUNTRY_CODE,	"IEEE country code as recv'd from beacon"),
-	IPW2100_ORD(COUNTRY_CHANNELS,	"channels suported by country"),
-	IPW2100_ORD(RESET_CNT,	"adapter resets (warm)"),
-	IPW2100_ORD(BEACON_INTERVAL,	"Beacon interval"),
-	IPW2100_ORD(ANTENNA_DIVERSITY,	"TRUE if antenna diversity is disabled"),
-	IPW2100_ORD(DTIM_PERIOD,	"beacon intervals between DTIMs"),
-	IPW2100_ORD(OUR_FREQ,	"current radio freq lower digits - channel ID"),
-	IPW2100_ORD(RTC_TIME,	"current RTC time"),
-	IPW2100_ORD(PORT_TYPE,	"operating mode"),
-	IPW2100_ORD(CURRENT_TX_RATE,	"current tx rate"),
-	IPW2100_ORD(SUPPORTED_RATES,	"supported tx rates"),
-	IPW2100_ORD(ATIM_WINDOW,	"current ATIM Window"),
-	IPW2100_ORD(BASIC_RATES,	"basic tx rates"),
-	IPW2100_ORD(NIC_HIGHEST_RATE,	"NIC highest tx rate"),
-	IPW2100_ORD(AP_HIGHEST_RATE,	"AP highest tx rate"),
-	IPW2100_ORD(CAPABILITIES,	"Management frame capability field"),
-	IPW2100_ORD(AUTH_TYPE,	"Type of authentication"),
-	IPW2100_ORD(RADIO_TYPE,	"Adapter card platform type"),
-	IPW2100_ORD(RTS_THRESHOLD,	"Min packet length for RTS handshaking"),
-	IPW2100_ORD(INT_MODE,	"International mode"),
-	IPW2100_ORD(FRAGMENTATION_THRESHOLD,	"protocol frag threshold"),
-	IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,	"EEPROM offset in SRAM"),
-	IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,	"EEPROM size in SRAM"),
-	IPW2100_ORD(EEPROM_SKU_CAPABILITY,	"EEPROM SKU Capability"),
-	IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,	"EEPROM IBSS 11b channel set"),
-	IPW2100_ORD(MAC_VERSION,	"MAC Version"),
-	IPW2100_ORD(MAC_REVISION,	"MAC Revision"),
-	IPW2100_ORD(RADIO_VERSION,	"Radio Version"),
-	IPW2100_ORD(NIC_MANF_DATE_TIME,	"MANF Date/Time STAMP"),
-	IPW2100_ORD(UCODE_VERSION,	"Ucode Version"),
-};
-
+IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
+	    IPW2100_ORD(STAT_TX_HOST_COMPLETE,
+				"successful Host Tx's (MSDU)"),
+	    IPW2100_ORD(STAT_TX_DIR_DATA,
+				"successful Directed Tx's (MSDU)"),
+	    IPW2100_ORD(STAT_TX_DIR_DATA1,
+				"successful Directed Tx's (MSDU) @ 1MB"),
+	    IPW2100_ORD(STAT_TX_DIR_DATA2,
+				"successful Directed Tx's (MSDU) @ 2MB"),
+	    IPW2100_ORD(STAT_TX_DIR_DATA5_5,
+				"successful Directed Tx's (MSDU) @ 5_5MB"),
+	    IPW2100_ORD(STAT_TX_DIR_DATA11,
+				"successful Directed Tx's (MSDU) @ 11MB"),
+	    IPW2100_ORD(STAT_TX_NODIR_DATA1,
+				"successful Non_Directed Tx's (MSDU) @ 1MB"),
+	    IPW2100_ORD(STAT_TX_NODIR_DATA2,
+				"successful Non_Directed Tx's (MSDU) @ 2MB"),
+	    IPW2100_ORD(STAT_TX_NODIR_DATA5_5,
+				"successful Non_Directed Tx's (MSDU) @ 5.5MB"),
+	    IPW2100_ORD(STAT_TX_NODIR_DATA11,
+				"successful Non_Directed Tx's (MSDU) @ 11MB"),
+	    IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
+	    IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
+	    IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
+	    IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
+	    IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
+	    IPW2100_ORD(STAT_TX_ASSN_RESP,
+				"successful Association response Tx's"),
+	    IPW2100_ORD(STAT_TX_REASSN,
+				"successful Reassociation Tx's"),
+	    IPW2100_ORD(STAT_TX_REASSN_RESP,
+				"successful Reassociation response Tx's"),
+	    IPW2100_ORD(STAT_TX_PROBE,
+				"probes successfully transmitted"),
+	    IPW2100_ORD(STAT_TX_PROBE_RESP,
+				"probe responses successfully transmitted"),
+	    IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
+	    IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
+	    IPW2100_ORD(STAT_TX_DISASSN,
+				"successful Disassociation TX"),
+	    IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
+	    IPW2100_ORD(STAT_TX_DEAUTH,
+				"successful Deauthentication TX"),
+	    IPW2100_ORD(STAT_TX_TOTAL_BYTES,
+				"Total successful Tx data bytes"),
+	    IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
+	    IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
+	    IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
+	    IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
+	    IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
+	    IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
+	    IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,
+				"times max tries in a hop failed"),
+	    IPW2100_ORD(STAT_TX_DISASSN_FAIL,
+				"times disassociation failed"),
+	    IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
+	    IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
+	    IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
+	    IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
+	    IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
+	    IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
+	    IPW2100_ORD(STAT_RX_DIR_DATA5_5,
+				"directed packets at 5.5MB"),
+	    IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
+	    IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"),
+	    IPW2100_ORD(STAT_RX_NODIR_DATA1,
+				"nondirected packets at 1MB"),
+	    IPW2100_ORD(STAT_RX_NODIR_DATA2,
+				"nondirected packets at 2MB"),
+	    IPW2100_ORD(STAT_RX_NODIR_DATA5_5,
+				"nondirected packets at 5.5MB"),
+	    IPW2100_ORD(STAT_RX_NODIR_DATA11,
+				"nondirected packets at 11MB"),
+	    IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
+	    IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS,
+								    "Rx CTS"),
+	    IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
+	    IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
+	    IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
+	    IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
+	    IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
+	    IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
+	    IPW2100_ORD(STAT_RX_REASSN_RESP,
+				"Reassociation response Rx's"),
+	    IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
+	    IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
+	    IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
+	    IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
+	    IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
+	    IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
+	    IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
+	    IPW2100_ORD(STAT_RX_TOTAL_BYTES,
+				"Total rx data bytes received"),
+	    IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
+	    IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
+	    IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
+	    IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
+	    IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
+	    IPW2100_ORD(STAT_RX_DUPLICATE1,
+				"duplicate rx packets at 1MB"),
+	    IPW2100_ORD(STAT_RX_DUPLICATE2,
+				"duplicate rx packets at 2MB"),
+	    IPW2100_ORD(STAT_RX_DUPLICATE5_5,
+				"duplicate rx packets at 5.5MB"),
+	    IPW2100_ORD(STAT_RX_DUPLICATE11,
+				"duplicate rx packets at 11MB"),
+	    IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
+	    IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent  db"),
+	    IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent  db"),
+	    IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent  db"),
+	    IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,
+				"rx frames with invalid protocol"),
+	    IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
+	    IPW2100_ORD(STAT_RX_NO_BUFFER,
+				"rx frames rejected due to no buffer"),
+	    IPW2100_ORD(STAT_RX_MISSING_FRAG,
+				"rx frames dropped due to missing fragment"),
+	    IPW2100_ORD(STAT_RX_ORPHAN_FRAG,
+				"rx frames dropped due to non-sequential fragment"),
+	    IPW2100_ORD(STAT_RX_ORPHAN_FRAME,
+				"rx frames dropped due to unmatched 1st frame"),
+	    IPW2100_ORD(STAT_RX_FRAG_AGEOUT,
+				"rx frames dropped due to uncompleted frame"),
+	    IPW2100_ORD(STAT_RX_ICV_ERRORS,
+				"ICV errors during decryption"),
+	    IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"),
+	    IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
+	    IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,
+				"poll response timeouts"),
+	    IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT,
+				"timeouts waiting for last {broad,multi}cast pkt"),
+	    IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
+	    IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
+	    IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"),
+	    IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
+	    IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,
+				"current calculation of % missed beacons"),
+	    IPW2100_ORD(STAT_PERCENT_RETRIES,
+				"current calculation of % missed tx retries"),
+	    IPW2100_ORD(ASSOCIATED_AP_PTR,
+				"0 if not associated, else pointer to AP table entry"),
+	    IPW2100_ORD(AVAILABLE_AP_CNT,
+				"AP's decsribed in the AP table"),
+	    IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
+	    IPW2100_ORD(STAT_AP_ASSNS, "associations"),
+	    IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
+	    IPW2100_ORD(STAT_ASSN_RESP_FAIL,
+				"failures due to response fail"),
+	    IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
+	    IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
+	    IPW2100_ORD(STAT_ROAM_INHIBIT,
+				"times roaming was inhibited due to activity"),
+	    IPW2100_ORD(RSSI_AT_ASSN,
+				"RSSI of associated AP at time of association"),
+	    IPW2100_ORD(STAT_ASSN_CAUSE1,
+				"reassociation: no probe response or TX on hop"),
+	    IPW2100_ORD(STAT_ASSN_CAUSE2,
+				"reassociation: poor tx/rx quality"),
+	    IPW2100_ORD(STAT_ASSN_CAUSE3,
+				"reassociation: tx/rx quality (excessive AP load"),
+	    IPW2100_ORD(STAT_ASSN_CAUSE4,
+				"reassociation: AP RSSI level"),
+	    IPW2100_ORD(STAT_ASSN_CAUSE5,
+				"reassociations due to load leveling"),
+	    IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
+	    IPW2100_ORD(STAT_AUTH_RESP_FAIL,
+				"times authentication response failed"),
+	    IPW2100_ORD(STATION_TABLE_CNT,
+				"entries in association table"),
+	    IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
+	    IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
+	    IPW2100_ORD(COUNTRY_CODE,
+				"IEEE country code as recv'd from beacon"),
+	    IPW2100_ORD(COUNTRY_CHANNELS,
+				"channels suported by country"),
+	    IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
+	    IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
+	    IPW2100_ORD(ANTENNA_DIVERSITY,
+				"TRUE if antenna diversity is disabled"),
+	    IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
+	    IPW2100_ORD(OUR_FREQ,
+				"current radio freq lower digits - channel ID"),
+	    IPW2100_ORD(RTC_TIME, "current RTC time"),
+	    IPW2100_ORD(PORT_TYPE, "operating mode"),
+	    IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
+	    IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
+	    IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
+	    IPW2100_ORD(BASIC_RATES, "basic tx rates"),
+	    IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
+	    IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
+	    IPW2100_ORD(CAPABILITIES,
+				"Management frame capability field"),
+	    IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
+	    IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
+	    IPW2100_ORD(RTS_THRESHOLD,
+				"Min packet length for RTS handshaking"),
+	    IPW2100_ORD(INT_MODE, "International mode"),
+	    IPW2100_ORD(FRAGMENTATION_THRESHOLD,
+				"protocol frag threshold"),
+	    IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
+				"EEPROM offset in SRAM"),
+	    IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,
+				"EEPROM size in SRAM"),
+	    IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
+	    IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,
+				"EEPROM IBSS 11b channel set"),
+	    IPW2100_ORD(MAC_VERSION, "MAC Version"),
+	    IPW2100_ORD(MAC_REVISION, "MAC Revision"),
+	    IPW2100_ORD(RADIO_VERSION, "Radio Version"),
+	    IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
+	    IPW2100_ORD(UCODE_VERSION, "Ucode Version"),};
 
 static ssize_t show_registers(struct device *d, struct device_attribute *attr,
-				char *buf)
+			      char *buf)
 {
 	int i;
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	struct net_device *dev = priv->net_dev;
-	char * out = buf;
+	char *out = buf;
 	u32 val = 0;
 
 	out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
@@ -3647,15 +3640,15 @@
 
 	return out - buf;
 }
+
 static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
 
-
 static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
-				char *buf)
+			     char *buf)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	struct net_device *dev = priv->net_dev;
-	char * out = buf;
+	char *out = buf;
 	int i;
 
 	out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
@@ -3688,11 +3681,11 @@
 	}
 	return out - buf;
 }
+
 static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
 
-
 static ssize_t show_memory(struct device *d, struct device_attribute *attr,
-				char *buf)
+			   char *buf)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	struct net_device *dev = priv->net_dev;
@@ -3708,10 +3701,13 @@
 	/* sysfs provides us PAGE_SIZE buffer */
 	while (len < PAGE_SIZE - 128 && loop < 0x30000) {
 
-		if (priv->snapshot[0]) for (i = 0; i < 4; i++)
-			buffer[i] = *(u32 *)SNAPSHOT_ADDR(loop + i * 4);
-		else for (i = 0; i < 4; i++)
-			read_nic_dword(dev, loop + i * 4, &buffer[i]);
+		if (priv->snapshot[0])
+			for (i = 0; i < 4; i++)
+				buffer[i] =
+				    *(u32 *) SNAPSHOT_ADDR(loop + i * 4);
+		else
+			for (i = 0; i < 4; i++)
+				read_nic_dword(dev, loop + i * 4, &buffer[i]);
 
 		if (priv->dump_raw)
 			len += sprintf(buf + len,
@@ -3719,26 +3715,26 @@
 				       "%c%c%c%c"
 				       "%c%c%c%c"
 				       "%c%c%c%c",
-				       ((u8*)buffer)[0x0],
-				       ((u8*)buffer)[0x1],
-				       ((u8*)buffer)[0x2],
-				       ((u8*)buffer)[0x3],
-				       ((u8*)buffer)[0x4],
-				       ((u8*)buffer)[0x5],
-				       ((u8*)buffer)[0x6],
-				       ((u8*)buffer)[0x7],
-				       ((u8*)buffer)[0x8],
-				       ((u8*)buffer)[0x9],
-				       ((u8*)buffer)[0xa],
-				       ((u8*)buffer)[0xb],
-				       ((u8*)buffer)[0xc],
-				       ((u8*)buffer)[0xd],
-				       ((u8*)buffer)[0xe],
-				       ((u8*)buffer)[0xf]);
+				       ((u8 *) buffer)[0x0],
+				       ((u8 *) buffer)[0x1],
+				       ((u8 *) buffer)[0x2],
+				       ((u8 *) buffer)[0x3],
+				       ((u8 *) buffer)[0x4],
+				       ((u8 *) buffer)[0x5],
+				       ((u8 *) buffer)[0x6],
+				       ((u8 *) buffer)[0x7],
+				       ((u8 *) buffer)[0x8],
+				       ((u8 *) buffer)[0x9],
+				       ((u8 *) buffer)[0xa],
+				       ((u8 *) buffer)[0xb],
+				       ((u8 *) buffer)[0xc],
+				       ((u8 *) buffer)[0xd],
+				       ((u8 *) buffer)[0xe],
+				       ((u8 *) buffer)[0xf]);
 		else
 			len += sprintf(buf + len, "%s\n",
 				       snprint_line(line, sizeof(line),
-						    (u8*)buffer, 16, loop));
+						    (u8 *) buffer, 16, loop));
 		loop += 16;
 	}
 
@@ -3746,44 +3742,44 @@
 }
 
 static ssize_t store_memory(struct device *d, struct device_attribute *attr,
-				const char *buf, size_t count)
+			    const char *buf, size_t count)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	struct net_device *dev = priv->net_dev;
 	const char *p = buf;
 
+	(void) dev; /* kill unused-var warning for debug-only code */
+
 	if (count < 1)
 		return count;
 
 	if (p[0] == '1' ||
 	    (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
 		IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
-		       dev->name);
+			       dev->name);
 		priv->dump_raw = 1;
 
 	} else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
-				  tolower(p[1]) == 'f')) {
+				   tolower(p[1]) == 'f')) {
 		IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
-		       dev->name);
+			       dev->name);
 		priv->dump_raw = 0;
 
 	} else if (tolower(p[0]) == 'r') {
-		IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n",
-		       dev->name);
+		IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name);
 		ipw2100_snapshot_free(priv);
 
 	} else
 		IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
-		       "reset = clear memory snapshot\n",
-		       dev->name);
+			       "reset = clear memory snapshot\n", dev->name);
 
 	return count;
 }
-static DEVICE_ATTR(memory, S_IWUSR|S_IRUGO, show_memory, store_memory);
 
+static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory);
 
 static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
-				char *buf)
+			     char *buf)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	u32 val = 0;
@@ -3791,6 +3787,9 @@
 	u32 val_len;
 	static int loop = 0;
 
+	if (priv->status & STATUS_RF_KILL_MASK)
+		return 0;
+
 	if (loop >= sizeof(ord_data) / sizeof(*ord_data))
 		loop = 0;
 
@@ -3814,14 +3813,14 @@
 
 	return len;
 }
+
 static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
 
-
 static ssize_t show_stats(struct device *d, struct device_attribute *attr,
-				char *buf)
+			  char *buf)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
-	char * out = buf;
+	char *out = buf;
 
 	out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
 		       priv->interrupts, priv->tx_interrupts,
@@ -3835,8 +3834,8 @@
 
 	return out - buf;
 }
-static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
 
+static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
 
 static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
 {
@@ -3864,19 +3863,18 @@
 		priv->last_mode = priv->ieee->iw_mode;
 		priv->net_dev->type = ARPHRD_IEEE80211;
 		break;
-#endif /* CONFIG_IPW2100_MONITOR */
+#endif				/* CONFIG_IPW2100_MONITOR */
 	}
 
 	priv->ieee->iw_mode = mode;
 
 #ifdef CONFIG_PM
-        /* Indicate ipw2100_download_firmware download firmware
+	/* Indicate ipw2100_download_firmware download firmware
 	 * from disk instead of memory. */
 	ipw2100_firmware.version = 0;
 #endif
 
-	printk(KERN_INFO "%s: Reseting on mode change.\n",
-		priv->net_dev->name);
+	printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name);
 	priv->reset_backoff = 0;
 	schedule_reset(priv);
 
@@ -3884,12 +3882,12 @@
 }
 
 static ssize_t show_internals(struct device *d, struct device_attribute *attr,
-				char *buf)
+			      char *buf)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	int len = 0;
 
-#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" # y "\n", priv-> x)
+#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x)
 
 	if (priv->status & STATUS_ASSOCIATED)
 		len += sprintf(buf + len, "connected: %lu\n",
@@ -3897,55 +3895,60 @@
 	else
 		len += sprintf(buf + len, "not connected\n");
 
-	DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], p);
-	DUMP_VAR(status, 08lx);
-	DUMP_VAR(config, 08lx);
-	DUMP_VAR(capability, 08lx);
+	DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], "p");
+	DUMP_VAR(status, "08lx");
+	DUMP_VAR(config, "08lx");
+	DUMP_VAR(capability, "08lx");
 
-	len += sprintf(buf + len, "last_rtc: %lu\n", (unsigned long)priv->last_rtc);
+	len +=
+	    sprintf(buf + len, "last_rtc: %lu\n",
+		    (unsigned long)priv->last_rtc);
 
-	DUMP_VAR(fatal_error, d);
-	DUMP_VAR(stop_hang_check, d);
-	DUMP_VAR(stop_rf_kill, d);
-	DUMP_VAR(messages_sent, d);
+	DUMP_VAR(fatal_error, "d");
+	DUMP_VAR(stop_hang_check, "d");
+	DUMP_VAR(stop_rf_kill, "d");
+	DUMP_VAR(messages_sent, "d");
 
-	DUMP_VAR(tx_pend_stat.value, d);
-	DUMP_VAR(tx_pend_stat.hi, d);
+	DUMP_VAR(tx_pend_stat.value, "d");
+	DUMP_VAR(tx_pend_stat.hi, "d");
 
-	DUMP_VAR(tx_free_stat.value, d);
-	DUMP_VAR(tx_free_stat.lo, d);
+	DUMP_VAR(tx_free_stat.value, "d");
+	DUMP_VAR(tx_free_stat.lo, "d");
 
-	DUMP_VAR(msg_free_stat.value, d);
-	DUMP_VAR(msg_free_stat.lo, d);
+	DUMP_VAR(msg_free_stat.value, "d");
+	DUMP_VAR(msg_free_stat.lo, "d");
 
-	DUMP_VAR(msg_pend_stat.value, d);
-	DUMP_VAR(msg_pend_stat.hi, d);
+	DUMP_VAR(msg_pend_stat.value, "d");
+	DUMP_VAR(msg_pend_stat.hi, "d");
 
-	DUMP_VAR(fw_pend_stat.value, d);
-	DUMP_VAR(fw_pend_stat.hi, d);
+	DUMP_VAR(fw_pend_stat.value, "d");
+	DUMP_VAR(fw_pend_stat.hi, "d");
 
-	DUMP_VAR(txq_stat.value, d);
-	DUMP_VAR(txq_stat.lo, d);
+	DUMP_VAR(txq_stat.value, "d");
+	DUMP_VAR(txq_stat.lo, "d");
 
-	DUMP_VAR(ieee->scans, d);
-	DUMP_VAR(reset_backoff, d);
+	DUMP_VAR(ieee->scans, "d");
+	DUMP_VAR(reset_backoff, "d");
 
 	return len;
 }
+
 static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
 
-
 static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
-				char *buf)
+			    char *buf)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	char essid[IW_ESSID_MAX_SIZE + 1];
 	u8 bssid[ETH_ALEN];
 	u32 chan = 0;
-	char * out = buf;
+	char *out = buf;
 	int length;
 	int ret;
 
+	if (priv->status & STATUS_RF_KILL_MASK)
+		return 0;
+
 	memset(essid, 0, sizeof(essid));
 	memset(bssid, 0, sizeof(bssid));
 
@@ -3976,8 +3979,8 @@
 
 	return out - buf;
 }
-static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
 
+static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
 
 #ifdef CONFIG_IPW_DEBUG
 static ssize_t show_debug_level(struct device_driver *d, char *buf)
@@ -3985,8 +3988,8 @@
 	return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
 }
 
-static ssize_t store_debug_level(struct device_driver *d, const char *buf,
-				 size_t count)
+static ssize_t store_debug_level(struct device_driver *d,
+				 const char *buf, size_t count)
 {
 	char *p = (char *)buf;
 	u32 val;
@@ -3999,28 +4002,26 @@
 	} else
 		val = simple_strtoul(p, &p, 10);
 	if (p == buf)
-		IPW_DEBUG_INFO(DRV_NAME
-		       ": %s is not in hex or decimal form.\n", buf);
+		IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
 	else
 		ipw2100_debug_level = val;
 
 	return strnlen(buf, count);
 }
+
 static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
 		   store_debug_level);
-#endif /* CONFIG_IPW_DEBUG */
-
+#endif				/* CONFIG_IPW_DEBUG */
 
 static ssize_t show_fatal_error(struct device *d,
-			struct device_attribute *attr, char *buf)
+				struct device_attribute *attr, char *buf)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	char *out = buf;
 	int i;
 
 	if (priv->fatal_error)
-		out += sprintf(out, "0x%08X\n",
-			       priv->fatal_error);
+		out += sprintf(out, "0x%08X\n", priv->fatal_error);
 	else
 		out += sprintf(out, "0\n");
 
@@ -4038,24 +4039,26 @@
 }
 
 static ssize_t store_fatal_error(struct device *d,
-		struct device_attribute *attr, const char *buf, size_t count)
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	schedule_reset(priv);
 	return count;
 }
-static DEVICE_ATTR(fatal_error, S_IWUSR|S_IRUGO, show_fatal_error, store_fatal_error);
 
+static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error,
+		   store_fatal_error);
 
 static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
-				char *buf)
+			     char *buf)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	return sprintf(buf, "%d\n", priv->ieee->scan_age);
 }
 
 static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
-				const char *buf, size_t count)
+			      const char *buf, size_t count)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	struct net_device *dev = priv->net_dev;
@@ -4065,6 +4068,8 @@
 	unsigned long val;
 	char *p = buffer;
 
+	(void) dev; /* kill unused-var warning for debug-only code */
+
 	IPW_DEBUG_INFO("enter\n");
 
 	strncpy(buffer, buf, len);
@@ -4078,8 +4083,7 @@
 	} else
 		val = simple_strtoul(p, &p, 10);
 	if (p == buffer) {
-		IPW_DEBUG_INFO("%s: user supplied invalid value.\n",
-		       dev->name);
+		IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
 	} else {
 		priv->ieee->scan_age = val;
 		IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
@@ -4088,11 +4092,11 @@
 	IPW_DEBUG_INFO("exit\n");
 	return len;
 }
+
 static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
 
-
 static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
-				char *buf)
+			    char *buf)
 {
 	/* 0 - RF kill not enabled
 	   1 - SW based RF kill active (sysfs)
@@ -4100,7 +4104,7 @@
 	   3 - Both HW and SW baed RF kill active */
 	struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data;
 	int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
-		(rf_kill_active(priv) ? 0x2 : 0x0);
+	    (rf_kill_active(priv) ? 0x2 : 0x0);
 	return sprintf(buf, "%i\n", val);
 }
 
@@ -4108,7 +4112,7 @@
 {
 	if ((disable_radio ? 1 : 0) ==
 	    (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
-		return 0 ;
+		return 0;
 
 	IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO  %s\n",
 			  disable_radio ? "OFF" : "ON");
@@ -4126,8 +4130,7 @@
 			/* Make sure the RF_KILL check timer is running */
 			priv->stop_rf_kill = 0;
 			cancel_delayed_work(&priv->rf_kill);
-			queue_delayed_work(priv->workqueue, &priv->rf_kill,
-					   HZ);
+			queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
 		} else
 			schedule_reset(priv);
 	}
@@ -4137,14 +4140,14 @@
 }
 
 static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
-				const char *buf, size_t count)
+			     const char *buf, size_t count)
 {
 	struct ipw2100_priv *priv = dev_get_drvdata(d);
 	ipw_radio_kill_sw(priv, buf[0] == '1');
 	return count;
 }
-static DEVICE_ATTR(rf_kill, S_IWUSR|S_IRUGO, show_rf_kill, store_rf_kill);
 
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
 
 static struct attribute *ipw2100_sysfs_entries[] = {
 	&dev_attr_hardware.attr,
@@ -4168,7 +4171,6 @@
 	.attrs = ipw2100_sysfs_entries,
 };
 
-
 static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
 {
 	struct ipw2100_status_queue *q = &priv->status_queue;
@@ -4176,11 +4178,11 @@
 	IPW_DEBUG_INFO("enter\n");
 
 	q->size = entries * sizeof(struct ipw2100_status);
-	q->drv = (struct ipw2100_status *)pci_alloc_consistent(
-		priv->pci_dev, q->size, &q->nic);
+	q->drv =
+	    (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev,
+							  q->size, &q->nic);
 	if (!q->drv) {
-		IPW_DEBUG_WARNING(
-		       "Can not allocate status queue.\n");
+		IPW_DEBUG_WARNING("Can not allocate status queue.\n");
 		return -ENOMEM;
 	}
 
@@ -4196,9 +4198,9 @@
 	IPW_DEBUG_INFO("enter\n");
 
 	if (priv->status_queue.drv) {
-		pci_free_consistent(
-			priv->pci_dev, priv->status_queue.size,
-			priv->status_queue.drv, priv->status_queue.nic);
+		pci_free_consistent(priv->pci_dev, priv->status_queue.size,
+				    priv->status_queue.drv,
+				    priv->status_queue.nic);
 		priv->status_queue.drv = NULL;
 	}
 
@@ -4216,7 +4218,8 @@
 	q->size = entries * sizeof(struct ipw2100_bd);
 	q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic);
 	if (!q->drv) {
-		IPW_DEBUG_INFO("can't allocate shared memory for buffer descriptors\n");
+		IPW_DEBUG_INFO
+		    ("can't allocate shared memory for buffer descriptors\n");
 		return -ENOMEM;
 	}
 	memset(q->drv, 0, q->size);
@@ -4226,8 +4229,7 @@
 	return 0;
 }
 
-static void bd_queue_free(struct ipw2100_priv *priv,
-			  struct ipw2100_bd_queue *q)
+static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
 {
 	IPW_DEBUG_INFO("enter\n");
 
@@ -4235,21 +4237,21 @@
 		return;
 
 	if (q->drv) {
-		pci_free_consistent(priv->pci_dev,
-				    q->size, q->drv, q->nic);
+		pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic);
 		q->drv = NULL;
 	}
 
 	IPW_DEBUG_INFO("exit\n");
 }
 
-static void bd_queue_initialize(
-	struct ipw2100_priv *priv, struct ipw2100_bd_queue * q,
-	u32 base, u32 size, u32 r, u32 w)
+static void bd_queue_initialize(struct ipw2100_priv *priv,
+				struct ipw2100_bd_queue *q, u32 base, u32 size,
+				u32 r, u32 w)
 {
 	IPW_DEBUG_INFO("enter\n");
 
-	IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv, (u32)q->nic);
+	IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
+		       (u32) q->nic);
 
 	write_register(priv->net_dev, base, q->nic);
 	write_register(priv->net_dev, size, q->entries);
@@ -4285,32 +4287,38 @@
 	err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
 	if (err) {
 		IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
-		       priv->net_dev->name);
+				priv->net_dev->name);
 		return err;
 	}
 
-	priv->tx_buffers = (struct ipw2100_tx_packet *)kmalloc(
-		TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
-		GFP_ATOMIC);
+	priv->tx_buffers =
+	    (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH *
+						sizeof(struct
+						       ipw2100_tx_packet),
+						GFP_ATOMIC);
 	if (!priv->tx_buffers) {
-		printk(KERN_ERR DRV_NAME ": %s: alloc failed form tx buffers.\n",
+		printk(KERN_ERR DRV_NAME
+		       ": %s: alloc failed form tx buffers.\n",
 		       priv->net_dev->name);
 		bd_queue_free(priv, &priv->tx_queue);
 		return -ENOMEM;
 	}
 
 	for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
-		v = pci_alloc_consistent(
-			priv->pci_dev, sizeof(struct ipw2100_data_header), &p);
+		v = pci_alloc_consistent(priv->pci_dev,
+					 sizeof(struct ipw2100_data_header),
+					 &p);
 		if (!v) {
-			printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for tx "
-			       "buffers.\n", priv->net_dev->name);
+			printk(KERN_ERR DRV_NAME
+			       ": %s: PCI alloc failed for tx " "buffers.\n",
+			       priv->net_dev->name);
 			err = -ENOMEM;
 			break;
 		}
 
 		priv->tx_buffers[i].type = DATA;
-		priv->tx_buffers[i].info.d_struct.data = (struct ipw2100_data_header*)v;
+		priv->tx_buffers[i].info.d_struct.data =
+		    (struct ipw2100_data_header *)v;
 		priv->tx_buffers[i].info.d_struct.data_phys = p;
 		priv->tx_buffers[i].info.d_struct.txb = NULL;
 	}
@@ -4319,11 +4327,11 @@
 		return 0;
 
 	for (j = 0; j < i; j++) {
-		pci_free_consistent(
-			priv->pci_dev,
-			sizeof(struct ipw2100_data_header),
-			priv->tx_buffers[j].info.d_struct.data,
-			priv->tx_buffers[j].info.d_struct.data_phys);
+		pci_free_consistent(priv->pci_dev,
+				    sizeof(struct ipw2100_data_header),
+				    priv->tx_buffers[j].info.d_struct.data,
+				    priv->tx_buffers[j].info.d_struct.
+				    data_phys);
 	}
 
 	kfree(priv->tx_buffers);
@@ -4356,7 +4364,8 @@
 		/* We simply drop any SKBs that have been queued for
 		 * transmit */
 		if (priv->tx_buffers[i].info.d_struct.txb) {
-			ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb);
+			ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
+					   txb);
 			priv->tx_buffers[i].info.d_struct.txb = NULL;
 		}
 
@@ -4394,15 +4403,17 @@
 
 	for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
 		if (priv->tx_buffers[i].info.d_struct.txb) {
-			ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb);
+			ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
+					   txb);
 			priv->tx_buffers[i].info.d_struct.txb = NULL;
 		}
 		if (priv->tx_buffers[i].info.d_struct.data)
-			pci_free_consistent(
-				priv->pci_dev,
-				sizeof(struct ipw2100_data_header),
-				priv->tx_buffers[i].info.d_struct.data,
-				priv->tx_buffers[i].info.d_struct.data_phys);
+			pci_free_consistent(priv->pci_dev,
+					    sizeof(struct ipw2100_data_header),
+					    priv->tx_buffers[i].info.d_struct.
+					    data,
+					    priv->tx_buffers[i].info.d_struct.
+					    data_phys);
 	}
 
 	kfree(priv->tx_buffers);
@@ -4411,8 +4422,6 @@
 	IPW_DEBUG_INFO("exit\n");
 }
 
-
-
 static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
 {
 	int i, j, err = -EINVAL;
@@ -4542,14 +4551,13 @@
 
 	int err;
 
-	err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC,
-				  mac, &length);
+	err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length);
 	if (err) {
 		IPW_DEBUG_INFO("MAC address read failed\n");
 		return -EIO;
 	}
 	IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n",
-	       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+		       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
 
 	memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN);
 
@@ -4576,8 +4584,7 @@
 	IPW_DEBUG_INFO("enter\n");
 
 	if (priv->config & CFG_CUSTOM_MAC) {
-		memcpy(cmd.host_command_parameters, priv->mac_addr,
-		       ETH_ALEN);
+		memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
 		memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
 	} else
 		memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
@@ -4614,7 +4621,8 @@
 	if (!batch_mode) {
 		err = ipw2100_disable_adapter(priv);
 		if (err) {
-			printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+			printk(KERN_ERR DRV_NAME
+			       ": %s: Could not disable adapter %d\n",
 			       priv->net_dev->name, err);
 			return err;
 		}
@@ -4629,7 +4637,6 @@
 	return err;
 }
 
-
 static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
 			       int batch_mode)
 {
@@ -4660,8 +4667,7 @@
 
 	err = ipw2100_hw_send_command(priv, &cmd);
 	if (err) {
-		IPW_DEBUG_INFO("Failed to set channel to %d",
-			       channel);
+		IPW_DEBUG_INFO("Failed to set channel to %d", channel);
 		return err;
 	}
 
@@ -4703,15 +4709,14 @@
 		cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
 
 	cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
-		IPW_CFG_BSS_MASK |
-		IPW_CFG_802_1x_ENABLE;
+	    IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
 
 	if (!(priv->config & CFG_LONG_PREAMBLE))
 		cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
 
 	err = ipw2100_get_ordinal(priv,
 				  IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
-				  &ibss_mask,  &len);
+				  &ibss_mask, &len);
 	if (err)
 		ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
 
@@ -4719,7 +4724,7 @@
 	cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
 
 	/* 11b only */
-	/*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A;*/
+	/*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
 
 	err = ipw2100_hw_send_command(priv, &cmd);
 	if (err)
@@ -4783,8 +4788,7 @@
 	return 0;
 }
 
-static int ipw2100_set_power_mode(struct ipw2100_priv *priv,
-				  int power_level)
+static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
 {
 	struct host_command cmd = {
 		.host_command = POWER_MODE,
@@ -4805,11 +4809,10 @@
 		priv->power_mode = IPW_POWER_ENABLED | power_level;
 
 #ifdef CONFIG_IPW2100_TX_POWER
-	if (priv->port_type == IBSS &&
-	    priv->adhoc_power != DFTL_IBSS_TX_POWER) {
+	if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
 		/* Set beacon interval */
 		cmd.host_command = TX_POWER_INDEX;
-		cmd.host_command_parameters[0] = (u32)priv->adhoc_power;
+		cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
 
 		err = ipw2100_hw_send_command(priv, &cmd);
 		if (err)
@@ -4820,7 +4823,6 @@
 	return 0;
 }
 
-
 static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
 {
 	struct host_command cmd = {
@@ -4925,8 +4927,7 @@
 	return 0;
 }
 
-
-static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 *bssid,
+static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
 				       int batch_mode)
 {
 	struct host_command cmd = {
@@ -4938,16 +4939,15 @@
 
 #ifdef CONFIG_IPW_DEBUG
 	if (bssid != NULL)
-		IPW_DEBUG_HC(
-			"MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
-			bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
-			bssid[5]);
+		IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
+			     bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
+			     bssid[5]);
 	else
 		IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
 #endif
 	/* if BSSID is empty then we disable mandatory bssid mode */
 	if (bssid != NULL)
-		memcpy((u8 *)cmd.host_command_parameters, bssid, ETH_ALEN);
+		memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
 
 	if (!batch_mode) {
 		err = ipw2100_disable_adapter(priv);
@@ -4963,7 +4963,6 @@
 	return err;
 }
 
-#ifdef CONFIG_IEEE80211_WPA
 static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
 {
 	struct host_command cmd = {
@@ -4987,42 +4986,10 @@
 
 	return err;
 }
-#endif
-
-/*
- * Pseudo code for setting up wpa_frame:
- */
-#if 0
-void x(struct ieee80211_assoc_frame *wpa_assoc)
-{
-	struct ipw2100_wpa_assoc_frame frame;
-	frame->fixed_ie_mask = IPW_WPA_CAPABILTIES |
-		IPW_WPA_LISTENINTERVAL |
-		IPW_WPA_AP_ADDRESS;
-	frame->capab_info = wpa_assoc->capab_info;
-	frame->lisen_interval = wpa_assoc->listent_interval;
-	memcpy(frame->current_ap, wpa_assoc->current_ap, ETH_ALEN);
-
-	/* UNKNOWN -- I'm not postivive about this part; don't have any WPA
-	 * setup here to test it with.
-	 *
-	 * Walk the IEs in the wpa_assoc and figure out the total size of all
-	 * that data.  Stick that into frame->var_ie_len.  Then memcpy() all of
-	 * the IEs from wpa_frame into frame.
-	 */
-	frame->var_ie_len = calculate_ie_len(wpa_assoc);
-	memcpy(frame->var_ie,  wpa_assoc->variable, frame->var_ie_len);
-
-	ipw2100_set_wpa_ie(priv, &frame, 0);
-}
-#endif
-
-
-
 
 static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
 			      struct ipw2100_wpa_assoc_frame *, int)
-__attribute__ ((unused));
+    __attribute__ ((unused));
 
 static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
 			      struct ipw2100_wpa_assoc_frame *wpa_frame,
@@ -5076,7 +5043,7 @@
 		.host_command_length = sizeof(struct security_info_params)
 	};
 	struct security_info_params *security =
-		(struct security_info_params *)&cmd.host_command_parameters;
+	    (struct security_info_params *)&cmd.host_command_parameters;
 	int err;
 	memset(security, 0, sizeof(*security));
 
@@ -5094,25 +5061,25 @@
 		break;
 	case SEC_LEVEL_1:
 		security->allowed_ciphers = IPW_WEP40_CIPHER |
-			IPW_WEP104_CIPHER;
+		    IPW_WEP104_CIPHER;
 		break;
 	case SEC_LEVEL_2:
 		security->allowed_ciphers = IPW_WEP40_CIPHER |
-			IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
+		    IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
 		break;
 	case SEC_LEVEL_2_CKIP:
 		security->allowed_ciphers = IPW_WEP40_CIPHER |
-			IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
+		    IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
 		break;
 	case SEC_LEVEL_3:
 		security->allowed_ciphers = IPW_WEP40_CIPHER |
-			IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
+		    IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
 		break;
 	}
 
-	IPW_DEBUG_HC(
-		"SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
-		security->auth_mode, security->allowed_ciphers, security_level);
+	IPW_DEBUG_HC
+	    ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
+	     security->auth_mode, security->allowed_ciphers, security_level);
 
 	security->replay_counters_number = 0;
 
@@ -5130,8 +5097,7 @@
 	return err;
 }
 
-static int ipw2100_set_tx_power(struct ipw2100_priv *priv,
-				u32 tx_power)
+static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
 {
 	struct host_command cmd = {
 		.host_command = TX_POWER_INDEX,
@@ -5140,6 +5106,10 @@
 	};
 	int err = 0;
 
+	if (tx_power != IPW_TX_POWER_DEFAULT)
+		tx_power = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
+		    (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
+
 	cmd.host_command_parameters[0] = tx_power;
 
 	if (priv->ieee->iw_mode == IW_MODE_ADHOC)
@@ -5185,7 +5155,6 @@
 	return 0;
 }
 
-
 void ipw2100_queues_initialize(struct ipw2100_priv *priv)
 {
 	ipw2100_tx_initialize(priv);
@@ -5203,13 +5172,12 @@
 int ipw2100_queues_allocate(struct ipw2100_priv *priv)
 {
 	if (ipw2100_tx_allocate(priv) ||
-	    ipw2100_rx_allocate(priv) ||
-	    ipw2100_msg_allocate(priv))
+	    ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
 		goto fail;
 
 	return 0;
 
- fail:
+      fail:
 	ipw2100_tx_free(priv);
 	ipw2100_rx_free(priv);
 	ipw2100_msg_free(priv);
@@ -5235,7 +5203,8 @@
 	if (!batch_mode) {
 		err = ipw2100_disable_adapter(priv);
 		if (err) {
-			printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+			printk(KERN_ERR DRV_NAME
+			       ": %s: Could not disable adapter %d\n",
 			       priv->net_dev->name, err);
 			return err;
 		}
@@ -5262,7 +5231,6 @@
 #define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
 #define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10]
 
-
 /**
  * Set a the wep key
  *
@@ -5287,11 +5255,11 @@
 		.host_command_sequence = 0,
 		.host_command_length = sizeof(struct ipw2100_wep_key),
 	};
-	struct ipw2100_wep_key *wep_key = (void*)cmd.host_command_parameters;
+	struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
 	int err;
 
 	IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
-				 idx, keylen, len);
+		     idx, keylen, len);
 
 	/* NOTE: We don't check cached values in case the firmware was reset
 	 * or some other problem is occuring.  If the user is setting the key,
@@ -5308,22 +5276,23 @@
 	/* Will be optimized out on debug not being configured in */
 	if (keylen == 0)
 		IPW_DEBUG_WEP("%s: Clearing key %d\n",
-				  priv->net_dev->name, wep_key->idx);
+			      priv->net_dev->name, wep_key->idx);
 	else if (keylen == 5)
 		IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
-				  priv->net_dev->name, wep_key->idx, wep_key->len,
-				  WEP_STR_64(wep_key->key));
+			      priv->net_dev->name, wep_key->idx, wep_key->len,
+			      WEP_STR_64(wep_key->key));
 	else
 		IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
-				  "\n",
-				  priv->net_dev->name, wep_key->idx, wep_key->len,
-				  WEP_STR_128(wep_key->key));
+			      "\n",
+			      priv->net_dev->name, wep_key->idx, wep_key->len,
+			      WEP_STR_128(wep_key->key));
 
 	if (!batch_mode) {
 		err = ipw2100_disable_adapter(priv);
 		/* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
 		if (err) {
-			printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+			printk(KERN_ERR DRV_NAME
+			       ": %s: Could not disable adapter %d\n",
 			       priv->net_dev->name, err);
 			return err;
 		}
@@ -5347,7 +5316,7 @@
 		.host_command = WEP_KEY_INDEX,
 		.host_command_sequence = 0,
 		.host_command_length = 4,
-		.host_command_parameters = { idx },
+		.host_command_parameters = {idx},
 	};
 	int err;
 
@@ -5359,7 +5328,8 @@
 	if (!batch_mode) {
 		err = ipw2100_disable_adapter(priv);
 		if (err) {
-			printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+			printk(KERN_ERR DRV_NAME
+			       ": %s: Could not disable adapter %d\n",
 			       priv->net_dev->name, err);
 			return err;
 		}
@@ -5374,9 +5344,7 @@
 	return err;
 }
 
-
-static int ipw2100_configure_security(struct ipw2100_priv *priv,
-				      int batch_mode)
+static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
 {
 	int i, err, auth_mode, sec_level, use_group;
 
@@ -5389,40 +5357,42 @@
 			return err;
 	}
 
-	if (!priv->sec.enabled) {
-		err = ipw2100_set_security_information(
-			priv, IPW_AUTH_OPEN, SEC_LEVEL_0, 0, 1);
+	if (!priv->ieee->sec.enabled) {
+		err =
+		    ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
+						     SEC_LEVEL_0, 0, 1);
 	} else {
 		auth_mode = IPW_AUTH_OPEN;
-		if ((priv->sec.flags & SEC_AUTH_MODE) &&
-		    (priv->sec.auth_mode == WLAN_AUTH_SHARED_KEY))
+		if ((priv->ieee->sec.flags & SEC_AUTH_MODE) &&
+		    (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY))
 			auth_mode = IPW_AUTH_SHARED;
 
 		sec_level = SEC_LEVEL_0;
-		if (priv->sec.flags & SEC_LEVEL)
-			sec_level = priv->sec.level;
+		if (priv->ieee->sec.flags & SEC_LEVEL)
+			sec_level = priv->ieee->sec.level;
 
 		use_group = 0;
-		if (priv->sec.flags & SEC_UNICAST_GROUP)
-			use_group = priv->sec.unicast_uses_group;
+		if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
+			use_group = priv->ieee->sec.unicast_uses_group;
 
-		err = ipw2100_set_security_information(
-			    priv, auth_mode, sec_level, use_group, 1);
+		err =
+		    ipw2100_set_security_information(priv, auth_mode, sec_level,
+						     use_group, 1);
 	}
 
 	if (err)
 		goto exit;
 
-	if (priv->sec.enabled) {
+	if (priv->ieee->sec.enabled) {
 		for (i = 0; i < 4; i++) {
-			if (!(priv->sec.flags & (1 << i))) {
-				memset(priv->sec.keys[i], 0, WEP_KEY_LEN);
-				priv->sec.key_sizes[i] = 0;
+			if (!(priv->ieee->sec.flags & (1 << i))) {
+				memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
+				priv->ieee->sec.key_sizes[i] = 0;
 			} else {
 				err = ipw2100_set_key(priv, i,
-						      priv->sec.keys[i],
-						      priv->sec.key_sizes[i],
-						      1);
+						      priv->ieee->sec.keys[i],
+						      priv->ieee->sec.
+						      key_sizes[i], 1);
 				if (err)
 					goto exit;
 			}
@@ -5433,14 +5403,16 @@
 
 	/* Always enable privacy so the Host can filter WEP packets if
 	 * encrypted data is sent up */
-	err = ipw2100_set_wep_flags(
-		priv, priv->sec.enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
+	err =
+	    ipw2100_set_wep_flags(priv,
+				  priv->ieee->sec.
+				  enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
 	if (err)
 		goto exit;
 
 	priv->status &= ~STATUS_SECURITY_UPDATED;
 
- exit:
+      exit:
 	if (!batch_mode)
 		ipw2100_enable_adapter(priv);
 
@@ -5469,60 +5441,64 @@
 
 	for (i = 0; i < 4; i++) {
 		if (sec->flags & (1 << i)) {
-			priv->sec.key_sizes[i] = sec->key_sizes[i];
+			priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
 			if (sec->key_sizes[i] == 0)
-				priv->sec.flags &= ~(1 << i);
+				priv->ieee->sec.flags &= ~(1 << i);
 			else
-				memcpy(priv->sec.keys[i], sec->keys[i],
+				memcpy(priv->ieee->sec.keys[i], sec->keys[i],
 				       sec->key_sizes[i]);
-			priv->sec.flags |= (1 << i);
-			priv->status |= STATUS_SECURITY_UPDATED;
+			if (sec->level == SEC_LEVEL_1) {
+				priv->ieee->sec.flags |= (1 << i);
+				priv->status |= STATUS_SECURITY_UPDATED;
+			} else
+				priv->ieee->sec.flags &= ~(1 << i);
 		}
 	}
 
 	if ((sec->flags & SEC_ACTIVE_KEY) &&
-	    priv->sec.active_key != sec->active_key) {
+	    priv->ieee->sec.active_key != sec->active_key) {
 		if (sec->active_key <= 3) {
-			priv->sec.active_key = sec->active_key;
-			priv->sec.flags |= SEC_ACTIVE_KEY;
+			priv->ieee->sec.active_key = sec->active_key;
+			priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
 		} else
-			priv->sec.flags &= ~SEC_ACTIVE_KEY;
+			priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
 
 		priv->status |= STATUS_SECURITY_UPDATED;
 	}
 
 	if ((sec->flags & SEC_AUTH_MODE) &&
-	    (priv->sec.auth_mode != sec->auth_mode)) {
-		priv->sec.auth_mode = sec->auth_mode;
-		priv->sec.flags |= SEC_AUTH_MODE;
+	    (priv->ieee->sec.auth_mode != sec->auth_mode)) {
+		priv->ieee->sec.auth_mode = sec->auth_mode;
+		priv->ieee->sec.flags |= SEC_AUTH_MODE;
 		priv->status |= STATUS_SECURITY_UPDATED;
 	}
 
-	if (sec->flags & SEC_ENABLED &&
-	    priv->sec.enabled != sec->enabled) {
-		priv->sec.flags |= SEC_ENABLED;
-		priv->sec.enabled = sec->enabled;
+	if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
+		priv->ieee->sec.flags |= SEC_ENABLED;
+		priv->ieee->sec.enabled = sec->enabled;
 		priv->status |= STATUS_SECURITY_UPDATED;
 		force_update = 1;
 	}
 
-	if (sec->flags & SEC_LEVEL &&
-	    priv->sec.level != sec->level) {
-		priv->sec.level = sec->level;
-		priv->sec.flags |= SEC_LEVEL;
+	if (sec->flags & SEC_ENCRYPT)
+		priv->ieee->sec.encrypt = sec->encrypt;
+
+	if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
+		priv->ieee->sec.level = sec->level;
+		priv->ieee->sec.flags |= SEC_LEVEL;
 		priv->status |= STATUS_SECURITY_UPDATED;
 	}
 
 	IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
-			  priv->sec.flags & (1<<8) ? '1' : '0',
-			  priv->sec.flags & (1<<7) ? '1' : '0',
-			  priv->sec.flags & (1<<6) ? '1' : '0',
-			  priv->sec.flags & (1<<5) ? '1' : '0',
-			  priv->sec.flags & (1<<4) ? '1' : '0',
-			  priv->sec.flags & (1<<3) ? '1' : '0',
-			  priv->sec.flags & (1<<2) ? '1' : '0',
-			  priv->sec.flags & (1<<1) ? '1' : '0',
-			  priv->sec.flags & (1<<0) ? '1' : '0');
+		      priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
+		      priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
+		      priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
+		      priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
+		      priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
+		      priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
+		      priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
+		      priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
+		      priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
 
 /* As a temporary work around to enable WPA until we figure out why
  * wpa_supplicant toggles the security capability of the driver, which
@@ -5531,7 +5507,7 @@
  *	if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
 	if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
 		ipw2100_configure_security(priv, 0);
-done:
+      done:
 	up(&priv->action_sem);
 }
 
@@ -5556,7 +5532,7 @@
 
 		return 0;
 	}
-#endif /* CONFIG_IPW2100_MONITOR */
+#endif				/* CONFIG_IPW2100_MONITOR */
 
 	err = ipw2100_read_mac_address(priv);
 	if (err)
@@ -5576,7 +5552,7 @@
 			return err;
 	}
 
-	err  = ipw2100_system_config(priv, batch_mode);
+	err = ipw2100_system_config(priv, batch_mode);
 	if (err)
 		return err;
 
@@ -5614,8 +5590,10 @@
 		return err;
 
 	if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
-		err = ipw2100_set_ibss_beacon_interval(
-			priv, priv->beacon_interval, batch_mode);
+		err =
+		    ipw2100_set_ibss_beacon_interval(priv,
+						     priv->beacon_interval,
+						     batch_mode);
 		if (err)
 			return err;
 
@@ -5625,18 +5603,17 @@
 	}
 
 	/*
-	  err = ipw2100_set_fragmentation_threshold(
-	  priv, priv->frag_threshold, batch_mode);
-	  if (err)
-	  return err;
-	*/
+	   err = ipw2100_set_fragmentation_threshold(
+	   priv, priv->frag_threshold, batch_mode);
+	   if (err)
+	   return err;
+	 */
 
 	IPW_DEBUG_INFO("exit\n");
 
 	return 0;
 }
 
-
 /*************************************************************************
  *
  * EXTERNALLY CALLED METHODS
@@ -5669,7 +5646,7 @@
 	ipw2100_reset_adapter(priv);
 	return 0;
 
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -5708,7 +5685,7 @@
 	/* Flush the TX queue ... */
 	while (!list_empty(&priv->tx_pend_list)) {
 		element = priv->tx_pend_list.next;
-                packet = list_entry(element, struct ipw2100_tx_packet, list);
+		packet = list_entry(element, struct ipw2100_tx_packet, list);
 
 		list_del(element);
 		DEC_STAT(&priv->tx_pend_stat);
@@ -5726,8 +5703,6 @@
 	return 0;
 }
 
-
-
 /*
  * TODO:  Fix this function... its just wrong
  */
@@ -5747,7 +5722,6 @@
 	schedule_reset(priv);
 }
 
-
 /*
  * TODO: reimplement it so that it reads statistics
  *       from the adapter using ordinal tables
@@ -5761,11 +5735,10 @@
 	return &priv->ieee->stats;
 }
 
-/* Support for wpa_supplicant. Will be replaced with WEXT once
- * they get WPA support. */
-#ifdef CONFIG_IEEE80211_WPA
+#if WIRELESS_EXT < 18
+/* Support for wpa_supplicant before WE-18, deprecated. */
 
-/* following definitions must match definitions in driver_ipw2100.c */
+/* following definitions must match definitions in driver_ipw.c */
 
 #define IPW2100_IOCTL_WPA_SUPPLICANT		SIOCIWFIRSTPRIV+30
 
@@ -5796,25 +5769,26 @@
 struct ipw2100_param {
 	u32 cmd;
 	u8 sta_addr[ETH_ALEN];
-        union {
+	union {
 		struct {
 			u8 name;
 			u32 value;
 		} wpa_param;
 		struct {
 			u32 len;
-			u8 *data;
+			u8 reserved[32];
+			u8 data[0];
 		} wpa_ie;
-	        struct{
-			int command;
-    			int reason_code;
+		struct {
+			u32 command;
+			u32 reason_code;
 		} mlme;
 		struct {
 			u8 alg[IPW2100_CRYPT_ALG_NAME_LEN];
 			u8 set_tx;
 			u32 err;
 			u8 idx;
-			u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+			u8 seq[8];	/* sequence counter (set: RX, get: TX) */
 			u16 key_len;
 			u8 key[0];
 		} crypt;
@@ -5822,38 +5796,24 @@
 	} u;
 };
 
-/* end of driver_ipw2100.c code */
+/* end of driver_ipw.c code */
+#endif				/* WIRELESS_EXT < 18 */
 
-static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value){
-
-	struct ieee80211_device *ieee = priv->ieee;
-	struct ieee80211_security sec = {
-		.flags = SEC_LEVEL | SEC_ENABLED,
-	};
-	int ret = 0;
-
-	ieee->wpa_enabled = value;
-
-	if (value){
-		sec.level = SEC_LEVEL_3;
-		sec.enabled = 1;
-	} else {
-		sec.level = SEC_LEVEL_0;
-		sec.enabled = 0;
-	}
-
-	if (ieee->set_security)
-		ieee->set_security(ieee->dev, &sec);
-	else
-		ret = -EOPNOTSUPP;
-
-	return ret;
+static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
+{
+	/* This is called when wpa_supplicant loads and closes the driver
+	 * interface. */
+	priv->ieee->wpa_enabled = value;
+	return 0;
 }
 
-#define AUTH_ALG_OPEN_SYSTEM			0x1
-#define AUTH_ALG_SHARED_KEY			0x2
+#if WIRELESS_EXT < 18
+#define IW_AUTH_ALG_OPEN_SYSTEM			0x1
+#define IW_AUTH_ALG_SHARED_KEY			0x2
+#endif
 
-static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){
+static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
+{
 
 	struct ieee80211_device *ieee = priv->ieee;
 	struct ieee80211_security sec = {
@@ -5861,13 +5821,14 @@
 	};
 	int ret = 0;
 
-	if (value & AUTH_ALG_SHARED_KEY){
+	if (value & IW_AUTH_ALG_SHARED_KEY) {
 		sec.auth_mode = WLAN_AUTH_SHARED_KEY;
 		ieee->open_wep = 0;
-	} else {
+	} else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
 		sec.auth_mode = WLAN_AUTH_OPEN;
 		ieee->open_wep = 1;
-	}
+	} else
+		return -EINVAL;
 
 	if (ieee->set_security)
 		ieee->set_security(ieee->dev, &sec);
@@ -5877,72 +5838,9 @@
 	return ret;
 }
 
-
-static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value){
-
-	struct ipw2100_priv *priv = ieee80211_priv(dev);
-	int ret=0;
-
-	switch(name){
-		case IPW2100_PARAM_WPA_ENABLED:
-			ret = ipw2100_wpa_enable(priv, value);
-			break;
-
-		case IPW2100_PARAM_TKIP_COUNTERMEASURES:
-			priv->ieee->tkip_countermeasures=value;
-			break;
-
-		case IPW2100_PARAM_DROP_UNENCRYPTED:
-			priv->ieee->drop_unencrypted=value;
-			break;
-
-		case IPW2100_PARAM_PRIVACY_INVOKED:
-			priv->ieee->privacy_invoked=value;
-			break;
-
-		case IPW2100_PARAM_AUTH_ALGS:
-			ret = ipw2100_wpa_set_auth_algs(priv, value);
-			break;
-
-		case IPW2100_PARAM_IEEE_802_1X:
-			priv->ieee->ieee802_1x=value;
-			break;
-
-		default:
-			printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n",
-					    dev->name, name);
-			ret = -EOPNOTSUPP;
-	}
-
-	return ret;
-}
-
-static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason){
-
-	struct ipw2100_priv *priv = ieee80211_priv(dev);
-	int ret=0;
-
-	switch(command){
-		case IPW2100_MLME_STA_DEAUTH:
-			// silently ignore
-			break;
-
-		case IPW2100_MLME_STA_DISASSOC:
-			ipw2100_disassociate_bssid(priv);
-			break;
-
-		default:
-			printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n",
-					    dev->name, command);
-			ret = -EOPNOTSUPP;
-	}
-
-	return ret;
-}
-
-
 void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
-			     char *wpa_ie, int wpa_ie_len){
+			     char *wpa_ie, int wpa_ie_len)
+{
 
 	struct ipw2100_wpa_assoc_frame frame;
 
@@ -5957,23 +5855,118 @@
 	ipw2100_set_wpa_ie(priv, &frame, 0);
 }
 
+#if WIRELESS_EXT < 18
+static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value)
+{
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	struct ieee80211_crypt_data *crypt;
+	unsigned long flags;
+	int ret = 0;
+
+	switch (name) {
+	case IPW2100_PARAM_WPA_ENABLED:
+		ret = ipw2100_wpa_enable(priv, value);
+		break;
+
+	case IPW2100_PARAM_TKIP_COUNTERMEASURES:
+		crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+		if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
+			break;
+
+		flags = crypt->ops->get_flags(crypt->priv);
+
+		if (value)
+			flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+		else
+			flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+
+		crypt->ops->set_flags(flags, crypt->priv);
+
+		break;
+
+	case IPW2100_PARAM_DROP_UNENCRYPTED:{
+			/* See IW_AUTH_DROP_UNENCRYPTED handling for details */
+			struct ieee80211_security sec = {
+				.flags = SEC_ENABLED,
+				.enabled = value,
+			};
+			priv->ieee->drop_unencrypted = value;
+			/* We only change SEC_LEVEL for open mode. Others
+			 * are set by ipw_wpa_set_encryption.
+			 */
+			if (!value) {
+				sec.flags |= SEC_LEVEL;
+				sec.level = SEC_LEVEL_0;
+			} else {
+				sec.flags |= SEC_LEVEL;
+				sec.level = SEC_LEVEL_1;
+			}
+			if (priv->ieee->set_security)
+				priv->ieee->set_security(priv->ieee->dev, &sec);
+			break;
+		}
+
+	case IPW2100_PARAM_PRIVACY_INVOKED:
+		priv->ieee->privacy_invoked = value;
+		break;
+
+	case IPW2100_PARAM_AUTH_ALGS:
+		ret = ipw2100_wpa_set_auth_algs(priv, value);
+		break;
+
+	case IPW2100_PARAM_IEEE_802_1X:
+		priv->ieee->ieee802_1x = value;
+		break;
+
+	default:
+		printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n",
+		       dev->name, name);
+		ret = -EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
+static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason)
+{
+
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	int ret = 0;
+
+	switch (command) {
+	case IPW2100_MLME_STA_DEAUTH:
+		// silently ignore
+		break;
+
+	case IPW2100_MLME_STA_DISASSOC:
+		ipw2100_disassociate_bssid(priv);
+		break;
+
+	default:
+		printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n",
+		       dev->name, command);
+		ret = -EOPNOTSUPP;
+	}
+
+	return ret;
+}
 
 static int ipw2100_wpa_set_wpa_ie(struct net_device *dev,
-				struct ipw2100_param *param, int plen){
+				  struct ipw2100_param *param, int plen)
+{
 
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	struct ieee80211_device *ieee = priv->ieee;
 	u8 *buf;
 
-	if (! ieee->wpa_enabled)
-	    return -EOPNOTSUPP;
+	if (!ieee->wpa_enabled)
+		return -EOPNOTSUPP;
 
 	if (param->u.wpa_ie.len > MAX_WPA_IE_LEN ||
-	   (param->u.wpa_ie.len &&
-		param->u.wpa_ie.data==NULL))
+	    (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL))
 		return -EINVAL;
 
-	if (param->u.wpa_ie.len){
+	if (param->u.wpa_ie.len) {
 		buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL);
 		if (buf == NULL)
 			return -ENOMEM;
@@ -5998,8 +5991,9 @@
 /* implementation borrowed from hostap driver */
 
 static int ipw2100_wpa_set_encryption(struct net_device *dev,
-				struct ipw2100_param *param, int param_len){
-
+				      struct ipw2100_param *param,
+				      int param_len)
+{
 	int ret = 0;
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	struct ieee80211_device *ieee = priv->ieee;
@@ -6014,9 +6008,10 @@
 	param->u.crypt.alg[IPW2100_CRYPT_ALG_NAME_LEN - 1] = '\0';
 
 	if (param_len !=
-	    (int) ((char *) param->u.crypt.key - (char *) param) +
-	    param->u.crypt.key_len){
-		IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, param->u.crypt.key_len);
+	    (int)((char *)param->u.crypt.key - (char *)param) +
+	    param->u.crypt.key_len) {
+		IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len,
+			       param->u.crypt.key_len);
 		return -EINVAL;
 	}
 	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
@@ -6029,17 +6024,19 @@
 		return -EINVAL;
 	}
 
+	sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
 	if (strcmp(param->u.crypt.alg, "none") == 0) {
-		if (crypt){
+		if (crypt) {
 			sec.enabled = 0;
+			sec.encrypt = 0;
 			sec.level = SEC_LEVEL_0;
-			sec.flags |= SEC_ENABLED | SEC_LEVEL;
+			sec.flags |= SEC_LEVEL;
 			ieee80211_crypt_delayed_deinit(ieee, crypt);
 		}
 		goto done;
 	}
 	sec.enabled = 1;
-	sec.flags |= SEC_ENABLED;
+	sec.encrypt = 1;
 
 	ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
 	if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
@@ -6054,7 +6051,7 @@
 	}
 	if (ops == NULL) {
 		IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n",
-		       dev->name, param->u.crypt.alg);
+			       dev->name, param->u.crypt.alg);
 		param->u.crypt.err = IPW2100_CRYPT_ERR_UNKNOWN_ALG;
 		ret = -EINVAL;
 		goto done;
@@ -6065,21 +6062,20 @@
 
 		ieee80211_crypt_delayed_deinit(ieee, crypt);
 
-		new_crypt = (struct ieee80211_crypt_data *)
-			kmalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL);
+		new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL);
 		if (new_crypt == NULL) {
 			ret = -ENOMEM;
 			goto done;
 		}
-		memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
 		new_crypt->ops = ops;
 		if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
-			new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
+			new_crypt->priv =
+			    new_crypt->ops->init(param->u.crypt.idx);
 
 		if (new_crypt->priv == NULL) {
 			kfree(new_crypt);
 			param->u.crypt.err =
-				IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED;
+			    IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED;
 			ret = -EINVAL;
 			goto done;
 		}
@@ -6091,24 +6087,25 @@
 	    (*crypt)->ops->set_key(param->u.crypt.key,
 				   param->u.crypt.key_len, param->u.crypt.seq,
 				   (*crypt)->priv) < 0) {
-		IPW_DEBUG_INFO("%s: key setting failed\n",
-		       dev->name);
+		IPW_DEBUG_INFO("%s: key setting failed\n", dev->name);
 		param->u.crypt.err = IPW2100_CRYPT_ERR_KEY_SET_FAILED;
 		ret = -EINVAL;
 		goto done;
 	}
 
-	if (param->u.crypt.set_tx){
+	if (param->u.crypt.set_tx) {
 		ieee->tx_keyidx = param->u.crypt.idx;
 		sec.active_key = param->u.crypt.idx;
 		sec.flags |= SEC_ACTIVE_KEY;
 	}
 
-	if (ops->name != NULL){
+	if (ops->name != NULL) {
 
 		if (strcmp(ops->name, "WEP") == 0) {
-			memcpy(sec.keys[param->u.crypt.idx], param->u.crypt.key, param->u.crypt.key_len);
-			sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
+			memcpy(sec.keys[param->u.crypt.idx],
+			       param->u.crypt.key, param->u.crypt.key_len);
+			sec.key_sizes[param->u.crypt.idx] =
+			    param->u.crypt.key_len;
 			sec.flags |= (1 << param->u.crypt.idx);
 			sec.flags |= SEC_LEVEL;
 			sec.level = SEC_LEVEL_1;
@@ -6120,7 +6117,7 @@
 			sec.level = SEC_LEVEL_3;
 		}
 	}
- done:
+      done:
 	if (ieee->set_security)
 		ieee->set_security(ieee->dev, &sec);
 
@@ -6131,8 +6128,7 @@
 	 * the callbacks structures used to initialize the 802.11 stack. */
 	if (ieee->reset_on_keychange &&
 	    ieee->iw_mode != IW_MODE_INFRA &&
-	    ieee->reset_port &&
-	    ieee->reset_port(dev)) {
+	    ieee->reset_port && ieee->reset_port(dev)) {
 		IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name);
 		param->u.crypt.err = IPW2100_CRYPT_ERR_CARD_CONF_FAILED;
 		return -EINVAL;
@@ -6141,11 +6137,11 @@
 	return ret;
 }
 
-
-static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){
+static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p)
+{
 
 	struct ipw2100_param *param;
-	int ret=0;
+	int ret = 0;
 
 	IPW_DEBUG_IOCTL("wpa_supplicant: len=%d\n", p->length);
 
@@ -6156,12 +6152,12 @@
 	if (param == NULL)
 		return -ENOMEM;
 
-	if (copy_from_user(param, p->pointer, p->length)){
+	if (copy_from_user(param, p->pointer, p->length)) {
 		kfree(param);
 		return -EFAULT;
 	}
 
-	switch (param->cmd){
+	switch (param->cmd) {
 
 	case IPW2100_CMD_SET_WPA_PARAM:
 		ret = ipw2100_wpa_set_param(dev, param->u.wpa_param.name,
@@ -6182,8 +6178,9 @@
 		break;
 
 	default:
-		printk(KERN_ERR DRV_NAME ": %s: Unknown WPA supplicant request: %d\n",
-				dev->name, param->cmd);
+		printk(KERN_ERR DRV_NAME
+		       ": %s: Unknown WPA supplicant request: %d\n", dev->name,
+		       param->cmd);
 		ret = -EOPNOTSUPP;
 
 	}
@@ -6194,27 +6191,23 @@
 	kfree(param);
 	return ret;
 }
-#endif /* CONFIG_IEEE80211_WPA */
 
 static int ipw2100_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-#ifdef CONFIG_IEEE80211_WPA
-	struct iwreq *wrq = (struct iwreq *) rq;
-	int ret=-1;
-	switch (cmd){
-	    case IPW2100_IOCTL_WPA_SUPPLICANT:
+	struct iwreq *wrq = (struct iwreq *)rq;
+	int ret = -1;
+	switch (cmd) {
+	case IPW2100_IOCTL_WPA_SUPPLICANT:
 		ret = ipw2100_wpa_supplicant(dev, &wrq->u.data);
 		return ret;
 
-	    default:
+	default:
 		return -EOPNOTSUPP;
 	}
 
-#endif /* CONFIG_IEEE80211_WPA */
-
 	return -EOPNOTSUPP;
 }
-
+#endif				/* WIRELESS_EXT < 18 */
 
 static void ipw_ethtool_get_drvinfo(struct net_device *dev,
 				    struct ethtool_drvinfo *info)
@@ -6236,14 +6229,13 @@
 
 static u32 ipw2100_ethtool_get_link(struct net_device *dev)
 {
-    struct ipw2100_priv *priv = ieee80211_priv(dev);
-    return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
 }
 
-
 static struct ethtool_ops ipw2100_ethtool_ops = {
-    .get_link        = ipw2100_ethtool_get_link,
-    .get_drvinfo     = ipw_ethtool_get_drvinfo,
+	.get_link = ipw2100_ethtool_get_link,
+	.get_drvinfo = ipw_ethtool_get_drvinfo,
 };
 
 static void ipw2100_hang_check(void *adapter)
@@ -6288,7 +6280,6 @@
 	spin_unlock_irqrestore(&priv->low_lock, flags);
 }
 
-
 static void ipw2100_rf_kill(void *adapter)
 {
 	struct ipw2100_priv *priv = adapter;
@@ -6313,7 +6304,7 @@
 		IPW_DEBUG_RF_KILL("HW RF Kill deactivated.  SW RF Kill still "
 				  "enabled\n");
 
- exit_unlock:
+      exit_unlock:
 	spin_unlock_irqrestore(&priv->low_lock, flags);
 }
 
@@ -6321,11 +6312,10 @@
 
 /* Look into using netdev destructor to shutdown ieee80211? */
 
-static struct net_device *ipw2100_alloc_device(
-	struct pci_dev *pci_dev,
-	void __iomem *base_addr,
-	unsigned long mem_start,
-	unsigned long mem_len)
+static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
+					       void __iomem * base_addr,
+					       unsigned long mem_start,
+					       unsigned long mem_len)
 {
 	struct ipw2100_priv *priv;
 	struct net_device *dev;
@@ -6341,17 +6331,22 @@
 	priv->ieee->hard_start_xmit = ipw2100_tx;
 	priv->ieee->set_security = shim__set_security;
 
+	priv->ieee->perfect_rssi = -20;
+	priv->ieee->worst_rssi = -85;
+
 	dev->open = ipw2100_open;
 	dev->stop = ipw2100_close;
 	dev->init = ipw2100_net_init;
+#if WIRELESS_EXT < 18
 	dev->do_ioctl = ipw2100_ioctl;
+#endif
 	dev->get_stats = ipw2100_stats;
 	dev->ethtool_ops = &ipw2100_ethtool_ops;
 	dev->tx_timeout = ipw2100_tx_timeout;
 	dev->wireless_handlers = &ipw2100_wx_handler_def;
 	dev->get_wireless_stats = ipw2100_wx_wireless_stats;
 	dev->set_mac_address = ipw2100_set_address;
-	dev->watchdog_timeo = 3*HZ;
+	dev->watchdog_timeo = 3 * HZ;
 	dev->irq = 0;
 
 	dev->base_addr = (unsigned long)base_addr;
@@ -6364,22 +6359,19 @@
 	 * ends up causing problems.  So, we just handle
 	 * the WX extensions through the ipw2100_ioctl interface */
 
-
 	/* memset() puts everything to 0, so we only have explicitely set
 	 * those values that need to be something else */
 
 	/* If power management is turned on, default to AUTO mode */
 	priv->power_mode = IPW_POWER_AUTO;
 
-
-
-#ifdef CONFIG_IEEE80211_WPA
+#ifdef CONFIG_IPW2100_MONITOR
+	priv->config |= CFG_CRC_CHECK;
+#endif
 	priv->ieee->wpa_enabled = 0;
-	priv->ieee->tkip_countermeasures = 0;
 	priv->ieee->drop_unencrypted = 0;
 	priv->ieee->privacy_invoked = 0;
 	priv->ieee->ieee802_1x = 1;
-#endif /* CONFIG_IEEE80211_WPA */
 
 	/* Set module parameters */
 	switch (mode) {
@@ -6401,8 +6393,7 @@
 		priv->status |= STATUS_RF_KILL_SW;
 
 	if (channel != 0 &&
-	    ((channel >= REG_MIN_CHANNEL) &&
-	     (channel <= REG_MAX_CHANNEL))) {
+	    ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
 		priv->config |= CFG_STATIC_CHANNEL;
 		priv->channel = channel;
 	}
@@ -6441,12 +6432,8 @@
 	INIT_LIST_HEAD(&priv->fw_pend_list);
 	INIT_STAT(&priv->fw_pend_stat);
 
-
-#ifdef CONFIG_SOFTWARE_SUSPEND2
-	priv->workqueue = create_workqueue(DRV_NAME, 0);
-#else
 	priv->workqueue = create_workqueue(DRV_NAME);
-#endif
+
 	INIT_WORK(&priv->reset_work,
 		  (void (*)(void *))ipw2100_reset_adapter, priv);
 	INIT_WORK(&priv->security_work,
@@ -6535,7 +6522,7 @@
 		return err;
 	}
 
-        /* We disable the RETRY_TIMEOUT register (0x41) to keep
+	/* We disable the RETRY_TIMEOUT register (0x41) to keep
 	 * PCI Tx retries from interfering with C3 CPU state */
 	pci_read_config_dword(pci_dev, 0x40, &val);
 	if ((val & 0x0000ff00) != 0)
@@ -6566,12 +6553,10 @@
 	ipw2100_queues_initialize(priv);
 
 	err = request_irq(pci_dev->irq,
-			  ipw2100_interrupt, SA_SHIRQ,
-			  dev->name, priv);
+			  ipw2100_interrupt, SA_SHIRQ, dev->name, priv);
 	if (err) {
 		printk(KERN_WARNING DRV_NAME
-		       "Error calling request_irq: %d.\n",
-		       pci_dev->irq);
+		       "Error calling request_irq: %d.\n", pci_dev->irq);
 		goto fail;
 	}
 	dev->irq = pci_dev->irq;
@@ -6606,7 +6591,6 @@
 
 	/* perform this after register_netdev so that dev->name is set */
 	sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
-	netif_carrier_off(dev);
 
 	/* If the RF Kill switch is disabled, go ahead and complete the
 	 * startup sequence */
@@ -6634,10 +6618,10 @@
 
 	return 0;
 
- fail_unlock:
+      fail_unlock:
 	up(&priv->action_sem);
 
- fail:
+      fail:
 	if (dev) {
 		if (registered)
 			unregister_netdev(dev);
@@ -6653,7 +6637,8 @@
 
 		/* These are safe to call even if they weren't allocated */
 		ipw2100_queues_free(priv);
-		sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+		sysfs_remove_group(&pci_dev->dev.kobj,
+				   &ipw2100_attribute_group);
 
 		free_ieee80211(dev);
 		pci_set_drvdata(pci_dev, NULL);
@@ -6679,7 +6664,8 @@
 		priv->status &= ~STATUS_INITIALIZED;
 
 		dev = priv->net_dev;
-		sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+		sysfs_remove_group(&pci_dev->dev.kobj,
+				   &ipw2100_attribute_group);
 
 #ifdef CONFIG_PM
 		if (ipw2100_firmware.version)
@@ -6721,19 +6707,13 @@
 	IPW_DEBUG_INFO("exit\n");
 }
 
-
 #ifdef CONFIG_PM
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
-static int ipw2100_suspend(struct pci_dev *pci_dev, u32 state)
-#else
 static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
-#endif
 {
 	struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
 	struct net_device *dev = priv->net_dev;
 
-	IPW_DEBUG_INFO("%s: Going into suspend...\n",
-	       dev->name);
+	IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
 
 	down(&priv->action_sem);
 	if (priv->status & STATUS_INITIALIZED) {
@@ -6745,7 +6725,7 @@
 	netif_device_detach(dev);
 
 	pci_save_state(pci_dev);
-	pci_disable_device (pci_dev);
+	pci_disable_device(pci_dev);
 	pci_set_power_state(pci_dev, PCI_D3hot);
 
 	up(&priv->action_sem);
@@ -6764,8 +6744,7 @@
 
 	down(&priv->action_sem);
 
-	IPW_DEBUG_INFO("%s: Coming out of suspend...\n",
-	       dev->name);
+	IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
 
 	pci_set_power_state(pci_dev, PCI_D0);
 	pci_enable_device(pci_dev);
@@ -6785,9 +6764,9 @@
 	 * the queue of needed */
 	netif_device_attach(dev);
 
-        /* Bring the device back up */
-        if (!(priv->status & STATUS_RF_KILL_SW))
-                ipw2100_up(priv, 0);
+	/* Bring the device back up */
+	if (!(priv->status & STATUS_RF_KILL_SW))
+		ipw2100_up(priv, 0);
 
 	up(&priv->action_sem);
 
@@ -6795,56 +6774,55 @@
 }
 #endif
 
-
 #define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
 
 static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
-	IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
-	IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
-	IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
-	IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
-	IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
-	IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
-	IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
-	IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
-	IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
+	IPW2100_DEV_ID(0x2520),	/* IN 2100A mPCI 3A */
+	IPW2100_DEV_ID(0x2521),	/* IN 2100A mPCI 3B */
+	IPW2100_DEV_ID(0x2524),	/* IN 2100A mPCI 3B */
+	IPW2100_DEV_ID(0x2525),	/* IN 2100A mPCI 3B */
+	IPW2100_DEV_ID(0x2526),	/* IN 2100A mPCI Gen A3 */
+	IPW2100_DEV_ID(0x2522),	/* IN 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2523),	/* IN 2100 mPCI 3A */
+	IPW2100_DEV_ID(0x2527),	/* IN 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2528),	/* IN 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2529),	/* IN 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x252B),	/* IN 2100 mPCI 3A */
+	IPW2100_DEV_ID(0x252C),	/* IN 2100 mPCI 3A */
+	IPW2100_DEV_ID(0x252D),	/* IN 2100 mPCI 3A */
 
-	IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
-	IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2550),	/* IB 2100A mPCI 3B */
+	IPW2100_DEV_ID(0x2551),	/* IB 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2553),	/* IB 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2554),	/* IB 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2555),	/* IB 2100 mPCI 3B */
 
-	IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
-	IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
-	IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
-	IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
-	IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
-	IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
-	IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
+	IPW2100_DEV_ID(0x2560),	/* DE 2100A mPCI 3A */
+	IPW2100_DEV_ID(0x2562),	/* DE 2100A mPCI 3A */
+	IPW2100_DEV_ID(0x2563),	/* DE 2100A mPCI 3A */
+	IPW2100_DEV_ID(0x2561),	/* DE 2100 mPCI 3A */
+	IPW2100_DEV_ID(0x2565),	/* DE 2100 mPCI 3A */
+	IPW2100_DEV_ID(0x2566),	/* DE 2100 mPCI 3A */
+	IPW2100_DEV_ID(0x2567),	/* DE 2100 mPCI 3A */
 
-	IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2570),	/* GA 2100 mPCI 3B */
 
-	IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
-	IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
-	IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
-	IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2580),	/* TO 2100A mPCI 3B */
+	IPW2100_DEV_ID(0x2582),	/* TO 2100A mPCI 3B */
+	IPW2100_DEV_ID(0x2583),	/* TO 2100A mPCI 3B */
+	IPW2100_DEV_ID(0x2581),	/* TO 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2585),	/* TO 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2586),	/* TO 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2587),	/* TO 2100 mPCI 3B */
 
-	IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
-	IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
-	IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
-	IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2590),	/* SO 2100A mPCI 3B */
+	IPW2100_DEV_ID(0x2592),	/* SO 2100A mPCI 3B */
+	IPW2100_DEV_ID(0x2591),	/* SO 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2593),	/* SO 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2596),	/* SO 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x2598),	/* SO 2100 mPCI 3B */
 
-	IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
+	IPW2100_DEV_ID(0x25A0),	/* HP 2100 mPCI 3B */
 	{0,},
 };
 
@@ -6861,7 +6839,6 @@
 #endif
 };
 
-
 /**
  * Initialize the ipw2100 driver/module
  *
@@ -6878,10 +6855,6 @@
 	printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
 	printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
 
-#ifdef CONFIG_IEEE80211_NOWEP
-	IPW_DEBUG_INFO(DRV_NAME ": Compiled with WEP disabled.\n");
-#endif
-
 	ret = pci_module_init(&ipw2100_pci_driver);
 
 #ifdef CONFIG_IPW_DEBUG
@@ -6893,7 +6866,6 @@
 	return ret;
 }
 
-
 /**
  * Cleanup ipw2100 driver registration
  */
@@ -6949,7 +6921,6 @@
 	return 0;
 }
 
-
 static int ipw2100_wx_set_freq(struct net_device *dev,
 			       struct iw_request_info *info,
 			       union iwreq_data *wrqu, char *extra)
@@ -6969,8 +6940,7 @@
 
 	/* if setting by freq convert to channel */
 	if (fwrq->e == 1) {
-		if ((fwrq->m >= (int) 2.412e8 &&
-		     fwrq->m <= (int) 2.487e8)) {
+		if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
 			int f = fwrq->m / 100000;
 			int c = 0;
 
@@ -6984,19 +6954,19 @@
 		}
 	}
 
-	if (fwrq->e > 0 || fwrq->m > 1000)
-		return -EOPNOTSUPP;
-	else { /* Set the channel */
+	if (fwrq->e > 0 || fwrq->m > 1000) {
+		err = -EOPNOTSUPP;
+		goto done;
+	} else {		/* Set the channel */
 		IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
 		err = ipw2100_set_channel(priv, fwrq->m, 0);
 	}
 
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
 
-
 static int ipw2100_wx_get_freq(struct net_device *dev,
 			       struct iw_request_info *info,
 			       union iwreq_data *wrqu, char *extra)
@@ -7045,7 +7015,7 @@
 	case IW_MODE_MONITOR:
 		err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
 		break;
-#endif /* CONFIG_IPW2100_MONITOR */
+#endif				/* CONFIG_IPW2100_MONITOR */
 	case IW_MODE_ADHOC:
 		err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
 		break;
@@ -7056,9 +7026,9 @@
 		break;
 	}
 
-done:
+      done:
 	up(&priv->action_sem);
- 	return err;
+	return err;
 }
 
 static int ipw2100_wx_get_mode(struct net_device *dev,
@@ -7077,7 +7047,6 @@
 	return 0;
 }
 
-
 #define POWER_MODES 5
 
 /* Values are in microsecond */
@@ -7124,19 +7093,19 @@
 	/* ~5 Mb/s real (802.11b) */
 	range->throughput = 5 * 1000 * 1000;
 
-//	range->sensitivity;	/* signal level threshold range */
+//      range->sensitivity;     /* signal level threshold range */
 
 	range->max_qual.qual = 100;
 	/* TODO: Find real max RSSI and stick here */
 	range->max_qual.level = 0;
 	range->max_qual.noise = 0;
-	range->max_qual.updated = 7; /* Updated all three */
+	range->max_qual.updated = 7;	/* Updated all three */
 
-	range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
+	range->avg_qual.qual = 70;	/* > 8% missed beacons is 'bad' */
 	/* TODO: Find real 'good' to 'bad' threshol value for RSSI */
 	range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
 	range->avg_qual.noise = 0;
-	range->avg_qual.updated = 7; /* Updated all three */
+	range->avg_qual.updated = 7;	/* Updated all three */
 
 	range->num_bitrates = RATE_COUNT;
 
@@ -7150,61 +7119,62 @@
 	range->max_frag = MAX_FRAG_THRESHOLD;
 
 	range->min_pmp = period_duration[0];	/* Minimal PM period */
-	range->max_pmp = period_duration[POWER_MODES-1];/* Maximal PM period */
-	range->min_pmt = timeout_duration[POWER_MODES-1];	/* Minimal PM timeout */
-	range->max_pmt = timeout_duration[0];/* Maximal PM timeout */
+	range->max_pmp = period_duration[POWER_MODES - 1];	/* Maximal PM period */
+	range->min_pmt = timeout_duration[POWER_MODES - 1];	/* Minimal PM timeout */
+	range->max_pmt = timeout_duration[0];	/* Maximal PM timeout */
 
-        /* How to decode max/min PM period */
+	/* How to decode max/min PM period */
 	range->pmp_flags = IW_POWER_PERIOD;
-        /* How to decode max/min PM period */
+	/* How to decode max/min PM period */
 	range->pmt_flags = IW_POWER_TIMEOUT;
 	/* What PM options are supported */
 	range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
 
 	range->encoding_size[0] = 5;
-	range->encoding_size[1] = 13;           /* Different token sizes */
-	range->num_encoding_sizes = 2;		/* Number of entry in the list */
-	range->max_encoding_tokens = WEP_KEYS;  /* Max number of tokens */
-//	range->encoding_login_index;		/* token index for login token */
+	range->encoding_size[1] = 13;	/* Different token sizes */
+	range->num_encoding_sizes = 2;	/* Number of entry in the list */
+	range->max_encoding_tokens = WEP_KEYS;	/* Max number of tokens */
+//      range->encoding_login_index;            /* token index for login token */
 
 	if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
 		range->txpower_capa = IW_TXPOW_DBM;
 		range->num_txpower = IW_MAX_TXPOWER;
-		for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16); i < IW_MAX_TXPOWER;
-		     i++, level -= ((IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM) * 16) /
-			     (IW_MAX_TXPOWER - 1))
+		for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
+		     i < IW_MAX_TXPOWER;
+		     i++, level -=
+		     ((IPW_TX_POWER_MAX_DBM -
+		       IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
 			range->txpower[i] = level / 16;
 	} else {
 		range->txpower_capa = 0;
 		range->num_txpower = 0;
 	}
 
-
 	/* Set the Wireless Extension versions */
 	range->we_version_compiled = WIRELESS_EXT;
 	range->we_version_source = 16;
 
-//	range->retry_capa;	/* What retry options are supported */
-//	range->retry_flags;	/* How to decode max/min retry limit */
-//	range->r_time_flags;	/* How to decode max/min retry life */
-//	range->min_retry;	/* Minimal number of retries */
-//	range->max_retry;	/* Maximal number of retries */
-//	range->min_r_time;	/* Minimal retry lifetime */
-//	range->max_r_time;	/* Maximal retry lifetime */
+//      range->retry_capa;      /* What retry options are supported */
+//      range->retry_flags;     /* How to decode max/min retry limit */
+//      range->r_time_flags;    /* How to decode max/min retry life */
+//      range->min_retry;       /* Minimal number of retries */
+//      range->max_retry;       /* Maximal number of retries */
+//      range->min_r_time;      /* Minimal retry lifetime */
+//      range->max_r_time;      /* Maximal retry lifetime */
 
-        range->num_channels = FREQ_COUNT;
+	range->num_channels = FREQ_COUNT;
 
 	val = 0;
 	for (i = 0; i < FREQ_COUNT; i++) {
 		// TODO: Include only legal frequencies for some countries
-//		if (local->channel_mask & (1 << i)) {
-			range->freq[val].i = i + 1;
-			range->freq[val].m = ipw2100_frequencies[i] * 100000;
-			range->freq[val].e = 1;
-			val++;
-//		}
+//              if (local->channel_mask & (1 << i)) {
+		range->freq[val].i = i + 1;
+		range->freq[val].m = ipw2100_frequencies[i] * 100000;
+		range->freq[val].e = 1;
+		val++;
+//              }
 		if (val == IW_MAX_FREQUENCIES)
-		break;
+			break;
 	}
 	range->num_frequency = val;
 
@@ -7259,7 +7229,7 @@
 		     wrqu->ap_addr.sa_data[4] & 0xff,
 		     wrqu->ap_addr.sa_data[5] & 0xff);
 
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -7276,10 +7246,9 @@
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured BSSID then return that; otherwise return ANY */
-	if (priv->config & CFG_STATIC_BSSID ||
-	    priv->status & STATUS_ASSOCIATED) {
+	if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
 		wrqu->ap_addr.sa_family = ARPHRD_ETHER;
-		memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN);
+		memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
 	} else
 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
 
@@ -7293,7 +7262,7 @@
 				union iwreq_data *wrqu, char *extra)
 {
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
-	char *essid = ""; /* ANY */
+	char *essid = "";	/* ANY */
 	int length = 0;
 	int err = 0;
 
@@ -7333,7 +7302,7 @@
 
 	err = ipw2100_set_essid(priv, essid, length, 0);
 
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -7350,17 +7319,16 @@
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured ESSID then return that; otherwise return ANY */
-	if (priv->config & CFG_STATIC_ESSID ||
-	    priv->status & STATUS_ASSOCIATED) {
+	if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
 		IPW_DEBUG_WX("Getting essid: '%s'\n",
 			     escape_essid(priv->essid, priv->essid_len));
 		memcpy(extra, priv->essid, priv->essid_len);
 		wrqu->essid.length = priv->essid_len;
-		wrqu->essid.flags = 1; /* active */
+		wrqu->essid.flags = 1;	/* active */
 	} else {
 		IPW_DEBUG_WX("Getting essid: ANY\n");
 		wrqu->essid.length = 0;
-		wrqu->essid.flags = 0; /* active */
+		wrqu->essid.flags = 0;	/* active */
 	}
 
 	return 0;
@@ -7379,9 +7347,9 @@
 	if (wrqu->data.length > IW_ESSID_MAX_SIZE)
 		return -E2BIG;
 
-	wrqu->data.length = min((size_t)wrqu->data.length, sizeof(priv->nick));
+	wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
 	memset(priv->nick, 0, sizeof(priv->nick));
-	memcpy(priv->nick, extra,  wrqu->data.length);
+	memcpy(priv->nick, extra, wrqu->data.length);
 
 	IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick);
 
@@ -7400,7 +7368,7 @@
 
 	wrqu->data.length = strlen(priv->nick) + 1;
 	memcpy(extra, priv->nick, wrqu->data.length);
-	wrqu->data.flags = 1; /* active */
+	wrqu->data.flags = 1;	/* active */
 
 	IPW_DEBUG_WX("GET Nickname -> %s \n", extra);
 
@@ -7442,12 +7410,11 @@
 	err = ipw2100_set_tx_rates(priv, rate, 0);
 
 	IPW_DEBUG_WX("SET Rate -> %04X \n", rate);
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
 
-
 static int ipw2100_wx_get_rate(struct net_device *dev,
 			       struct iw_request_info *info,
 			       union iwreq_data *wrqu, char *extra)
@@ -7495,7 +7462,7 @@
 
 	IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
 
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -7520,8 +7487,7 @@
 	if (wrqu->rts.disabled)
 		value = priv->rts_threshold | RTS_DISABLED;
 	else {
-		if (wrqu->rts.value < 1 ||
-		    wrqu->rts.value > 2304) {
+		if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
 			err = -EINVAL;
 			goto done;
 		}
@@ -7531,7 +7497,7 @@
 	err = ipw2100_set_rts_threshold(priv, value);
 
 	IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value);
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -7547,7 +7513,7 @@
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 
 	wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
-	wrqu->rts.fixed = 1; /* no auto select */
+	wrqu->rts.fixed = 1;	/* no auto select */
 
 	/* If RTS is set to the default value, then it is disabled */
 	wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
@@ -7574,8 +7540,7 @@
 		    wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
 			return -EINVAL;
 
-		value = (wrqu->txpower.value - IPW_TX_POWER_MIN_DBM) * 16 /
-			(IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
+		value = wrqu->txpower.value;
 	}
 
 	down(&priv->action_sem);
@@ -7588,7 +7553,7 @@
 
 	IPW_DEBUG_WX("SET TX Power -> %d \n", value);
 
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -7615,11 +7580,7 @@
 	} else {
 		wrqu->power.disabled = 0;
 		wrqu->power.fixed = 1;
-		wrqu->power.value =
-			(priv->tx_power *
-			 (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM)) /
-			(IPW_TX_POWER_MAX - IPW_TX_POWER_MIN) +
-			IPW_TX_POWER_MIN_DBM;
+		wrqu->power.value = priv->tx_power;
 	}
 
 	wrqu->power.flags = IW_TXPOW_DBM;
@@ -7684,8 +7645,7 @@
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	int err = 0;
 
-	if (wrqu->retry.flags & IW_RETRY_LIFETIME ||
-	    wrqu->retry.disabled)
+	if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
 		return -EINVAL;
 
 	if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
@@ -7700,14 +7660,14 @@
 	if (wrqu->retry.flags & IW_RETRY_MIN) {
 		err = ipw2100_set_short_retry(priv, wrqu->retry.value);
 		IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
-		       wrqu->retry.value);
+			     wrqu->retry.value);
 		goto done;
 	}
 
 	if (wrqu->retry.flags & IW_RETRY_MAX) {
 		err = ipw2100_set_long_retry(priv, wrqu->retry.value);
 		IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
-		       wrqu->retry.value);
+			     wrqu->retry.value);
 		goto done;
 	}
 
@@ -7717,7 +7677,7 @@
 
 	IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value);
 
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -7732,20 +7692,19 @@
 
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 
-	wrqu->retry.disabled = 0; /* can't be disabled */
+	wrqu->retry.disabled = 0;	/* can't be disabled */
 
-	if ((wrqu->retry.flags & IW_RETRY_TYPE) ==
-	    IW_RETRY_LIFETIME)
+	if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
 		return -EINVAL;
 
 	if (wrqu->retry.flags & IW_RETRY_MAX) {
-		wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX;
+		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
 		wrqu->retry.value = priv->long_retry_limit;
 	} else {
 		wrqu->retry.flags =
 		    (priv->short_retry_limit !=
 		     priv->long_retry_limit) ?
-		    IW_RETRY_LIMIT & IW_RETRY_MIN : IW_RETRY_LIMIT;
+		    IW_RETRY_LIMIT | IW_RETRY_MIN : IW_RETRY_LIMIT;
 
 		wrqu->retry.value = priv->short_retry_limit;
 	}
@@ -7769,15 +7728,14 @@
 	}
 
 	IPW_DEBUG_WX("Initiating scan...\n");
-	if (ipw2100_set_scan_options(priv) ||
-	    ipw2100_start_scan(priv)) {
+	if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
 		IPW_DEBUG_WX("Start scan failed.\n");
 
 		/* TODO: Mark a scan as pending so when hardware initialized
 		 *       a scan starts */
 	}
 
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -7794,7 +7752,6 @@
 	return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
 }
 
-
 /*
  * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
  */
@@ -7823,8 +7780,8 @@
 }
 
 static int ipw2100_wx_set_power(struct net_device *dev,
-			        struct iw_request_info *info,
-			        union iwreq_data *wrqu, char *extra)
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *extra)
 {
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	int err = 0;
@@ -7843,11 +7800,11 @@
 	}
 
 	switch (wrqu->power.flags & IW_POWER_MODE) {
-	case IW_POWER_ON:    /* If not specified */
-	case IW_POWER_MODE:  /* If set all mask */
-	case IW_POWER_ALL_R: /* If explicitely state all */
+	case IW_POWER_ON:	/* If not specified */
+	case IW_POWER_MODE:	/* If set all mask */
+	case IW_POWER_ALL_R:	/* If explicitely state all */
 		break;
-	default: /* Otherwise we don't support it */
+	default:		/* Otherwise we don't support it */
 		IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
 			     wrqu->power.flags);
 		err = -EOPNOTSUPP;
@@ -7859,18 +7816,17 @@
 	priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
 	err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
 
-	IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n",
-		     priv->power_mode);
+	IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
 
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 
 }
 
 static int ipw2100_wx_get_power(struct net_device *dev,
-			        struct iw_request_info *info,
-			        union iwreq_data *wrqu, char *extra)
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *extra)
 {
 	/*
 	 * This can be called at any time.  No action lock required
@@ -7878,9 +7834,9 @@
 
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 
-	if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+	if (!(priv->power_mode & IPW_POWER_ENABLED))
 		wrqu->power.disabled = 1;
-	} else {
+	else {
 		wrqu->power.disabled = 0;
 		wrqu->power.flags = 0;
 	}
@@ -7890,6 +7846,269 @@
 	return 0;
 }
 
+#if WIRELESS_EXT > 17
+/*
+ * WE-18 WPA support
+ */
+
+/* SIOCSIWGENIE */
+static int ipw2100_wx_set_genie(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *extra)
+{
+
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	struct ieee80211_device *ieee = priv->ieee;
+	u8 *buf;
+
+	if (!ieee->wpa_enabled)
+		return -EOPNOTSUPP;
+
+	if (wrqu->data.length > MAX_WPA_IE_LEN ||
+	    (wrqu->data.length && extra == NULL))
+		return -EINVAL;
+
+	if (wrqu->data.length) {
+		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+		if (buf == NULL)
+			return -ENOMEM;
+
+		memcpy(buf, extra, wrqu->data.length);
+		kfree(ieee->wpa_ie);
+		ieee->wpa_ie = buf;
+		ieee->wpa_ie_len = wrqu->data.length;
+	} else {
+		kfree(ieee->wpa_ie);
+		ieee->wpa_ie = NULL;
+		ieee->wpa_ie_len = 0;
+	}
+
+	ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
+
+	return 0;
+}
+
+/* SIOCGIWGENIE */
+static int ipw2100_wx_get_genie(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *extra)
+{
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	struct ieee80211_device *ieee = priv->ieee;
+
+	if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
+		wrqu->data.length = 0;
+		return 0;
+	}
+
+	if (wrqu->data.length < ieee->wpa_ie_len)
+		return -E2BIG;
+
+	wrqu->data.length = ieee->wpa_ie_len;
+	memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
+
+	return 0;
+}
+
+/* SIOCSIWAUTH */
+static int ipw2100_wx_set_auth(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	struct ieee80211_device *ieee = priv->ieee;
+	struct iw_param *param = &wrqu->param;
+	struct ieee80211_crypt_data *crypt;
+	unsigned long flags;
+	int ret = 0;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 * ipw2200 does not use these parameters
+		 */
+		break;
+
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+		if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
+			break;
+
+		flags = crypt->ops->get_flags(crypt->priv);
+
+		if (param->value)
+			flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+		else
+			flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+
+		crypt->ops->set_flags(flags, crypt->priv);
+
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:{
+			/* HACK:
+			 *
+			 * wpa_supplicant calls set_wpa_enabled when the driver
+			 * is loaded and unloaded, regardless of if WPA is being
+			 * used.  No other calls are made which can be used to
+			 * determine if encryption will be used or not prior to
+			 * association being expected.  If encryption is not being
+			 * used, drop_unencrypted is set to false, else true -- we
+			 * can use this to determine if the CAP_PRIVACY_ON bit should
+			 * be set.
+			 */
+			struct ieee80211_security sec = {
+				.flags = SEC_ENABLED,
+				.enabled = param->value,
+			};
+			priv->ieee->drop_unencrypted = param->value;
+			/* We only change SEC_LEVEL for open mode. Others
+			 * are set by ipw_wpa_set_encryption.
+			 */
+			if (!param->value) {
+				sec.flags |= SEC_LEVEL;
+				sec.level = SEC_LEVEL_0;
+			} else {
+				sec.flags |= SEC_LEVEL;
+				sec.level = SEC_LEVEL_1;
+			}
+			if (priv->ieee->set_security)
+				priv->ieee->set_security(priv->ieee->dev, &sec);
+			break;
+		}
+
+	case IW_AUTH_80211_AUTH_ALG:
+		ret = ipw2100_wpa_set_auth_algs(priv, param->value);
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		ret = ipw2100_wpa_enable(priv, param->value);
+		break;
+
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		ieee->ieee802_1x = param->value;
+		break;
+
+		//case IW_AUTH_ROAMING_CONTROL:
+	case IW_AUTH_PRIVACY_INVOKED:
+		ieee->privacy_invoked = param->value;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+/* SIOCGIWAUTH */
+static int ipw2100_wx_get_auth(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	struct ieee80211_device *ieee = priv->ieee;
+	struct ieee80211_crypt_data *crypt;
+	struct iw_param *param = &wrqu->param;
+	int ret = 0;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 * wpa_supplicant will control these internally
+		 */
+		ret = -EOPNOTSUPP;
+		break;
+
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+		if (!crypt || !crypt->ops->get_flags) {
+			IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
+					  "crypt not set!\n");
+			break;
+		}
+
+		param->value = (crypt->ops->get_flags(crypt->priv) &
+				IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
+
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		param->value = ieee->drop_unencrypted;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		param->value = priv->ieee->sec.auth_mode;
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		param->value = ieee->wpa_enabled;
+		break;
+
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		param->value = ieee->ieee802_1x;
+		break;
+
+	case IW_AUTH_ROAMING_CONTROL:
+	case IW_AUTH_PRIVACY_INVOKED:
+		param->value = ieee->privacy_invoked;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+/* SIOCSIWENCODEEXT */
+static int ipw2100_wx_set_encodeext(struct net_device *dev,
+				    struct iw_request_info *info,
+				    union iwreq_data *wrqu, char *extra)
+{
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra);
+}
+
+/* SIOCGIWENCODEEXT */
+static int ipw2100_wx_get_encodeext(struct net_device *dev,
+				    struct iw_request_info *info,
+				    union iwreq_data *wrqu, char *extra)
+{
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra);
+}
+
+/* SIOCSIWMLME */
+static int ipw2100_wx_set_mlme(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	struct iw_mlme *mlme = (struct iw_mlme *)extra;
+	u16 reason;
+
+	reason = cpu_to_le16(mlme->reason_code);
+
+	switch (mlme->cmd) {
+	case IW_MLME_DEAUTH:
+		// silently ignore
+		break;
+
+	case IW_MLME_DISASSOC:
+		ipw2100_disassociate_bssid(priv);
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+#endif				/* WIRELESS_EXT > 17 */
 
 /*
  *
@@ -7923,7 +8142,7 @@
 		if (priv->ieee->iw_mode == IW_MODE_MONITOR)
 			err = ipw2100_switch_mode(priv, priv->last_mode);
 	}
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -7958,7 +8177,7 @@
 
 	if (priv->power_mode != mode)
 		err = ipw2100_set_power_mode(priv, mode);
- done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
@@ -7986,8 +8205,8 @@
 				 "Power save level: %d (None)", level);
 			break;
 		case IPW_POWER_AUTO:
-		snprintf(extra, MAX_POWER_STRING,
-			 "Power save level: %d (Auto)", 0);
+			snprintf(extra, MAX_POWER_STRING,
+				 "Power save level: %d (Auto)", 0);
 			break;
 		default:
 			timeout = timeout_duration[level - 1] / 1000;
@@ -8004,7 +8223,6 @@
 	return 0;
 }
 
-
 static int ipw2100_wx_set_preamble(struct net_device *dev,
 				   struct iw_request_info *info,
 				   union iwreq_data *wrqu, char *extra)
@@ -8029,14 +8247,14 @@
 
 	err = ipw2100_system_config(priv, 0);
 
-done:
+      done:
 	up(&priv->action_sem);
 	return err;
 }
 
 static int ipw2100_wx_get_preamble(struct net_device *dev,
-				    struct iw_request_info *info,
-				    union iwreq_data *wrqu, char *extra)
+				   struct iw_request_info *info,
+				   union iwreq_data *wrqu, char *extra)
 {
 	/*
 	 * This can be called at any time.  No action lock required
@@ -8052,54 +8270,116 @@
 	return 0;
 }
 
-static iw_handler ipw2100_wx_handlers[] =
+#ifdef CONFIG_IPW2100_MONITOR
+static int ipw2100_wx_set_crc_check(struct net_device *dev,
+				    struct iw_request_info *info,
+				    union iwreq_data *wrqu, char *extra)
 {
-        NULL,                     /* SIOCSIWCOMMIT */
-        ipw2100_wx_get_name,      /* SIOCGIWNAME */
-        NULL,                     /* SIOCSIWNWID */
-        NULL,                     /* SIOCGIWNWID */
-        ipw2100_wx_set_freq,      /* SIOCSIWFREQ */
-        ipw2100_wx_get_freq,      /* SIOCGIWFREQ */
-        ipw2100_wx_set_mode,      /* SIOCSIWMODE */
-        ipw2100_wx_get_mode,      /* SIOCGIWMODE */
-        NULL,                     /* SIOCSIWSENS */
-        NULL,                     /* SIOCGIWSENS */
-        NULL,                     /* SIOCSIWRANGE */
-        ipw2100_wx_get_range,     /* SIOCGIWRANGE */
-        NULL,                     /* SIOCSIWPRIV */
-        NULL,                     /* SIOCGIWPRIV */
-        NULL,                     /* SIOCSIWSTATS */
-        NULL,                     /* SIOCGIWSTATS */
-        NULL,                     /* SIOCSIWSPY */
-        NULL,                     /* SIOCGIWSPY */
-        NULL,                     /* SIOCGIWTHRSPY */
-        NULL,                     /* SIOCWIWTHRSPY */
-        ipw2100_wx_set_wap,       /* SIOCSIWAP */
-        ipw2100_wx_get_wap,       /* SIOCGIWAP */
-        NULL,                     /* -- hole -- */
-        NULL,                     /* SIOCGIWAPLIST -- deprecated */
-        ipw2100_wx_set_scan,      /* SIOCSIWSCAN */
-        ipw2100_wx_get_scan,      /* SIOCGIWSCAN */
-        ipw2100_wx_set_essid,     /* SIOCSIWESSID */
-        ipw2100_wx_get_essid,     /* SIOCGIWESSID */
-        ipw2100_wx_set_nick,      /* SIOCSIWNICKN */
-        ipw2100_wx_get_nick,      /* SIOCGIWNICKN */
-        NULL,                     /* -- hole -- */
-        NULL,                     /* -- hole -- */
-        ipw2100_wx_set_rate,      /* SIOCSIWRATE */
-        ipw2100_wx_get_rate,      /* SIOCGIWRATE */
-        ipw2100_wx_set_rts,       /* SIOCSIWRTS */
-        ipw2100_wx_get_rts,       /* SIOCGIWRTS */
-        ipw2100_wx_set_frag,      /* SIOCSIWFRAG */
-        ipw2100_wx_get_frag,      /* SIOCGIWFRAG */
-        ipw2100_wx_set_txpow,     /* SIOCSIWTXPOW */
-        ipw2100_wx_get_txpow,     /* SIOCGIWTXPOW */
-        ipw2100_wx_set_retry,     /* SIOCSIWRETRY */
-        ipw2100_wx_get_retry,     /* SIOCGIWRETRY */
-        ipw2100_wx_set_encode,    /* SIOCSIWENCODE */
-        ipw2100_wx_get_encode,    /* SIOCGIWENCODE */
-        ipw2100_wx_set_power,     /* SIOCSIWPOWER */
-        ipw2100_wx_get_power,     /* SIOCGIWPOWER */
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	int err, mode = *(int *)extra;
+
+	down(&priv->action_sem);
+	if (!(priv->status & STATUS_INITIALIZED)) {
+		err = -EIO;
+		goto done;
+	}
+
+	if (mode == 1)
+		priv->config |= CFG_CRC_CHECK;
+	else if (mode == 0)
+		priv->config &= ~CFG_CRC_CHECK;
+	else {
+		err = -EINVAL;
+		goto done;
+	}
+	err = 0;
+
+      done:
+	up(&priv->action_sem);
+	return err;
+}
+
+static int ipw2100_wx_get_crc_check(struct net_device *dev,
+				    struct iw_request_info *info,
+				    union iwreq_data *wrqu, char *extra)
+{
+	/*
+	 * This can be called at any time.  No action lock required
+	 */
+
+	struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+	if (priv->config & CFG_CRC_CHECK)
+		snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
+	else
+		snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
+
+	return 0;
+}
+#endif				/* CONFIG_IPW2100_MONITOR */
+
+static iw_handler ipw2100_wx_handlers[] = {
+	NULL,			/* SIOCSIWCOMMIT */
+	ipw2100_wx_get_name,	/* SIOCGIWNAME */
+	NULL,			/* SIOCSIWNWID */
+	NULL,			/* SIOCGIWNWID */
+	ipw2100_wx_set_freq,	/* SIOCSIWFREQ */
+	ipw2100_wx_get_freq,	/* SIOCGIWFREQ */
+	ipw2100_wx_set_mode,	/* SIOCSIWMODE */
+	ipw2100_wx_get_mode,	/* SIOCGIWMODE */
+	NULL,			/* SIOCSIWSENS */
+	NULL,			/* SIOCGIWSENS */
+	NULL,			/* SIOCSIWRANGE */
+	ipw2100_wx_get_range,	/* SIOCGIWRANGE */
+	NULL,			/* SIOCSIWPRIV */
+	NULL,			/* SIOCGIWPRIV */
+	NULL,			/* SIOCSIWSTATS */
+	NULL,			/* SIOCGIWSTATS */
+	NULL,			/* SIOCSIWSPY */
+	NULL,			/* SIOCGIWSPY */
+	NULL,			/* SIOCGIWTHRSPY */
+	NULL,			/* SIOCWIWTHRSPY */
+	ipw2100_wx_set_wap,	/* SIOCSIWAP */
+	ipw2100_wx_get_wap,	/* SIOCGIWAP */
+#if WIRELESS_EXT > 17
+	ipw2100_wx_set_mlme,	/* SIOCSIWMLME */
+#else
+	NULL,			/* -- hole -- */
+#endif
+	NULL,			/* SIOCGIWAPLIST -- deprecated */
+	ipw2100_wx_set_scan,	/* SIOCSIWSCAN */
+	ipw2100_wx_get_scan,	/* SIOCGIWSCAN */
+	ipw2100_wx_set_essid,	/* SIOCSIWESSID */
+	ipw2100_wx_get_essid,	/* SIOCGIWESSID */
+	ipw2100_wx_set_nick,	/* SIOCSIWNICKN */
+	ipw2100_wx_get_nick,	/* SIOCGIWNICKN */
+	NULL,			/* -- hole -- */
+	NULL,			/* -- hole -- */
+	ipw2100_wx_set_rate,	/* SIOCSIWRATE */
+	ipw2100_wx_get_rate,	/* SIOCGIWRATE */
+	ipw2100_wx_set_rts,	/* SIOCSIWRTS */
+	ipw2100_wx_get_rts,	/* SIOCGIWRTS */
+	ipw2100_wx_set_frag,	/* SIOCSIWFRAG */
+	ipw2100_wx_get_frag,	/* SIOCGIWFRAG */
+	ipw2100_wx_set_txpow,	/* SIOCSIWTXPOW */
+	ipw2100_wx_get_txpow,	/* SIOCGIWTXPOW */
+	ipw2100_wx_set_retry,	/* SIOCSIWRETRY */
+	ipw2100_wx_get_retry,	/* SIOCGIWRETRY */
+	ipw2100_wx_set_encode,	/* SIOCSIWENCODE */
+	ipw2100_wx_get_encode,	/* SIOCGIWENCODE */
+	ipw2100_wx_set_power,	/* SIOCSIWPOWER */
+	ipw2100_wx_get_power,	/* SIOCGIWPOWER */
+#if WIRELESS_EXT > 17
+	NULL,			/* -- hole -- */
+	NULL,			/* -- hole -- */
+	ipw2100_wx_set_genie,	/* SIOCSIWGENIE */
+	ipw2100_wx_get_genie,	/* SIOCGIWGENIE */
+	ipw2100_wx_set_auth,	/* SIOCSIWAUTH */
+	ipw2100_wx_get_auth,	/* SIOCGIWAUTH */
+	ipw2100_wx_set_encodeext,	/* SIOCSIWENCODEEXT */
+	ipw2100_wx_get_encodeext,	/* SIOCGIWENCODEEXT */
+	NULL,			/* SIOCSIWPMKSA */
+#endif
 };
 
 #define IPW2100_PRIV_SET_MONITOR	SIOCIWFIRSTPRIV
@@ -8108,60 +8388,71 @@
 #define IPW2100_PRIV_GET_POWER		SIOCIWFIRSTPRIV+3
 #define IPW2100_PRIV_SET_LONGPREAMBLE	SIOCIWFIRSTPRIV+4
 #define IPW2100_PRIV_GET_LONGPREAMBLE	SIOCIWFIRSTPRIV+5
+#define IPW2100_PRIV_SET_CRC_CHECK	SIOCIWFIRSTPRIV+6
+#define IPW2100_PRIV_GET_CRC_CHECK	SIOCIWFIRSTPRIV+7
 
 static const struct iw_priv_args ipw2100_private_args[] = {
 
 #ifdef CONFIG_IPW2100_MONITOR
 	{
-		IPW2100_PRIV_SET_MONITOR,
-		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"
-	},
+	 IPW2100_PRIV_SET_MONITOR,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
 	{
-		IPW2100_PRIV_RESET,
-		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"
-	},
-#endif /* CONFIG_IPW2100_MONITOR */
+	 IPW2100_PRIV_RESET,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
+#endif				/* CONFIG_IPW2100_MONITOR */
 
 	{
-		IPW2100_PRIV_SET_POWER,
-		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"
-	},
+	 IPW2100_PRIV_SET_POWER,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
 	{
-		IPW2100_PRIV_GET_POWER,
-		0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING, "get_power"
-	},
+	 IPW2100_PRIV_GET_POWER,
+	 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
+	 "get_power"},
 	{
-		IPW2100_PRIV_SET_LONGPREAMBLE,
-		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"
-	},
+	 IPW2100_PRIV_SET_LONGPREAMBLE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
 	{
-		IPW2100_PRIV_GET_LONGPREAMBLE,
-		0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"
-	},
+	 IPW2100_PRIV_GET_LONGPREAMBLE,
+	 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
+#ifdef CONFIG_IPW2100_MONITOR
+	{
+	 IPW2100_PRIV_SET_CRC_CHECK,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
+	{
+	 IPW2100_PRIV_GET_CRC_CHECK,
+	 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
+#endif				/* CONFIG_IPW2100_MONITOR */
 };
 
 static iw_handler ipw2100_private_handler[] = {
 #ifdef CONFIG_IPW2100_MONITOR
 	ipw2100_wx_set_promisc,
 	ipw2100_wx_reset,
-#else /* CONFIG_IPW2100_MONITOR */
+#else				/* CONFIG_IPW2100_MONITOR */
 	NULL,
 	NULL,
-#endif /* CONFIG_IPW2100_MONITOR */
+#endif				/* CONFIG_IPW2100_MONITOR */
 	ipw2100_wx_set_powermode,
 	ipw2100_wx_get_powermode,
 	ipw2100_wx_set_preamble,
 	ipw2100_wx_get_preamble,
+#ifdef CONFIG_IPW2100_MONITOR
+	ipw2100_wx_set_crc_check,
+	ipw2100_wx_get_crc_check,
+#else				/* CONFIG_IPW2100_MONITOR */
+	NULL,
+	NULL,
+#endif				/* CONFIG_IPW2100_MONITOR */
 };
 
-static struct iw_handler_def ipw2100_wx_handler_def =
-{
+static struct iw_handler_def ipw2100_wx_handler_def = {
 	.standard = ipw2100_wx_handlers,
 	.num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler),
 	.num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler),
- 	.num_private_args = sizeof(ipw2100_private_args) /
-	sizeof(struct iw_priv_args),
-	.private = (iw_handler *)ipw2100_private_handler,
+	.num_private_args = sizeof(ipw2100_private_args) /
+	    sizeof(struct iw_priv_args),
+	.private = (iw_handler *) ipw2100_private_handler,
 	.private_args = (struct iw_priv_args *)ipw2100_private_args,
 };
 
@@ -8170,7 +8461,7 @@
  * Called by /proc/net/wireless
  * Also called by SIOCGIWSTATS
  */
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
+static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
 {
 	enum {
 		POOR = 30,
@@ -8190,7 +8481,7 @@
 	u32 ord_len = sizeof(u32);
 
 	if (!priv)
-		return (struct iw_statistics *) NULL;
+		return (struct iw_statistics *)NULL;
 
 	wstats = &priv->wstats;
 
@@ -8207,7 +8498,7 @@
 		wstats->qual.noise = 0;
 		wstats->qual.updated = 7;
 		wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
-			IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+		    IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
 		return wstats;
 	}
 
@@ -8215,7 +8506,7 @@
 				&missed_beacons, &ord_len))
 		goto fail_get_ordinal;
 
-        /* If we don't have a connection the quality and level is 0*/
+	/* If we don't have a connection the quality and level is 0 */
 	if (!(priv->status & STATUS_ASSOCIATED)) {
 		wstats->qual.qual = 0;
 		wstats->qual.level = 0;
@@ -8232,10 +8523,10 @@
 			rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
 		else if (rssi < 30)
 			rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
-				10 + GOOD;
+			    10 + GOOD;
 		else
 			rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
-				10 + VERY_GOOD;
+			    10 + VERY_GOOD;
 
 		if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
 					&tx_retries, &ord_len))
@@ -8249,25 +8540,25 @@
 			tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
 		else if (tx_retries > 50)
 			tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
-				15 + GOOD;
+			    15 + GOOD;
 		else
 			tx_qual = (50 - tx_retries) *
-				(PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+			    (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
 
 		if (missed_beacons > 50)
 			beacon_qual = (60 - missed_beacons) * POOR / 10;
 		else if (missed_beacons > 40)
 			beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
-				10 + POOR;
+			    10 + POOR;
 		else if (missed_beacons > 32)
 			beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
-				18 + FAIR;
+			    18 + FAIR;
 		else if (missed_beacons > 20)
 			beacon_qual = (32 - missed_beacons) *
-				(VERY_GOOD - GOOD) / 20 + GOOD;
+			    (VERY_GOOD - GOOD) / 20 + GOOD;
 		else
 			beacon_qual = (20 - missed_beacons) *
-				(PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
+			    (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
 
 		quality = min(beacon_qual, min(tx_qual, rssi_qual));
 
@@ -8290,7 +8581,7 @@
 	wstats->qual.updated = 7;
 	wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
 
-        /* FIXME: this is percent and not a # */
+	/* FIXME: this is percent and not a # */
 	wstats->miss.beacon = missed_beacons;
 
 	if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
@@ -8300,10 +8591,10 @@
 
 	return wstats;
 
- fail_get_ordinal:
+      fail_get_ordinal:
 	IPW_DEBUG_WX("failed querying ordinals.\n");
 
-	return (struct iw_statistics *) NULL;
+	return (struct iw_statistics *)NULL;
 }
 
 static void ipw2100_wx_event_work(struct ipw2100_priv *priv)
@@ -8326,23 +8617,17 @@
 	if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
 	    priv->status & STATUS_RF_KILL_MASK ||
 	    ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
-				&priv->bssid,  &len)) {
+				&priv->bssid, &len)) {
 		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
 	} else {
 		/* We now have the BSSID, so can finish setting to the full
 		 * associated state */
 		memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
-		memcpy(&priv->ieee->bssid, priv->bssid, ETH_ALEN);
+		memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
 		priv->status &= ~STATUS_ASSOCIATING;
 		priv->status |= STATUS_ASSOCIATED;
 		netif_carrier_on(priv->net_dev);
-		if (netif_queue_stopped(priv->net_dev)) {
-			IPW_DEBUG_INFO("Waking net queue.\n");
-			netif_wake_queue(priv->net_dev);
-		} else {
-			IPW_DEBUG_INFO("Starting net queue.\n");
-			netif_start_queue(priv->net_dev);
-		}
+		netif_wake_queue(priv->net_dev);
 	}
 
 	if (!(priv->status & STATUS_ASSOCIATED)) {
@@ -8351,7 +8636,8 @@
 		/* This is a disassociation event, so kick the firmware to
 		 * look for another AP */
 		if (priv->config & CFG_STATIC_ESSID)
-			ipw2100_set_essid(priv, priv->essid, priv->essid_len, 0);
+			ipw2100_set_essid(priv, priv->essid, priv->essid_len,
+					  0);
 		else
 			ipw2100_set_essid(priv, NULL, 0, 0);
 		up(&priv->action_sem);
@@ -8374,7 +8660,6 @@
 
 #define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
 
-
 /*
 
 BINARY FIRMWARE HEADER FORMAT
@@ -8396,12 +8681,10 @@
 	unsigned int uc_size;
 } __attribute__ ((packed));
 
-
-
 static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
 {
 	struct ipw2100_fw_header *h =
-		(struct ipw2100_fw_header *)fw->fw_entry->data;
+	    (struct ipw2100_fw_header *)fw->fw_entry->data;
 
 	if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
 		printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
@@ -8420,7 +8703,6 @@
 	return 0;
 }
 
-
 static int ipw2100_get_firmware(struct ipw2100_priv *priv,
 				struct ipw2100_fw *fw)
 {
@@ -8428,7 +8710,7 @@
 	int rc;
 
 	IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
-	       priv->net_dev->name);
+		       priv->net_dev->name);
 
 	switch (priv->ieee->iw_mode) {
 	case IW_MODE_ADHOC:
@@ -8454,7 +8736,7 @@
 		return rc;
 	}
 	IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
-			   fw->fw_entry->size);
+		       fw->fw_entry->size);
 
 	ipw2100_mod_firmware_load(fw);
 
@@ -8470,7 +8752,6 @@
 	fw->fw_entry = NULL;
 }
 
-
 static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
 				 size_t max)
 {
@@ -8479,8 +8760,7 @@
 	u32 tmp;
 	int i;
 	/* firmware version is an ascii string (max len of 14) */
-	if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM,
-				ver, &len))
+	if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
 		return -EIO;
 	tmp = max;
 	if (len >= max)
@@ -8497,8 +8777,7 @@
 	u32 ver;
 	u32 len = sizeof(ver);
 	/* microcode version is a 32 bit integer */
-	if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION,
-				&ver, &len))
+	if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
 		return -EIO;
 	return snprintf(buf, max, "%08X", ver);
 }
@@ -8506,8 +8785,7 @@
 /*
  * On exit, the firmware will have been freed from the fw list
  */
-static int ipw2100_fw_download(struct ipw2100_priv *priv,
-			       struct ipw2100_fw *fw)
+static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
 {
 	/* firmware is constructed of N contiguous entries, each entry is
 	 * structured as:
@@ -8515,7 +8793,7 @@
 	 * offset    sie         desc
 	 * 0         4           address to write to
 	 * 4         2           length of data run
-         * 6         length      data
+	 * 6         length      data
 	 */
 	unsigned int addr;
 	unsigned short len;
@@ -8524,12 +8802,12 @@
 	unsigned int firmware_data_left = fw->fw.size;
 
 	while (firmware_data_left > 0) {
-	   	addr = *(u32 *)(firmware_data);
-		firmware_data      += 4;
+		addr = *(u32 *) (firmware_data);
+		firmware_data += 4;
 		firmware_data_left -= 4;
 
-	   	len = *(u16 *)(firmware_data);
-		firmware_data      += 2;
+		len = *(u16 *) (firmware_data);
+		firmware_data += 2;
 		firmware_data_left -= 2;
 
 		if (len > 32) {
@@ -8540,7 +8818,7 @@
 		}
 
 		write_nic_memory(priv->net_dev, addr, len, firmware_data);
-		firmware_data      += len;
+		firmware_data += len;
 		firmware_data_left -= len;
 	}
 
@@ -8654,21 +8932,19 @@
 	for (i = 0; i < 30; i++) {
 		/* Read alive response structure */
 		for (j = 0;
-		     j < (sizeof(struct symbol_alive_response) >> 1);
-		     j++)
-			read_nic_word(dev, 0x210004,
-				      ((u16 *)&response) + j);
+		     j < (sizeof(struct symbol_alive_response) >> 1); j++)
+			read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
 
-		if ((response.cmd_id == 1) &&
-		    (response.ucode_valid == 0x1))
+		if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
 			break;
 		udelay(10);
 	}
 
 	if (i == 30) {
-		printk(KERN_ERR DRV_NAME ": %s: No response from Symbol - hw not alive\n",
+		printk(KERN_ERR DRV_NAME
+		       ": %s: No response from Symbol - hw not alive\n",
 		       dev->name);
-		printk_buf(IPW_DL_ERROR, (u8*)&response, sizeof(response));
+		printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
 		return -EIO;
 	}
 
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h
index c9e99ce..140fdf2 100644
--- a/drivers/net/wireless/ipw2100.h
+++ b/drivers/net/wireless/ipw2100.h
@@ -1,6 +1,6 @@
 /******************************************************************************
 
-  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+  Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms of version 2 of the GNU General Public License as
@@ -37,7 +37,6 @@
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
-#include <linux/version.h>
 #include <net/iw_handler.h>	// new driver API
 
 #include <net/ieee80211.h>
@@ -93,7 +92,6 @@
 #define IPW_DL_IOCTL         (1<<14)
 #define IPW_DL_RF_KILL       (1<<17)
 
-
 #define IPW_DL_MANAGE        (1<<15)
 #define IPW_DL_FW            (1<<16)
 
@@ -156,7 +154,9 @@
 
 struct bd_status {
 	union {
-		struct { u8 nlf:1, txType:2, intEnabled:1, reserved:4;} fields;
+		struct {
+			u8 nlf:1, txType:2, intEnabled:1, reserved:4;
+		} fields;
 		u8 field;
 	} info;
 } __attribute__ ((packed));
@@ -165,7 +165,7 @@
 	u32 host_addr;
 	u32 buf_length;
 	struct bd_status status;
-        /* number of fragments for frame (should be set only for
+	/* number of fragments for frame (should be set only for
 	 * 1st TBD) */
 	u8 num_fragments;
 	u8 reserved[6];
@@ -293,10 +293,10 @@
 struct ipw2100_data_header {
 	u32 host_command_reg;
 	u32 host_command_reg1;
-	u8 encrypted;	// BOOLEAN in win! TRUE if frame is enc by driver
+	u8 encrypted;		// BOOLEAN in win! TRUE if frame is enc by driver
 	u8 needs_encryption;	// BOOLEAN in win! TRUE if frma need to be enc in NIC
 	u8 wep_index;		// 0 no key, 1-4 key index, 0xff immediate key
-	u8 key_size;	// 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV
+	u8 key_size;		// 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV
 	u8 key[16];
 	u8 reserved[10];	// f/w reserved
 	u8 src_addr[ETH_ALEN];
@@ -306,14 +306,13 @@
 
 /* Host command data structure */
 struct host_command {
-	u32 host_command;		// COMMAND ID
-	u32 host_command1;		// COMMAND ID
+	u32 host_command;	// COMMAND ID
+	u32 host_command1;	// COMMAND ID
 	u32 host_command_sequence;	// UNIQUE COMMAND NUMBER (ID)
 	u32 host_command_length;	// LENGTH
 	u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN];	// COMMAND PARAMETERS
 } __attribute__ ((packed));
 
-
 typedef enum {
 	POWER_ON_RESET,
 	EXIT_POWER_DOWN_RESET,
@@ -328,17 +327,16 @@
 	RX
 };
 
-
 struct ipw2100_tx_packet {
 	int type;
 	int index;
 	union {
-		struct { /* COMMAND */
-			struct ipw2100_cmd_header* cmd;
+		struct {	/* COMMAND */
+			struct ipw2100_cmd_header *cmd;
 			dma_addr_t cmd_phys;
 		} c_struct;
-		struct { /* DATA */
-			struct ipw2100_data_header* data;
+		struct {	/* DATA */
+			struct ipw2100_data_header *data;
 			dma_addr_t data_phys;
 			struct ieee80211_txb *txb;
 		} d_struct;
@@ -348,7 +346,6 @@
 	struct list_head list;
 };
 
-
 struct ipw2100_rx_packet {
 	struct ipw2100_rx *rxp;
 	dma_addr_t dma_addr;
@@ -432,13 +429,13 @@
 };
 
 #define STATUS_POWERED          (1<<0)
-#define STATUS_CMD_ACTIVE       (1<<1)  /**< host command in progress */
-#define STATUS_RUNNING          (1<<2)  /* Card initialized, but not enabled */
-#define STATUS_ENABLED          (1<<3)  /* Card enabled -- can scan,Tx,Rx */
-#define STATUS_STOPPING         (1<<4)  /* Card is in shutdown phase */
-#define STATUS_INITIALIZED      (1<<5)  /* Card is ready for external calls */
-#define STATUS_ASSOCIATING      (1<<9)  /* Associated, but no BSSID yet */
-#define STATUS_ASSOCIATED       (1<<10) /* Associated and BSSID valid */
+#define STATUS_CMD_ACTIVE       (1<<1)	/**< host command in progress */
+#define STATUS_RUNNING          (1<<2)	/* Card initialized, but not enabled */
+#define STATUS_ENABLED          (1<<3)	/* Card enabled -- can scan,Tx,Rx */
+#define STATUS_STOPPING         (1<<4)	/* Card is in shutdown phase */
+#define STATUS_INITIALIZED      (1<<5)	/* Card is ready for external calls */
+#define STATUS_ASSOCIATING      (1<<9)	/* Associated, but no BSSID yet */
+#define STATUS_ASSOCIATED       (1<<10)	/* Associated and BSSID valid */
 #define STATUS_INT_ENABLED      (1<<11)
 #define STATUS_RF_KILL_HW       (1<<12)
 #define STATUS_RF_KILL_SW       (1<<13)
@@ -451,9 +448,7 @@
 #define STATUS_SCAN_COMPLETE    (1<<26)
 #define STATUS_WX_EVENT_PENDING (1<<27)
 #define STATUS_RESET_PENDING    (1<<29)
-#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */
-
-
+#define STATUS_SECURITY_UPDATED (1<<30)	/* Security sync needed */
 
 /* Internal NIC states */
 #define IPW_STATE_INITIALIZED	(1<<0)
@@ -469,11 +464,9 @@
 #define IPW_STATE_POWER_DOWN	(1<<10)
 #define IPW_STATE_SCANNING      (1<<11)
 
-
-
-#define CFG_STATIC_CHANNEL      (1<<0) /* Restrict assoc. to single channel */
-#define CFG_STATIC_ESSID        (1<<1) /* Restrict assoc. to single SSID */
-#define CFG_STATIC_BSSID        (1<<2) /* Restrict assoc. to single BSSID */
+#define CFG_STATIC_CHANNEL      (1<<0)	/* Restrict assoc. to single channel */
+#define CFG_STATIC_ESSID        (1<<1)	/* Restrict assoc. to single SSID */
+#define CFG_STATIC_BSSID        (1<<2)	/* Restrict assoc. to single BSSID */
 #define CFG_CUSTOM_MAC          (1<<3)
 #define CFG_LONG_PREAMBLE       (1<<4)
 #define CFG_ASSOCIATE           (1<<6)
@@ -481,14 +474,17 @@
 #define CFG_ADHOC_CREATE        (1<<8)
 #define CFG_C3_DISABLED         (1<<9)
 #define CFG_PASSIVE_SCAN        (1<<10)
+#ifdef CONFIG_IPW2100_MONITOR
+#define CFG_CRC_CHECK           (1<<11)
+#endif
 
-#define CAP_SHARED_KEY          (1<<0) /* Off = OPEN */
-#define CAP_PRIVACY_ON          (1<<1) /* Off = No privacy */
+#define CAP_SHARED_KEY          (1<<0)	/* Off = OPEN */
+#define CAP_PRIVACY_ON          (1<<1)	/* Off = No privacy */
 
 struct ipw2100_priv {
 
-	int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
-	int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
+	int stop_hang_check;	/* Set 1 when shutting down to kill hang_check */
+	int stop_rf_kill;	/* Set 1 when shutting down to kill rf_kill */
 
 	struct ieee80211_device *ieee;
 	unsigned long status;
@@ -519,19 +515,16 @@
 	unsigned long hw_features;
 	int hangs;
 	u32 last_rtc;
-	int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */
-	u8* snapshot[0x30];
+	int dump_raw;		/* 1 to dump raw bytes in /sys/.../memory */
+	u8 *snapshot[0x30];
 
 	u8 mandatory_bssid_mac[ETH_ALEN];
 	u8 mac_addr[ETH_ALEN];
 
 	int power_mode;
 
-	/* WEP data */
-	struct ieee80211_security sec;
 	int messages_sent;
 
-
 	int short_retry_limit;
 	int long_retry_limit;
 
@@ -599,7 +592,6 @@
 	wait_queue_head_t wait_command_queue;
 };
 
-
 /*********************************************************
  * Host Command -> From Driver to FW
  *********************************************************/
@@ -646,7 +638,6 @@
 #define CARD_DISABLE_PHY_OFF   61
 #define MSDU_TX_RATES          62
 
-
 /* Rogue AP Detection */
 #define SET_STATION_STAT_BITS      64
 #define CLEAR_STATIONS_STAT_BITS   65
@@ -655,8 +646,6 @@
 #define DISASSOCIATION_BSSID	   68
 #define SET_WPA_IE                 69
 
-
-
 /* system configuration bit mask: */
 #define IPW_CFG_MONITOR               0x00004
 #define IPW_CFG_PREAMBLE_AUTO        0x00010
@@ -704,7 +693,7 @@
 #define IPW2100_INTA_TX_TRANSFER               (0x00000001)	// Bit 0 (LSB)
 #define IPW2100_INTA_RX_TRANSFER               (0x00000002)	// Bit 1
 #define IPW2100_INTA_TX_COMPLETE	       (0x00000004)	// Bit 2
-#define IPW2100_INTA_EVENT_INTERRUPT           (0x00000008)     // Bit 3
+#define IPW2100_INTA_EVENT_INTERRUPT           (0x00000008)	// Bit 3
 #define IPW2100_INTA_STATUS_CHANGE             (0x00000010)	// Bit 4
 #define IPW2100_INTA_BEACON_PERIOD_EXPIRED     (0x00000020)	// Bit 5
 #define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE  (0x00010000)	// Bit 16
@@ -784,9 +773,6 @@
 #define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT	    100	// 100 milli
 #define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT	    100	// 100 milli
 
-
-
-
 #define IPW_HEADER_802_11_SIZE		 sizeof(struct ieee80211_hdr_3addr)
 #define IPW_MAX_80211_PAYLOAD_SIZE              2304U
 #define IPW_MAX_802_11_PAYLOAD_LENGTH		2312
@@ -843,8 +829,8 @@
 #define IPW_TX_POWER_MIN_DBM         (-12)
 #define IPW_TX_POWER_MAX_DBM         16
 
-#define FW_SCAN_DONOT_ASSOCIATE     0x0001 // Dont Attempt to Associate after Scan
-#define FW_SCAN_PASSIVE             0x0008 // Force PASSSIVE Scan
+#define FW_SCAN_DONOT_ASSOCIATE     0x0001	// Dont Attempt to Associate after Scan
+#define FW_SCAN_PASSIVE             0x0008	// Force PASSSIVE Scan
 
 #define REG_MIN_CHANNEL             0
 #define REG_MAX_CHANNEL             14
@@ -856,7 +842,6 @@
 #define DIVERSITY_ANTENNA_A         1	// Use antenna A
 #define DIVERSITY_ANTENNA_B         2	// Use antenna B
 
-
 #define HOST_COMMAND_WAIT 0
 #define HOST_COMMAND_NO_WAIT 1
 
@@ -873,10 +858,9 @@
 #define TYPE_ASSOCIATION_REQUEST	0x0013
 #define TYPE_REASSOCIATION_REQUEST	0x0014
 
-
-#define HW_FEATURE_RFKILL (0x0001)
-#define RF_KILLSWITCH_OFF (1)
-#define RF_KILLSWITCH_ON  (0)
+#define HW_FEATURE_RFKILL 0x0001
+#define RF_KILLSWITCH_OFF 1
+#define RF_KILLSWITCH_ON  0
 
 #define IPW_COMMAND_POOL_SIZE        40
 
@@ -895,7 +879,7 @@
 // Fixed size data: Ordinal Table 1
 typedef enum _ORDINAL_TABLE_1 {	// NS - means Not Supported by FW
 // Transmit statistics
-	IPW_ORD_STAT_TX_HOST_REQUESTS = 1,// # of requested Host Tx's (MSDU)
+	IPW_ORD_STAT_TX_HOST_REQUESTS = 1,	// # of requested Host Tx's (MSDU)
 	IPW_ORD_STAT_TX_HOST_COMPLETE,	// # of successful Host Tx's (MSDU)
 	IPW_ORD_STAT_TX_DIR_DATA,	// # of successful Directed Tx's (MSDU)
 
@@ -905,42 +889,42 @@
 	IPW_ORD_STAT_TX_DIR_DATA11,	// # of successful Directed Tx's (MSDU) @ 11MB
 	IPW_ORD_STAT_TX_DIR_DATA22,	// # of successful Directed Tx's (MSDU) @ 22MB
 
-	IPW_ORD_STAT_TX_NODIR_DATA1 = 13,// # of successful Non_Directed Tx's (MSDU) @ 1MB
+	IPW_ORD_STAT_TX_NODIR_DATA1 = 13,	// # of successful Non_Directed Tx's (MSDU) @ 1MB
 	IPW_ORD_STAT_TX_NODIR_DATA2,	// # of successful Non_Directed Tx's (MSDU) @ 2MB
 	IPW_ORD_STAT_TX_NODIR_DATA5_5,	// # of successful Non_Directed Tx's (MSDU) @ 5.5MB
 	IPW_ORD_STAT_TX_NODIR_DATA11,	// # of successful Non_Directed Tx's (MSDU) @ 11MB
 
 	IPW_ORD_STAT_NULL_DATA = 21,	// # of successful NULL data Tx's
-	IPW_ORD_STAT_TX_RTS,	        // # of successful Tx RTS
-	IPW_ORD_STAT_TX_CTS,	        // # of successful Tx CTS
-	IPW_ORD_STAT_TX_ACK,	        // # of successful Tx ACK
-	IPW_ORD_STAT_TX_ASSN,	        // # of successful Association Tx's
+	IPW_ORD_STAT_TX_RTS,	// # of successful Tx RTS
+	IPW_ORD_STAT_TX_CTS,	// # of successful Tx CTS
+	IPW_ORD_STAT_TX_ACK,	// # of successful Tx ACK
+	IPW_ORD_STAT_TX_ASSN,	// # of successful Association Tx's
 	IPW_ORD_STAT_TX_ASSN_RESP,	// # of successful Association response Tx's
-	IPW_ORD_STAT_TX_REASSN,	        // # of successful Reassociation Tx's
+	IPW_ORD_STAT_TX_REASSN,	// # of successful Reassociation Tx's
 	IPW_ORD_STAT_TX_REASSN_RESP,	// # of successful Reassociation response Tx's
-	IPW_ORD_STAT_TX_PROBE,	        // # of probes successfully transmitted
+	IPW_ORD_STAT_TX_PROBE,	// # of probes successfully transmitted
 	IPW_ORD_STAT_TX_PROBE_RESP,	// # of probe responses successfully transmitted
-	IPW_ORD_STAT_TX_BEACON,	        // # of tx beacon
-	IPW_ORD_STAT_TX_ATIM,	        // # of Tx ATIM
+	IPW_ORD_STAT_TX_BEACON,	// # of tx beacon
+	IPW_ORD_STAT_TX_ATIM,	// # of Tx ATIM
 	IPW_ORD_STAT_TX_DISASSN,	// # of successful Disassociation TX
-	IPW_ORD_STAT_TX_AUTH,	        // # of successful Authentication Tx
-	IPW_ORD_STAT_TX_DEAUTH,	        // # of successful Deauthentication TX
+	IPW_ORD_STAT_TX_AUTH,	// # of successful Authentication Tx
+	IPW_ORD_STAT_TX_DEAUTH,	// # of successful Deauthentication TX
 
-	IPW_ORD_STAT_TX_TOTAL_BYTES = 41,// Total successful Tx data bytes
-	IPW_ORD_STAT_TX_RETRIES,         // # of Tx retries
-	IPW_ORD_STAT_TX_RETRY1,          // # of Tx retries at 1MBPS
-	IPW_ORD_STAT_TX_RETRY2,          // # of Tx retries at 2MBPS
-	IPW_ORD_STAT_TX_RETRY5_5,	 // # of Tx retries at 5.5MBPS
-	IPW_ORD_STAT_TX_RETRY11,	 // # of Tx retries at 11MBPS
+	IPW_ORD_STAT_TX_TOTAL_BYTES = 41,	// Total successful Tx data bytes
+	IPW_ORD_STAT_TX_RETRIES,	// # of Tx retries
+	IPW_ORD_STAT_TX_RETRY1,	// # of Tx retries at 1MBPS
+	IPW_ORD_STAT_TX_RETRY2,	// # of Tx retries at 2MBPS
+	IPW_ORD_STAT_TX_RETRY5_5,	// # of Tx retries at 5.5MBPS
+	IPW_ORD_STAT_TX_RETRY11,	// # of Tx retries at 11MBPS
 
 	IPW_ORD_STAT_TX_FAILURES = 51,	// # of Tx Failures
 	IPW_ORD_STAT_TX_ABORT_AT_HOP,	//NS // # of Tx's aborted at hop time
-	IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP,// # of times max tries in a hop failed
+	IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP,	// # of times max tries in a hop failed
 	IPW_ORD_STAT_TX_ABORT_LATE_DMA,	//NS // # of times tx aborted due to late dma setup
 	IPW_ORD_STAT_TX_ABORT_STX,	//NS // # of times backoff aborted
 	IPW_ORD_STAT_TX_DISASSN_FAIL,	// # of times disassociation failed
-	IPW_ORD_STAT_TX_ERR_CTS,         // # of missed/bad CTS frames
-	IPW_ORD_STAT_TX_BPDU,	        //NS // # of spanning tree BPDUs sent
+	IPW_ORD_STAT_TX_ERR_CTS,	// # of missed/bad CTS frames
+	IPW_ORD_STAT_TX_BPDU,	//NS // # of spanning tree BPDUs sent
 	IPW_ORD_STAT_TX_ERR_ACK,	// # of tx err due to acks
 
 	// Receive statistics
@@ -952,7 +936,7 @@
 	IPW_ORD_STAT_RX_DIR_DATA11,	// # of directed packets at 11MB
 	IPW_ORD_STAT_RX_DIR_DATA22,	// # of directed packets at 22MB
 
-	IPW_ORD_STAT_RX_NODIR_DATA = 71,// # of nondirected packets
+	IPW_ORD_STAT_RX_NODIR_DATA = 71,	// # of nondirected packets
 	IPW_ORD_STAT_RX_NODIR_DATA1,	// # of nondirected packets at 1MB
 	IPW_ORD_STAT_RX_NODIR_DATA2,	// # of nondirected packets at 2MB
 	IPW_ORD_STAT_RX_NODIR_DATA5_5,	// # of nondirected packets at 5.5MB
@@ -977,18 +961,18 @@
 	IPW_ORD_STAT_RX_AUTH,	// # of authentication Rx
 	IPW_ORD_STAT_RX_DEAUTH,	// # of deauthentication Rx
 
-	IPW_ORD_STAT_RX_TOTAL_BYTES = 101,// Total rx data bytes received
-	IPW_ORD_STAT_RX_ERR_CRC,	 // # of packets with Rx CRC error
-	IPW_ORD_STAT_RX_ERR_CRC1,	 // # of Rx CRC errors at 1MB
-	IPW_ORD_STAT_RX_ERR_CRC2,	 // # of Rx CRC errors at 2MB
-	IPW_ORD_STAT_RX_ERR_CRC5_5,	 // # of Rx CRC errors at 5.5MB
-	IPW_ORD_STAT_RX_ERR_CRC11,	 // # of Rx CRC errors at 11MB
+	IPW_ORD_STAT_RX_TOTAL_BYTES = 101,	// Total rx data bytes received
+	IPW_ORD_STAT_RX_ERR_CRC,	// # of packets with Rx CRC error
+	IPW_ORD_STAT_RX_ERR_CRC1,	// # of Rx CRC errors at 1MB
+	IPW_ORD_STAT_RX_ERR_CRC2,	// # of Rx CRC errors at 2MB
+	IPW_ORD_STAT_RX_ERR_CRC5_5,	// # of Rx CRC errors at 5.5MB
+	IPW_ORD_STAT_RX_ERR_CRC11,	// # of Rx CRC errors at 11MB
 
-	IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB
-	IPW_ORD_STAT_RX_DUPLICATE2,	 // # of duplicate rx packets at 2MB
-	IPW_ORD_STAT_RX_DUPLICATE5_5,	 // # of duplicate rx packets at 5.5MB
-	IPW_ORD_STAT_RX_DUPLICATE11,	 // # of duplicate rx packets at 11MB
-	IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets
+	IPW_ORD_STAT_RX_DUPLICATE1 = 112,	// # of duplicate rx packets at 1MB
+	IPW_ORD_STAT_RX_DUPLICATE2,	// # of duplicate rx packets at 2MB
+	IPW_ORD_STAT_RX_DUPLICATE5_5,	// # of duplicate rx packets at 5.5MB
+	IPW_ORD_STAT_RX_DUPLICATE11,	// # of duplicate rx packets at 11MB
+	IPW_ORD_STAT_RX_DUPLICATE = 119,	// # of duplicate rx packets
 
 	IPW_ORD_PERS_DB_LOCK = 120,	// # locking fw permanent  db
 	IPW_ORD_PERS_DB_SIZE,	// # size of fw permanent  db
@@ -1006,17 +990,17 @@
 	IPW_ORD_STAT_RX_ICV_ERRORS,	// # of ICV errors during decryption
 
 // PSP Statistics
-	IPW_ORD_STAT_PSP_SUSPENSION = 137,// # of times adapter suspended
+	IPW_ORD_STAT_PSP_SUSPENSION = 137,	// # of times adapter suspended
 	IPW_ORD_STAT_PSP_BCN_TIMEOUT,	// # of beacon timeout
 	IPW_ORD_STAT_PSP_POLL_TIMEOUT,	// # of poll response timeouts
-	IPW_ORD_STAT_PSP_NONDIR_TIMEOUT,// # of timeouts waiting for last broadcast/muticast pkt
+	IPW_ORD_STAT_PSP_NONDIR_TIMEOUT,	// # of timeouts waiting for last broadcast/muticast pkt
 	IPW_ORD_STAT_PSP_RX_DTIMS,	// # of PSP DTIMs received
 	IPW_ORD_STAT_PSP_RX_TIMS,	// # of PSP TIMs received
 	IPW_ORD_STAT_PSP_STATION_ID,	// PSP Station ID
 
 // Association and roaming
 	IPW_ORD_LAST_ASSN_TIME = 147,	// RTC time of last association
-	IPW_ORD_STAT_PERCENT_MISSED_BCNS,// current calculation of % missed beacons
+	IPW_ORD_STAT_PERCENT_MISSED_BCNS,	// current calculation of % missed beacons
 	IPW_ORD_STAT_PERCENT_RETRIES,	// current calculation of % missed tx retries
 	IPW_ORD_ASSOCIATED_AP_PTR,	// If associated, this is ptr to the associated
 	// AP table entry. set to 0 if not associated
@@ -1151,7 +1135,7 @@
 };
 
 struct ipw2100_fw_chunk_set {
-   	const void *data;
+	const void *data;
 	unsigned long size;
 };
 
@@ -1164,4 +1148,4 @@
 
 #define MAX_FW_VERSION_LEN 14
 
-#endif /* _IPW2100_H */
+#endif				/* _IPW2100_H */
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 3db0c32..b0d195d 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1,6 +1,6 @@
 /******************************************************************************
 
-  Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
 
   802.11 status code portion of this file from ethereal-0.10.6:
     Copyright 2000, Axis Communications AB
@@ -31,30 +31,103 @@
 ******************************************************************************/
 
 #include "ipw2200.h"
+#include <linux/version.h>
 
-#define IPW2200_VERSION "1.0.0"
+#define IPW2200_VERSION "git-1.0.8"
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2200/2915 Network Driver"
-#define DRV_COPYRIGHT	"Copyright(c) 2003-2004 Intel Corporation"
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2005 Intel Corporation"
 #define DRV_VERSION     IPW2200_VERSION
 
+#define ETH_P_80211_STATS (ETH_P_80211_RAW + 1)
+
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
+static int cmdlog = 0;
 static int debug = 0;
 static int channel = 0;
-static char *ifname;
 static int mode = 0;
 
 static u32 ipw_debug_level;
 static int associate = 1;
 static int auto_create = 1;
+static int led = 0;
 static int disable = 0;
+static int hwcrypto = 1;
 static const char ipw_modes[] = {
 	'a', 'b', 'g', '?'
 };
 
+#ifdef CONFIG_IPW_QOS
+static int qos_enable = 0;
+static int qos_burst_enable = 0;
+static int qos_no_ack_mask = 0;
+static int burst_duration_CCK = 0;
+static int burst_duration_OFDM = 0;
+
+static struct ieee80211_qos_parameters def_qos_parameters_OFDM = {
+	{QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM,
+	 QOS_TX3_CW_MIN_OFDM},
+	{QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM,
+	 QOS_TX3_CW_MAX_OFDM},
+	{QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
+	{QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
+	{QOS_TX0_TXOP_LIMIT_OFDM, QOS_TX1_TXOP_LIMIT_OFDM,
+	 QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM}
+};
+
+static struct ieee80211_qos_parameters def_qos_parameters_CCK = {
+	{QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK,
+	 QOS_TX3_CW_MIN_CCK},
+	{QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK,
+	 QOS_TX3_CW_MAX_CCK},
+	{QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
+	{QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
+	{QOS_TX0_TXOP_LIMIT_CCK, QOS_TX1_TXOP_LIMIT_CCK, QOS_TX2_TXOP_LIMIT_CCK,
+	 QOS_TX3_TXOP_LIMIT_CCK}
+};
+
+static struct ieee80211_qos_parameters def_parameters_OFDM = {
+	{DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM,
+	 DEF_TX3_CW_MIN_OFDM},
+	{DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM,
+	 DEF_TX3_CW_MAX_OFDM},
+	{DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
+	{DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
+	{DEF_TX0_TXOP_LIMIT_OFDM, DEF_TX1_TXOP_LIMIT_OFDM,
+	 DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM}
+};
+
+static struct ieee80211_qos_parameters def_parameters_CCK = {
+	{DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK,
+	 DEF_TX3_CW_MIN_CCK},
+	{DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK,
+	 DEF_TX3_CW_MAX_CCK},
+	{DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
+	{DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
+	{DEF_TX0_TXOP_LIMIT_CCK, DEF_TX1_TXOP_LIMIT_CCK, DEF_TX2_TXOP_LIMIT_CCK,
+	 DEF_TX3_TXOP_LIMIT_CCK}
+};
+
+static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
+
+static int from_priority_to_tx_queue[] = {
+	IPW_TX_QUEUE_1, IPW_TX_QUEUE_2, IPW_TX_QUEUE_2, IPW_TX_QUEUE_1,
+	IPW_TX_QUEUE_3, IPW_TX_QUEUE_3, IPW_TX_QUEUE_4, IPW_TX_QUEUE_4
+};
+
+static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv);
+
+static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters
+				       *qos_param);
+static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element
+				     *qos_param);
+#endif				/* CONFIG_IPW_QOS */
+
+static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev);
+static void ipw_remove_current_network(struct ipw_priv *priv);
 static void ipw_rx(struct ipw_priv *priv);
 static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
 				struct clx2_tx_queue *txq, int qindex);
@@ -68,42 +141,24 @@
 static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *);
 static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *);
 static void ipw_rx_queue_replenish(void *);
-
 static int ipw_up(struct ipw_priv *);
+static void ipw_bg_up(void *);
 static void ipw_down(struct ipw_priv *);
+static void ipw_bg_down(void *);
 static int ipw_config(struct ipw_priv *);
 static int init_supported_rates(struct ipw_priv *priv,
 				struct ipw_supported_rates *prates);
+static void ipw_set_hwcrypto_keys(struct ipw_priv *);
+static void ipw_send_wep_keys(struct ipw_priv *, int);
 
-static u8 band_b_active_channel[MAX_B_CHANNELS] = {
-	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0
-};
-static u8 band_a_active_channel[MAX_A_CHANNELS] = {
-	36, 40, 44, 48, 149, 153, 157, 161, 165, 52, 56, 60, 64, 0
-};
+static int ipw_is_valid_channel(struct ieee80211_device *, u8);
+static int ipw_channel_to_index(struct ieee80211_device *, u8);
+static u8 ipw_freq_to_channel(struct ieee80211_device *, u32);
+static int ipw_set_geo(struct ieee80211_device *, const struct ieee80211_geo *);
+static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *);
 
-static int is_valid_channel(int mode_mask, int channel)
-{
-	int i;
-
-	if (!channel)
-		return 0;
-
-	if (mode_mask & IEEE_A)
-		for (i = 0; i < MAX_A_CHANNELS; i++)
-			if (band_a_active_channel[i] == channel)
-				return IEEE_A;
-
-	if (mode_mask & (IEEE_B | IEEE_G))
-		for (i = 0; i < MAX_B_CHANNELS; i++)
-			if (band_b_active_channel[i] == channel)
-				return mode_mask & (IEEE_B | IEEE_G);
-
-	return 0;
-}
-
-static char *snprint_line(char *buf, size_t count,
-			  const u8 * data, u32 len, u32 ofs)
+static int snprint_line(char *buf, size_t count,
+			const u8 * data, u32 len, u32 ofs)
 {
 	int out, i, j, l;
 	char c;
@@ -134,7 +189,7 @@
 			out += snprintf(buf + out, count - out, " ");
 	}
 
-	return buf;
+	return out;
 }
 
 static void printk_buf(int level, const u8 * data, u32 len)
@@ -145,14 +200,33 @@
 		return;
 
 	while (len) {
-		printk(KERN_DEBUG "%s\n",
-		       snprint_line(line, sizeof(line), &data[ofs],
-				    min(len, 16U), ofs));
+		snprint_line(line, sizeof(line), &data[ofs],
+			     min(len, 16U), ofs);
+		printk(KERN_DEBUG "%s\n", line);
 		ofs += 16;
 		len -= min(len, 16U);
 	}
 }
 
+static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len)
+{
+	size_t out = size;
+	u32 ofs = 0;
+	int total = 0;
+
+	while (size && len) {
+		out = snprint_line(output, size, &data[ofs],
+				   min_t(size_t, len, 16U), ofs);
+
+		ofs += 16;
+		output += out;
+		size -= out;
+		len -= min_t(size_t, len, 16U);
+		total += out;
+	}
+	return total;
+}
+
 static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);
 #define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)
 
@@ -226,38 +300,42 @@
 #define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs)
 
 static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
-#define ipw_read_indirect(a, b, c, d) \
-	IPW_DEBUG_IO("%s %d: read_inddirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
-	_ipw_read_indirect(a, b, c, d)
+static inline void __ipw_read_indirect(const char *f, int l,
+				       struct ipw_priv *a, u32 b, u8 * c, int d)
+{
+	IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b),
+		     d);
+	_ipw_read_indirect(a, b, c, d);
+}
+
+#define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d)
 
 static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
 				int num);
 #define ipw_write_indirect(a, b, c, d) \
 	IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
-        _ipw_write_indirect(a, b, c, d)
+	_ipw_write_indirect(a, b, c, d)
 
 /* indirect write s */
 static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)
 {
 	IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value);
-	_ipw_write32(priv, CX2_INDIRECT_ADDR, reg);
-	_ipw_write32(priv, CX2_INDIRECT_DATA, value);
+	_ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
+	_ipw_write32(priv, IPW_INDIRECT_DATA, value);
 }
 
 static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value)
 {
 	IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
-	_ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
-	_ipw_write8(priv, CX2_INDIRECT_DATA, value);
-	IPW_DEBUG_IO(" reg = 0x%8lX : value = 0x%8X\n",
-		     (unsigned long)(priv->hw_base + CX2_INDIRECT_DATA), value);
+	_ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
+	_ipw_write8(priv, IPW_INDIRECT_DATA, value);
 }
 
 static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value)
 {
 	IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
-	_ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
-	_ipw_write16(priv, CX2_INDIRECT_DATA, value);
+	_ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
+	_ipw_write16(priv, IPW_INDIRECT_DATA, value);
 }
 
 /* indirect read s */
@@ -265,9 +343,9 @@
 static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
 {
 	u32 word;
-	_ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
+	_ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
 	IPW_DEBUG_IO(" reg = 0x%8X : \n", reg);
-	word = _ipw_read32(priv, CX2_INDIRECT_DATA);
+	word = _ipw_read32(priv, IPW_INDIRECT_DATA);
 	return (word >> ((reg & 0x3) * 8)) & 0xff;
 }
 
@@ -277,8 +355,8 @@
 
 	IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg);
 
-	_ipw_write32(priv, CX2_INDIRECT_ADDR, reg);
-	value = _ipw_read32(priv, CX2_INDIRECT_DATA);
+	_ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
+	value = _ipw_read32(priv, IPW_INDIRECT_DATA);
 	IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value);
 	return value;
 }
@@ -287,67 +365,69 @@
 static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
 			       int num)
 {
-	u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK;
+	u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK;
 	u32 dif_len = addr - aligned_addr;
-	u32 aligned_len;
 	u32 i;
 
 	IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
 
+	if (num <= 0) {
+		return;
+	}
+
 	/* Read the first nibble byte by byte */
 	if (unlikely(dif_len)) {
+		_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
 		/* Start reading at aligned_addr + dif_len */
-		_ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
-		for (i = dif_len; i < 4; i++, buf++)
-			*buf = _ipw_read8(priv, CX2_INDIRECT_DATA + i);
-		num -= dif_len;
+		for (i = dif_len; ((i < 4) && (num > 0)); i++, num--)
+			*buf++ = _ipw_read8(priv, IPW_INDIRECT_DATA + i);
 		aligned_addr += 4;
 	}
 
-	/* Read DWs through autoinc register */
-	_ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr);
-	aligned_len = num & CX2_INDIRECT_ADDR_MASK;
-	for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
-		*(u32 *) buf = ipw_read32(priv, CX2_AUTOINC_DATA);
+	_ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
+	for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
+		*(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA);
 
 	/* Copy the last nibble */
-	dif_len = num - aligned_len;
-	_ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
-	for (i = 0; i < dif_len; i++, buf++)
-		*buf = ipw_read8(priv, CX2_INDIRECT_DATA + i);
+	if (unlikely(num)) {
+		_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
+		for (i = 0; num > 0; i++, num--)
+			*buf++ = ipw_read8(priv, IPW_INDIRECT_DATA + i);
+	}
 }
 
 static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
 				int num)
 {
-	u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK;
+	u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK;
 	u32 dif_len = addr - aligned_addr;
-	u32 aligned_len;
 	u32 i;
 
 	IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
 
+	if (num <= 0) {
+		return;
+	}
+
 	/* Write the first nibble byte by byte */
 	if (unlikely(dif_len)) {
-		/* Start writing at aligned_addr + dif_len */
-		_ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
-		for (i = dif_len; i < 4; i++, buf++)
-			_ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf);
-		num -= dif_len;
+		_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
+		/* Start reading at aligned_addr + dif_len */
+		for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++)
+			_ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
 		aligned_addr += 4;
 	}
 
-	/* Write DWs through autoinc register */
-	_ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr);
-	aligned_len = num & CX2_INDIRECT_ADDR_MASK;
-	for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
-		_ipw_write32(priv, CX2_AUTOINC_DATA, *(u32 *) buf);
+	_ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
+	for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
+		_ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf);
 
 	/* Copy the last nibble */
-	dif_len = num - aligned_len;
-	_ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
-	for (i = 0; i < dif_len; i++, buf++)
-		_ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf);
+	if (unlikely(num)) {
+		_ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
+		for (i = 0; num > 0; i++, num--, buf++)
+			_ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
+	}
 }
 
 static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf,
@@ -371,7 +451,7 @@
 	if (priv->status & STATUS_INT_ENABLED)
 		return;
 	priv->status |= STATUS_INT_ENABLED;
-	ipw_write32(priv, CX2_INTA_MASK_R, CX2_INTA_MASK_ALL);
+	ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);
 }
 
 static inline void ipw_disable_interrupts(struct ipw_priv *priv)
@@ -379,9 +459,10 @@
 	if (!(priv->status & STATUS_INT_ENABLED))
 		return;
 	priv->status &= ~STATUS_INT_ENABLED;
-	ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+	ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
 }
 
+#ifdef CONFIG_IPW_DEBUG
 static char *ipw_error_desc(u32 val)
 {
 	switch (val) {
@@ -394,81 +475,65 @@
 	case IPW_FW_ERROR_MEMORY_OVERFLOW:
 		return "MEMORY_OVERFLOW";
 	case IPW_FW_ERROR_BAD_PARAM:
-		return "ERROR_BAD_PARAM";
+		return "BAD_PARAM";
 	case IPW_FW_ERROR_BAD_CHECKSUM:
-		return "ERROR_BAD_CHECKSUM";
+		return "BAD_CHECKSUM";
 	case IPW_FW_ERROR_NMI_INTERRUPT:
-		return "ERROR_NMI_INTERRUPT";
+		return "NMI_INTERRUPT";
 	case IPW_FW_ERROR_BAD_DATABASE:
-		return "ERROR_BAD_DATABASE";
+		return "BAD_DATABASE";
 	case IPW_FW_ERROR_ALLOC_FAIL:
-		return "ERROR_ALLOC_FAIL";
+		return "ALLOC_FAIL";
 	case IPW_FW_ERROR_DMA_UNDERRUN:
-		return "ERROR_DMA_UNDERRUN";
+		return "DMA_UNDERRUN";
 	case IPW_FW_ERROR_DMA_STATUS:
-		return "ERROR_DMA_STATUS";
-	case IPW_FW_ERROR_DINOSTATUS_ERROR:
-		return "ERROR_DINOSTATUS_ERROR";
-	case IPW_FW_ERROR_EEPROMSTATUS_ERROR:
-		return "ERROR_EEPROMSTATUS_ERROR";
+		return "DMA_STATUS";
+	case IPW_FW_ERROR_DINO_ERROR:
+		return "DINO_ERROR";
+	case IPW_FW_ERROR_EEPROM_ERROR:
+		return "EEPROM_ERROR";
 	case IPW_FW_ERROR_SYSASSERT:
-		return "ERROR_SYSASSERT";
+		return "SYSASSERT";
 	case IPW_FW_ERROR_FATAL_ERROR:
-		return "ERROR_FATALSTATUS_ERROR";
+		return "FATAL_ERROR";
 	default:
-		return "UNKNOWNSTATUS_ERROR";
+		return "UNKNOWN_ERROR";
 	}
 }
 
-static void ipw_dump_nic_error_log(struct ipw_priv *priv)
+static void ipw_dump_error_log(struct ipw_priv *priv,
+			       struct ipw_fw_error *error)
 {
-	u32 desc, time, blink1, blink2, ilink1, ilink2, idata, i, count, base;
+	u32 i;
 
-	base = ipw_read32(priv, IPWSTATUS_ERROR_LOG);
-	count = ipw_read_reg32(priv, base);
-
-	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
-		IPW_ERROR("Start IPW Error Log Dump:\n");
-		IPW_ERROR("Status: 0x%08X, Config: %08X\n",
-			  priv->status, priv->config);
+	if (!error) {
+		IPW_ERROR("Error allocating and capturing error log.  "
+			  "Nothing to dump.\n");
+		return;
 	}
 
-	for (i = ERROR_START_OFFSET;
-	     i <= count * ERROR_ELEM_SIZE; i += ERROR_ELEM_SIZE) {
-		desc = ipw_read_reg32(priv, base + i);
-		time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
-		blink1 = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));
-		blink2 = ipw_read_reg32(priv, base + i + 3 * sizeof(u32));
-		ilink1 = ipw_read_reg32(priv, base + i + 4 * sizeof(u32));
-		ilink2 = ipw_read_reg32(priv, base + i + 5 * sizeof(u32));
-		idata = ipw_read_reg32(priv, base + i + 6 * sizeof(u32));
+	IPW_ERROR("Start IPW Error Log Dump:\n");
+	IPW_ERROR("Status: 0x%08X, Config: %08X\n",
+		  error->status, error->config);
 
+	for (i = 0; i < error->elem_len; i++)
 		IPW_ERROR("%s %i 0x%08x  0x%08x  0x%08x  0x%08x  0x%08x\n",
-			  ipw_error_desc(desc), time, blink1, blink2,
-			  ilink1, ilink2, idata);
-	}
+			  ipw_error_desc(error->elem[i].desc),
+			  error->elem[i].time,
+			  error->elem[i].blink1,
+			  error->elem[i].blink2,
+			  error->elem[i].link1,
+			  error->elem[i].link2, error->elem[i].data);
+	for (i = 0; i < error->log_len; i++)
+		IPW_ERROR("%i\t0x%08x\t%i\n",
+			  error->log[i].time,
+			  error->log[i].data, error->log[i].event);
 }
-
-static void ipw_dump_nic_event_log(struct ipw_priv *priv)
-{
-	u32 ev, time, data, i, count, base;
-
-	base = ipw_read32(priv, IPW_EVENT_LOG);
-	count = ipw_read_reg32(priv, base);
-
-	if (EVENT_START_OFFSET <= count * EVENT_ELEM_SIZE)
-		IPW_ERROR("Start IPW Event Log Dump:\n");
-
-	for (i = EVENT_START_OFFSET;
-	     i <= count * EVENT_ELEM_SIZE; i += EVENT_ELEM_SIZE) {
-		ev = ipw_read_reg32(priv, base + i);
-		time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
-		data = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));
-
-#ifdef CONFIG_IPW_DEBUG
-		IPW_ERROR("%i\t0x%08x\t%i\n", time, data, ev);
 #endif
-	}
+
+static inline int ipw_is_init(struct ipw_priv *priv)
+{
+	return (priv->status & STATUS_INIT) ? 1 : 0;
 }
 
 static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len)
@@ -636,6 +701,340 @@
 
 }
 
+u32 ipw_register_toggle(u32 reg)
+{
+	reg &= ~IPW_START_STANDBY;
+	if (reg & IPW_GATE_ODMA)
+		reg &= ~IPW_GATE_ODMA;
+	if (reg & IPW_GATE_IDMA)
+		reg &= ~IPW_GATE_IDMA;
+	if (reg & IPW_GATE_ADMA)
+		reg &= ~IPW_GATE_ADMA;
+	return reg;
+}
+
+/*
+ * LED behavior:
+ * - On radio ON, turn on any LEDs that require to be on during start
+ * - On initialization, start unassociated blink
+ * - On association, disable unassociated blink
+ * - On disassociation, start unassociated blink
+ * - On radio OFF, turn off any LEDs started during radio on
+ *
+ */
+#define LD_TIME_LINK_ON 300
+#define LD_TIME_LINK_OFF 2700
+#define LD_TIME_ACT_ON 250
+
+void ipw_led_link_on(struct ipw_priv *priv)
+{
+	unsigned long flags;
+	u32 led;
+
+	/* If configured to not use LEDs, or nic_type is 1,
+	 * then we don't toggle a LINK led */
+	if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (!(priv->status & STATUS_RF_KILL_MASK) &&
+	    !(priv->status & STATUS_LED_LINK_ON)) {
+		IPW_DEBUG_LED("Link LED On\n");
+		led = ipw_read_reg32(priv, IPW_EVENT_REG);
+		led |= priv->led_association_on;
+
+		led = ipw_register_toggle(led);
+
+		IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+		ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+		priv->status |= STATUS_LED_LINK_ON;
+
+		/* If we aren't associated, schedule turning the LED off */
+		if (!(priv->status & STATUS_ASSOCIATED))
+			queue_delayed_work(priv->workqueue,
+					   &priv->led_link_off,
+					   LD_TIME_LINK_ON);
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void ipw_bg_led_link_on(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_led_link_on(data);
+	up(&priv->sem);
+}
+
+void ipw_led_link_off(struct ipw_priv *priv)
+{
+	unsigned long flags;
+	u32 led;
+
+	/* If configured not to use LEDs, or nic type is 1,
+	 * then we don't goggle the LINK led. */
+	if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->status & STATUS_LED_LINK_ON) {
+		led = ipw_read_reg32(priv, IPW_EVENT_REG);
+		led &= priv->led_association_off;
+		led = ipw_register_toggle(led);
+
+		IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+		ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+		IPW_DEBUG_LED("Link LED Off\n");
+
+		priv->status &= ~STATUS_LED_LINK_ON;
+
+		/* If we aren't associated and the radio is on, schedule
+		 * turning the LED on (blink while unassociated) */
+		if (!(priv->status & STATUS_RF_KILL_MASK) &&
+		    !(priv->status & STATUS_ASSOCIATED))
+			queue_delayed_work(priv->workqueue, &priv->led_link_on,
+					   LD_TIME_LINK_OFF);
+
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void ipw_bg_led_link_off(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_led_link_off(data);
+	up(&priv->sem);
+}
+
+static inline void __ipw_led_activity_on(struct ipw_priv *priv)
+{
+	u32 led;
+
+	if (priv->config & CFG_NO_LED)
+		return;
+
+	if (priv->status & STATUS_RF_KILL_MASK)
+		return;
+
+	if (!(priv->status & STATUS_LED_ACT_ON)) {
+		led = ipw_read_reg32(priv, IPW_EVENT_REG);
+		led |= priv->led_activity_on;
+
+		led = ipw_register_toggle(led);
+
+		IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+		ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+		IPW_DEBUG_LED("Activity LED On\n");
+
+		priv->status |= STATUS_LED_ACT_ON;
+
+		cancel_delayed_work(&priv->led_act_off);
+		queue_delayed_work(priv->workqueue, &priv->led_act_off,
+				   LD_TIME_ACT_ON);
+	} else {
+		/* Reschedule LED off for full time period */
+		cancel_delayed_work(&priv->led_act_off);
+		queue_delayed_work(priv->workqueue, &priv->led_act_off,
+				   LD_TIME_ACT_ON);
+	}
+}
+
+void ipw_led_activity_on(struct ipw_priv *priv)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&priv->lock, flags);
+	__ipw_led_activity_on(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void ipw_led_activity_off(struct ipw_priv *priv)
+{
+	unsigned long flags;
+	u32 led;
+
+	if (priv->config & CFG_NO_LED)
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->status & STATUS_LED_ACT_ON) {
+		led = ipw_read_reg32(priv, IPW_EVENT_REG);
+		led &= priv->led_activity_off;
+
+		led = ipw_register_toggle(led);
+
+		IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+		ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+		IPW_DEBUG_LED("Activity LED Off\n");
+
+		priv->status &= ~STATUS_LED_ACT_ON;
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void ipw_bg_led_activity_off(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_led_activity_off(data);
+	up(&priv->sem);
+}
+
+void ipw_led_band_on(struct ipw_priv *priv)
+{
+	unsigned long flags;
+	u32 led;
+
+	/* Only nic type 1 supports mode LEDs */
+	if (priv->config & CFG_NO_LED ||
+	    priv->nic_type != EEPROM_NIC_TYPE_1 || !priv->assoc_network)
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	led = ipw_read_reg32(priv, IPW_EVENT_REG);
+	if (priv->assoc_network->mode == IEEE_A) {
+		led |= priv->led_ofdm_on;
+		led &= priv->led_association_off;
+		IPW_DEBUG_LED("Mode LED On: 802.11a\n");
+	} else if (priv->assoc_network->mode == IEEE_G) {
+		led |= priv->led_ofdm_on;
+		led |= priv->led_association_on;
+		IPW_DEBUG_LED("Mode LED On: 802.11g\n");
+	} else {
+		led &= priv->led_ofdm_off;
+		led |= priv->led_association_on;
+		IPW_DEBUG_LED("Mode LED On: 802.11b\n");
+	}
+
+	led = ipw_register_toggle(led);
+
+	IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+	ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void ipw_led_band_off(struct ipw_priv *priv)
+{
+	unsigned long flags;
+	u32 led;
+
+	/* Only nic type 1 supports mode LEDs */
+	if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1)
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	led = ipw_read_reg32(priv, IPW_EVENT_REG);
+	led &= priv->led_ofdm_off;
+	led &= priv->led_association_off;
+
+	led = ipw_register_toggle(led);
+
+	IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+	ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void ipw_led_radio_on(struct ipw_priv *priv)
+{
+	ipw_led_link_on(priv);
+}
+
+void ipw_led_radio_off(struct ipw_priv *priv)
+{
+	ipw_led_activity_off(priv);
+	ipw_led_link_off(priv);
+}
+
+void ipw_led_link_up(struct ipw_priv *priv)
+{
+	/* Set the Link Led on for all nic types */
+	ipw_led_link_on(priv);
+}
+
+void ipw_led_link_down(struct ipw_priv *priv)
+{
+	ipw_led_activity_off(priv);
+	ipw_led_link_off(priv);
+
+	if (priv->status & STATUS_RF_KILL_MASK)
+		ipw_led_radio_off(priv);
+}
+
+void ipw_led_init(struct ipw_priv *priv)
+{
+	priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE];
+
+	/* Set the default PINs for the link and activity leds */
+	priv->led_activity_on = IPW_ACTIVITY_LED;
+	priv->led_activity_off = ~(IPW_ACTIVITY_LED);
+
+	priv->led_association_on = IPW_ASSOCIATED_LED;
+	priv->led_association_off = ~(IPW_ASSOCIATED_LED);
+
+	/* Set the default PINs for the OFDM leds */
+	priv->led_ofdm_on = IPW_OFDM_LED;
+	priv->led_ofdm_off = ~(IPW_OFDM_LED);
+
+	switch (priv->nic_type) {
+	case EEPROM_NIC_TYPE_1:
+		/* In this NIC type, the LEDs are reversed.... */
+		priv->led_activity_on = IPW_ASSOCIATED_LED;
+		priv->led_activity_off = ~(IPW_ASSOCIATED_LED);
+		priv->led_association_on = IPW_ACTIVITY_LED;
+		priv->led_association_off = ~(IPW_ACTIVITY_LED);
+
+		if (!(priv->config & CFG_NO_LED))
+			ipw_led_band_on(priv);
+
+		/* And we don't blink link LEDs for this nic, so
+		 * just return here */
+		return;
+
+	case EEPROM_NIC_TYPE_3:
+	case EEPROM_NIC_TYPE_2:
+	case EEPROM_NIC_TYPE_4:
+	case EEPROM_NIC_TYPE_0:
+		break;
+
+	default:
+		IPW_DEBUG_INFO("Unknown NIC type from EEPROM: %d\n",
+			       priv->nic_type);
+		priv->nic_type = EEPROM_NIC_TYPE_0;
+		break;
+	}
+
+	if (!(priv->config & CFG_NO_LED)) {
+		if (priv->status & STATUS_ASSOCIATED)
+			ipw_led_link_on(priv);
+		else
+			ipw_led_link_off(priv);
+	}
+}
+
+void ipw_led_shutdown(struct ipw_priv *priv)
+{
+	ipw_led_activity_off(priv);
+	ipw_led_link_off(priv);
+	ipw_led_band_off(priv);
+	cancel_delayed_work(&priv->led_link_on);
+	cancel_delayed_work(&priv->led_link_off);
+	cancel_delayed_work(&priv->led_act_off);
+}
+
 /*
  * The following adds a new attribute to the sysfs representation
  * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/)
@@ -647,8 +1046,9 @@
 {
 	return sprintf(buf, "0x%08X\n", ipw_debug_level);
 }
-static ssize_t store_debug_level(struct device_driver *d,
-				 const char *buf, size_t count)
+
+static ssize_t store_debug_level(struct device_driver *d, const char *buf,
+				 size_t count)
 {
 	char *p = (char *)buf;
 	u32 val;
@@ -672,6 +1072,237 @@
 static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
 		   show_debug_level, store_debug_level);
 
+static inline u32 ipw_get_event_log_len(struct ipw_priv *priv)
+{
+	return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG));
+}
+
+static void ipw_capture_event_log(struct ipw_priv *priv,
+				  u32 log_len, struct ipw_event *log)
+{
+	u32 base;
+
+	if (log_len) {
+		base = ipw_read32(priv, IPW_EVENT_LOG);
+		ipw_read_indirect(priv, base + sizeof(base) + sizeof(u32),
+				  (u8 *) log, sizeof(*log) * log_len);
+	}
+}
+
+static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
+{
+	struct ipw_fw_error *error;
+	u32 log_len = ipw_get_event_log_len(priv);
+	u32 base = ipw_read32(priv, IPW_ERROR_LOG);
+	u32 elem_len = ipw_read_reg32(priv, base);
+
+	error = kmalloc(sizeof(*error) +
+			sizeof(*error->elem) * elem_len +
+			sizeof(*error->log) * log_len, GFP_ATOMIC);
+	if (!error) {
+		IPW_ERROR("Memory allocation for firmware error log "
+			  "failed.\n");
+		return NULL;
+	}
+	error->jiffies = jiffies;
+	error->status = priv->status;
+	error->config = priv->config;
+	error->elem_len = elem_len;
+	error->log_len = log_len;
+	error->elem = (struct ipw_error_elem *)error->payload;
+	error->log = (struct ipw_event *)(error->elem +
+					  (sizeof(*error->elem) * elem_len));
+
+	ipw_capture_event_log(priv, log_len, error->log);
+
+	if (elem_len)
+		ipw_read_indirect(priv, base + sizeof(base), (u8 *) error->elem,
+				  sizeof(*error->elem) * elem_len);
+
+	return error;
+}
+
+static void ipw_free_error_log(struct ipw_fw_error *error)
+{
+	if (error)
+		kfree(error);
+}
+
+static ssize_t show_event_log(struct device *d,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+	u32 log_len = ipw_get_event_log_len(priv);
+	struct ipw_event log[log_len];
+	u32 len = 0, i;
+
+	ipw_capture_event_log(priv, log_len, log);
+
+	len += snprintf(buf + len, PAGE_SIZE - len, "%08X", log_len);
+	for (i = 0; i < log_len; i++)
+		len += snprintf(buf + len, PAGE_SIZE - len,
+				"\n%08X%08X%08X",
+				log[i].time, log[i].event, log[i].data);
+	len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+	return len;
+}
+
+static DEVICE_ATTR(event_log, S_IRUGO, show_event_log, NULL);
+
+static ssize_t show_error(struct device *d,
+			  struct device_attribute *attr, char *buf)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+	u32 len = 0, i;
+	if (!priv->error)
+		return 0;
+	len += snprintf(buf + len, PAGE_SIZE - len,
+			"%08lX%08X%08X%08X",
+			priv->error->jiffies,
+			priv->error->status,
+			priv->error->config, priv->error->elem_len);
+	for (i = 0; i < priv->error->elem_len; i++)
+		len += snprintf(buf + len, PAGE_SIZE - len,
+				"\n%08X%08X%08X%08X%08X%08X%08X",
+				priv->error->elem[i].time,
+				priv->error->elem[i].desc,
+				priv->error->elem[i].blink1,
+				priv->error->elem[i].blink2,
+				priv->error->elem[i].link1,
+				priv->error->elem[i].link2,
+				priv->error->elem[i].data);
+
+	len += snprintf(buf + len, PAGE_SIZE - len,
+			"\n%08X", priv->error->log_len);
+	for (i = 0; i < priv->error->log_len; i++)
+		len += snprintf(buf + len, PAGE_SIZE - len,
+				"\n%08X%08X%08X",
+				priv->error->log[i].time,
+				priv->error->log[i].event,
+				priv->error->log[i].data);
+	len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+	return len;
+}
+
+static ssize_t clear_error(struct device *d,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+	if (priv->error) {
+		ipw_free_error_log(priv->error);
+		priv->error = NULL;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error);
+
+static ssize_t show_cmd_log(struct device *d,
+			    struct device_attribute *attr, char *buf)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+	u32 len = 0, i;
+	if (!priv->cmdlog)
+		return 0;
+	for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len;
+	     (i != priv->cmdlog_pos) && (PAGE_SIZE - len);
+	     i = (i + 1) % priv->cmdlog_len) {
+		len +=
+		    snprintf(buf + len, PAGE_SIZE - len,
+			     "\n%08lX%08X%08X%08X\n", priv->cmdlog[i].jiffies,
+			     priv->cmdlog[i].retcode, priv->cmdlog[i].cmd.cmd,
+			     priv->cmdlog[i].cmd.len);
+		len +=
+		    snprintk_buf(buf + len, PAGE_SIZE - len,
+				 (u8 *) priv->cmdlog[i].cmd.param,
+				 priv->cmdlog[i].cmd.len);
+		len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+	}
+	len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+	return len;
+}
+
+static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL);
+
+static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
+			     char *buf)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+	return sprintf(buf, "%d\n", priv->ieee->scan_age);
+}
+
+static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+#ifdef CONFIG_IPW_DEBUG
+	struct net_device *dev = priv->net_dev;
+#endif
+	char buffer[] = "00000000";
+	unsigned long len =
+	    (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
+	unsigned long val;
+	char *p = buffer;
+
+	IPW_DEBUG_INFO("enter\n");
+
+	strncpy(buffer, buf, len);
+	buffer[len] = 0;
+
+	if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+		p++;
+		if (p[0] == 'x' || p[0] == 'X')
+			p++;
+		val = simple_strtoul(p, &p, 16);
+	} else
+		val = simple_strtoul(p, &p, 10);
+	if (p == buffer) {
+		IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
+	} else {
+		priv->ieee->scan_age = val;
+		IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
+	}
+
+	IPW_DEBUG_INFO("exit\n");
+	return len;
+}
+
+static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
+
+static ssize_t show_led(struct device *d, struct device_attribute *attr,
+			char *buf)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+	return sprintf(buf, "%d\n", (priv->config & CFG_NO_LED) ? 0 : 1);
+}
+
+static ssize_t store_led(struct device *d, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+
+	IPW_DEBUG_INFO("enter\n");
+
+	if (count == 0)
+		return 0;
+
+	if (*buf == 0) {
+		IPW_DEBUG_LED("Disabling LED control.\n");
+		priv->config |= CFG_NO_LED;
+		ipw_led_shutdown(priv);
+	} else {
+		IPW_DEBUG_LED("Enabling LED control.\n");
+		priv->config &= ~CFG_NO_LED;
+		ipw_led_init(priv);
+	}
+
+	IPW_DEBUG_INFO("exit\n");
+	return count;
+}
+
+static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led);
+
 static ssize_t show_status(struct device *d,
 			   struct device_attribute *attr, char *buf)
 {
@@ -693,55 +1324,12 @@
 static ssize_t show_nic_type(struct device *d,
 			     struct device_attribute *attr, char *buf)
 {
-	struct ipw_priv *p = d->driver_data;
-	u8 type = p->eeprom[EEPROM_NIC_TYPE];
-
-	switch (type) {
-	case EEPROM_NIC_TYPE_STANDARD:
-		return sprintf(buf, "STANDARD\n");
-	case EEPROM_NIC_TYPE_DELL:
-		return sprintf(buf, "DELL\n");
-	case EEPROM_NIC_TYPE_FUJITSU:
-		return sprintf(buf, "FUJITSU\n");
-	case EEPROM_NIC_TYPE_IBM:
-		return sprintf(buf, "IBM\n");
-	case EEPROM_NIC_TYPE_HP:
-		return sprintf(buf, "HP\n");
-	}
-
-	return sprintf(buf, "UNKNOWN\n");
+	struct ipw_priv *priv = d->driver_data;
+	return sprintf(buf, "TYPE: %d\n", priv->nic_type);
 }
 
 static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL);
 
-static ssize_t dump_error_log(struct device *d,
-			      struct device_attribute *attr, const char *buf,
-			      size_t count)
-{
-	char *p = (char *)buf;
-
-	if (p[0] == '1')
-		ipw_dump_nic_error_log((struct ipw_priv *)d->driver_data);
-
-	return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
-
-static ssize_t dump_event_log(struct device *d,
-			      struct device_attribute *attr, const char *buf,
-			      size_t count)
-{
-	char *p = (char *)buf;
-
-	if (p[0] == '1')
-		ipw_dump_nic_event_log((struct ipw_priv *)d->driver_data);
-
-	return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
-
 static ssize_t show_ucode_version(struct device *d,
 				  struct device_attribute *attr, char *buf)
 {
@@ -798,7 +1386,7 @@
 	u32 reg = 0;
 	struct ipw_priv *p = d->driver_data;
 
-	reg = ipw_read_reg32(p, CX2_INTERNAL_CMD_EVENT);
+	reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT);
 	return sprintf(buf, "0x%08x\n", reg);
 }
 static ssize_t store_command_event_reg(struct device *d,
@@ -809,7 +1397,7 @@
 	struct ipw_priv *p = d->driver_data;
 
 	sscanf(buf, "%x", &reg);
-	ipw_write_reg32(p, CX2_INTERNAL_CMD_EVENT, reg);
+	ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg);
 	return strnlen(buf, count);
 }
 
@@ -845,6 +1433,7 @@
 {
 	u32 reg = 0;
 	struct ipw_priv *priv = d->driver_data;
+
 	if (priv->status & STATUS_INDIRECT_DWORD)
 		reg = ipw_read_reg32(priv, priv->indirect_dword);
 	else
@@ -871,6 +1460,7 @@
 {
 	u8 reg = 0;
 	struct ipw_priv *priv = d->driver_data;
+
 	if (priv->status & STATUS_INDIRECT_BYTE)
 		reg = ipw_read_reg8(priv, priv->indirect_byte);
 	else
@@ -945,7 +1535,7 @@
 static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
 {
 	if ((disable_radio ? 1 : 0) ==
-	    (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
+	    ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0))
 		return 0;
 
 	IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO  %s\n",
@@ -954,10 +1544,8 @@
 	if (disable_radio) {
 		priv->status |= STATUS_RF_KILL_SW;
 
-		if (priv->workqueue) {
+		if (priv->workqueue)
 			cancel_delayed_work(&priv->request_scan);
-		}
-		wake_up_interruptible(&priv->wait_command_queue);
 		queue_work(priv->workqueue, &priv->down);
 	} else {
 		priv->status &= ~STATUS_RF_KILL_SW;
@@ -987,6 +1575,93 @@
 
 static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
 
+static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr,
+			       char *buf)
+{
+	struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;
+	int pos = 0, len = 0;
+	if (priv->config & CFG_SPEED_SCAN) {
+		while (priv->speed_scan[pos] != 0)
+			len += sprintf(&buf[len], "%d ",
+				       priv->speed_scan[pos++]);
+		return len + sprintf(&buf[len], "\n");
+	}
+
+	return sprintf(buf, "0\n");
+}
+
+static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;
+	int channel, pos = 0;
+	const char *p = buf;
+
+	/* list of space separated channels to scan, optionally ending with 0 */
+	while ((channel = simple_strtol(p, NULL, 0))) {
+		if (pos == MAX_SPEED_SCAN - 1) {
+			priv->speed_scan[pos] = 0;
+			break;
+		}
+
+		if (ipw_is_valid_channel(priv->ieee, channel))
+			priv->speed_scan[pos++] = channel;
+		else
+			IPW_WARNING("Skipping invalid channel request: %d\n",
+				    channel);
+		p = strchr(p, ' ');
+		if (!p)
+			break;
+		while (*p == ' ' || *p == '\t')
+			p++;
+	}
+
+	if (pos == 0)
+		priv->config &= ~CFG_SPEED_SCAN;
+	else {
+		priv->speed_scan_pos = 0;
+		priv->config |= CFG_SPEED_SCAN;
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan,
+		   store_speed_scan);
+
+static ssize_t show_net_stats(struct device *d, struct device_attribute *attr,
+			      char *buf)
+{
+	struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;
+	return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0');
+}
+
+static ssize_t store_net_stats(struct device *d, struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;
+	if (buf[0] == '1')
+		priv->config |= CFG_NET_STATS;
+	else
+		priv->config &= ~CFG_NET_STATS;
+
+	return count;
+}
+
+static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO,
+		   show_net_stats, store_net_stats);
+
+static void notify_wx_assoc_event(struct ipw_priv *priv)
+{
+	union iwreq_data wrqu;
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	if (priv->status & STATUS_ASSOCIATED)
+		memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
+	else
+		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+	wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+}
+
 static void ipw_irq_tasklet(struct ipw_priv *priv)
 {
 	u32 inta, inta_mask, handled = 0;
@@ -995,102 +1670,135 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	inta = ipw_read32(priv, CX2_INTA_RW);
-	inta_mask = ipw_read32(priv, CX2_INTA_MASK_R);
-	inta &= (CX2_INTA_MASK_ALL & inta_mask);
+	inta = ipw_read32(priv, IPW_INTA_RW);
+	inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
+	inta &= (IPW_INTA_MASK_ALL & inta_mask);
 
 	/* Add any cached INTA values that need to be handled */
 	inta |= priv->isr_inta;
 
 	/* handle all the justifications for the interrupt */
-	if (inta & CX2_INTA_BIT_RX_TRANSFER) {
+	if (inta & IPW_INTA_BIT_RX_TRANSFER) {
 		ipw_rx(priv);
-		handled |= CX2_INTA_BIT_RX_TRANSFER;
+		handled |= IPW_INTA_BIT_RX_TRANSFER;
 	}
 
-	if (inta & CX2_INTA_BIT_TX_CMD_QUEUE) {
+	if (inta & IPW_INTA_BIT_TX_CMD_QUEUE) {
 		IPW_DEBUG_HC("Command completed.\n");
 		rc = ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1);
 		priv->status &= ~STATUS_HCMD_ACTIVE;
 		wake_up_interruptible(&priv->wait_command_queue);
-		handled |= CX2_INTA_BIT_TX_CMD_QUEUE;
+		handled |= IPW_INTA_BIT_TX_CMD_QUEUE;
 	}
 
-	if (inta & CX2_INTA_BIT_TX_QUEUE_1) {
+	if (inta & IPW_INTA_BIT_TX_QUEUE_1) {
 		IPW_DEBUG_TX("TX_QUEUE_1\n");
 		rc = ipw_queue_tx_reclaim(priv, &priv->txq[0], 0);
-		handled |= CX2_INTA_BIT_TX_QUEUE_1;
+		handled |= IPW_INTA_BIT_TX_QUEUE_1;
 	}
 
-	if (inta & CX2_INTA_BIT_TX_QUEUE_2) {
+	if (inta & IPW_INTA_BIT_TX_QUEUE_2) {
 		IPW_DEBUG_TX("TX_QUEUE_2\n");
 		rc = ipw_queue_tx_reclaim(priv, &priv->txq[1], 1);
-		handled |= CX2_INTA_BIT_TX_QUEUE_2;
+		handled |= IPW_INTA_BIT_TX_QUEUE_2;
 	}
 
-	if (inta & CX2_INTA_BIT_TX_QUEUE_3) {
+	if (inta & IPW_INTA_BIT_TX_QUEUE_3) {
 		IPW_DEBUG_TX("TX_QUEUE_3\n");
 		rc = ipw_queue_tx_reclaim(priv, &priv->txq[2], 2);
-		handled |= CX2_INTA_BIT_TX_QUEUE_3;
+		handled |= IPW_INTA_BIT_TX_QUEUE_3;
 	}
 
-	if (inta & CX2_INTA_BIT_TX_QUEUE_4) {
+	if (inta & IPW_INTA_BIT_TX_QUEUE_4) {
 		IPW_DEBUG_TX("TX_QUEUE_4\n");
 		rc = ipw_queue_tx_reclaim(priv, &priv->txq[3], 3);
-		handled |= CX2_INTA_BIT_TX_QUEUE_4;
+		handled |= IPW_INTA_BIT_TX_QUEUE_4;
 	}
 
-	if (inta & CX2_INTA_BIT_STATUS_CHANGE) {
+	if (inta & IPW_INTA_BIT_STATUS_CHANGE) {
 		IPW_WARNING("STATUS_CHANGE\n");
-		handled |= CX2_INTA_BIT_STATUS_CHANGE;
+		handled |= IPW_INTA_BIT_STATUS_CHANGE;
 	}
 
-	if (inta & CX2_INTA_BIT_BEACON_PERIOD_EXPIRED) {
+	if (inta & IPW_INTA_BIT_BEACON_PERIOD_EXPIRED) {
 		IPW_WARNING("TX_PERIOD_EXPIRED\n");
-		handled |= CX2_INTA_BIT_BEACON_PERIOD_EXPIRED;
+		handled |= IPW_INTA_BIT_BEACON_PERIOD_EXPIRED;
 	}
 
-	if (inta & CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) {
+	if (inta & IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) {
 		IPW_WARNING("HOST_CMD_DONE\n");
-		handled |= CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE;
+		handled |= IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE;
 	}
 
-	if (inta & CX2_INTA_BIT_FW_INITIALIZATION_DONE) {
+	if (inta & IPW_INTA_BIT_FW_INITIALIZATION_DONE) {
 		IPW_WARNING("FW_INITIALIZATION_DONE\n");
-		handled |= CX2_INTA_BIT_FW_INITIALIZATION_DONE;
+		handled |= IPW_INTA_BIT_FW_INITIALIZATION_DONE;
 	}
 
-	if (inta & CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) {
+	if (inta & IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) {
 		IPW_WARNING("PHY_OFF_DONE\n");
-		handled |= CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE;
+		handled |= IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE;
 	}
 
-	if (inta & CX2_INTA_BIT_RF_KILL_DONE) {
+	if (inta & IPW_INTA_BIT_RF_KILL_DONE) {
 		IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
 		priv->status |= STATUS_RF_KILL_HW;
 		wake_up_interruptible(&priv->wait_command_queue);
-		netif_carrier_off(priv->net_dev);
-		netif_stop_queue(priv->net_dev);
+		priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
 		cancel_delayed_work(&priv->request_scan);
+		schedule_work(&priv->link_down);
 		queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
-		handled |= CX2_INTA_BIT_RF_KILL_DONE;
+		handled |= IPW_INTA_BIT_RF_KILL_DONE;
 	}
 
-	if (inta & CX2_INTA_BIT_FATAL_ERROR) {
+	if (inta & IPW_INTA_BIT_FATAL_ERROR) {
 		IPW_ERROR("Firmware error detected.  Restarting.\n");
+		if (priv->error) {
+			IPW_ERROR("Sysfs 'error' log already exists.\n");
 #ifdef CONFIG_IPW_DEBUG
-		if (ipw_debug_level & IPW_DL_FW_ERRORS) {
-			ipw_dump_nic_error_log(priv);
-			ipw_dump_nic_event_log(priv);
-		}
+			if (ipw_debug_level & IPW_DL_FW_ERRORS) {
+				struct ipw_fw_error *error =
+				    ipw_alloc_error_log(priv);
+				ipw_dump_error_log(priv, error);
+				if (error)
+					ipw_free_error_log(error);
+			}
 #endif
+		} else {
+			priv->error = ipw_alloc_error_log(priv);
+			if (priv->error)
+				IPW_ERROR("Sysfs 'error' log captured.\n");
+			else
+				IPW_ERROR("Error allocating sysfs 'error' "
+					  "log.\n");
+#ifdef CONFIG_IPW_DEBUG
+			if (ipw_debug_level & IPW_DL_FW_ERRORS)
+				ipw_dump_error_log(priv, priv->error);
+#endif
+		}
+
+		/* XXX: If hardware encryption is for WPA/WPA2,
+		 * we have to notify the supplicant. */
+		if (priv->ieee->sec.encrypt) {
+			priv->status &= ~STATUS_ASSOCIATED;
+			notify_wx_assoc_event(priv);
+		}
+
+		/* Keep the restart process from trying to send host
+		 * commands by clearing the INIT status bit */
+		priv->status &= ~STATUS_INIT;
+
+		/* Cancel currently queued command. */
+		priv->status &= ~STATUS_HCMD_ACTIVE;
+		wake_up_interruptible(&priv->wait_command_queue);
+
 		queue_work(priv->workqueue, &priv->adapter_restart);
-		handled |= CX2_INTA_BIT_FATAL_ERROR;
+		handled |= IPW_INTA_BIT_FATAL_ERROR;
 	}
 
-	if (inta & CX2_INTA_BIT_PARITY_ERROR) {
+	if (inta & IPW_INTA_BIT_PARITY_ERROR) {
 		IPW_ERROR("Parity error\n");
-		handled |= CX2_INTA_BIT_PARITY_ERROR;
+		handled |= IPW_INTA_BIT_PARITY_ERROR;
 	}
 
 	if (handled != inta) {
@@ -1103,7 +1811,6 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-#ifdef CONFIG_IPW_DEBUG
 #define IPW_CMD(x) case IPW_CMD_ ## x : return #x
 static char *get_cmd_string(u8 cmd)
 {
@@ -1162,44 +1869,78 @@
 		return "UNKNOWN";
 	}
 }
-#endif				/* CONFIG_IPW_DEBUG */
 
 #define HOST_COMPLETE_TIMEOUT HZ
 static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
 {
 	int rc = 0;
+	unsigned long flags;
 
+	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->status & STATUS_HCMD_ACTIVE) {
-		IPW_ERROR("Already sending a command\n");
-		return -1;
+		IPW_ERROR("Failed to send %s: Already sending a command.\n",
+			  get_cmd_string(cmd->cmd));
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return -EAGAIN;
 	}
 
 	priv->status |= STATUS_HCMD_ACTIVE;
 
-	IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
-		     get_cmd_string(cmd->cmd), cmd->cmd, cmd->len);
+	if (priv->cmdlog) {
+		priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies;
+		priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd;
+		priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len;
+		memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param,
+		       cmd->len);
+		priv->cmdlog[priv->cmdlog_pos].retcode = -1;
+	}
+
+	IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n",
+		     get_cmd_string(cmd->cmd), cmd->cmd, cmd->len,
+		     priv->status);
 	printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len);
 
 	rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0);
-	if (rc)
-		return rc;
+	if (rc) {
+		priv->status &= ~STATUS_HCMD_ACTIVE;
+		IPW_ERROR("Failed to send %s: Reason %d\n",
+			  get_cmd_string(cmd->cmd), rc);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		goto exit;
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	rc = wait_event_interruptible_timeout(priv->wait_command_queue,
 					      !(priv->
 						status & STATUS_HCMD_ACTIVE),
 					      HOST_COMPLETE_TIMEOUT);
 	if (rc == 0) {
-		IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
-			       jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
-		priv->status &= ~STATUS_HCMD_ACTIVE;
-		return -EIO;
-	}
-	if (priv->status & STATUS_RF_KILL_MASK) {
-		IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n");
-		return -EIO;
+		spin_lock_irqsave(&priv->lock, flags);
+		if (priv->status & STATUS_HCMD_ACTIVE) {
+			IPW_ERROR("Failed to send %s: Command timed out.\n",
+				  get_cmd_string(cmd->cmd));
+			priv->status &= ~STATUS_HCMD_ACTIVE;
+			spin_unlock_irqrestore(&priv->lock, flags);
+			rc = -EIO;
+			goto exit;
+		}
+		spin_unlock_irqrestore(&priv->lock, flags);
+	} else
+		rc = 0;
+
+	if (priv->status & STATUS_RF_KILL_HW) {
+		IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n",
+			  get_cmd_string(cmd->cmd));
+		rc = -EIO;
+		goto exit;
 	}
 
-	return 0;
+      exit:
+	if (priv->cmdlog) {
+		priv->cmdlog[priv->cmdlog_pos++].retcode = rc;
+		priv->cmdlog_pos %= priv->cmdlog_len;
+	}
+	return rc;
 }
 
 static int ipw_send_host_complete(struct ipw_priv *priv)
@@ -1214,12 +1955,7 @@
 		return -1;
 	}
 
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send HOST_COMPLETE command\n");
-		return -1;
-	}
-
-	return 0;
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_send_system_config(struct ipw_priv *priv,
@@ -1235,13 +1971,8 @@
 		return -1;
 	}
 
-	memcpy(&cmd.param, config, sizeof(*config));
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send SYSTEM_CONFIG command\n");
-		return -1;
-	}
-
-	return 0;
+	memcpy(cmd.param, config, sizeof(*config));
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
@@ -1256,13 +1987,8 @@
 		return -1;
 	}
 
-	memcpy(&cmd.param, ssid, cmd.len);
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send SSID command\n");
-		return -1;
-	}
-
-	return 0;
+	memcpy(cmd.param, ssid, cmd.len);
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
@@ -1280,16 +2006,15 @@
 	IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n",
 		       priv->net_dev->name, MAC_ARG(mac));
 
-	memcpy(&cmd.param, mac, ETH_ALEN);
-
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send ADAPTER_ADDRESS command\n");
-		return -1;
-	}
-
-	return 0;
+	memcpy(cmd.param, mac, ETH_ALEN);
+	return ipw_send_cmd(priv, &cmd);
 }
 
+/*
+ * NOTE: This must be executed from our workqueue as it results in udelay
+ * being called which may corrupt the keyboard if executed on default
+ * workqueue
+ */
 static void ipw_adapter_restart(void *adapter)
 {
 	struct ipw_priv *priv = adapter;
@@ -1298,12 +2023,25 @@
 		return;
 
 	ipw_down(priv);
+
+	if (priv->assoc_network &&
+	    (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS))
+		ipw_remove_current_network(priv);
+
 	if (ipw_up(priv)) {
 		IPW_ERROR("Failed to up device\n");
 		return;
 	}
 }
 
+static void ipw_bg_adapter_restart(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_adapter_restart(data);
+	up(&priv->sem);
+}
+
 #define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
 
 static void ipw_scan_check(void *data)
@@ -1313,10 +2051,18 @@
 		IPW_DEBUG_SCAN("Scan completion watchdog resetting "
 			       "adapter (%dms).\n",
 			       IPW_SCAN_CHECK_WATCHDOG / 100);
-		ipw_adapter_restart(priv);
+		queue_work(priv->workqueue, &priv->adapter_restart);
 	}
 }
 
+static void ipw_bg_scan_check(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_scan_check(data);
+	up(&priv->sem);
+}
+
 static int ipw_send_scan_request_ext(struct ipw_priv *priv,
 				     struct ipw_scan_request_ext *request)
 {
@@ -1325,20 +2071,8 @@
 		.len = sizeof(*request)
 	};
 
-	if (!priv || !request) {
-		IPW_ERROR("Invalid args\n");
-		return -1;
-	}
-
-	memcpy(&cmd.param, request, sizeof(*request));
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n");
-		return -1;
-	}
-
-	queue_delayed_work(priv->workqueue, &priv->scan_check,
-			   IPW_SCAN_CHECK_WATCHDOG);
-	return 0;
+	memcpy(cmd.param, request, sizeof(*request));
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_send_scan_abort(struct ipw_priv *priv)
@@ -1353,12 +2087,7 @@
 		return -1;
 	}
 
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send SCAN_ABORT command\n");
-		return -1;
-	}
-
-	return 0;
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
@@ -1370,12 +2099,7 @@
 	struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *)
 	    &cmd.param;
 	calib->beacon_rssi_raw = sens;
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send SENSITIVITY CALIB command\n");
-		return -1;
-	}
-
-	return 0;
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_send_associate(struct ipw_priv *priv,
@@ -1386,18 +2110,26 @@
 		.len = sizeof(*associate)
 	};
 
+	struct ipw_associate tmp_associate;
+	memcpy(&tmp_associate, associate, sizeof(*associate));
+	tmp_associate.policy_support =
+	    cpu_to_le16(tmp_associate.policy_support);
+	tmp_associate.assoc_tsf_msw = cpu_to_le32(tmp_associate.assoc_tsf_msw);
+	tmp_associate.assoc_tsf_lsw = cpu_to_le32(tmp_associate.assoc_tsf_lsw);
+	tmp_associate.capability = cpu_to_le16(tmp_associate.capability);
+	tmp_associate.listen_interval =
+	    cpu_to_le16(tmp_associate.listen_interval);
+	tmp_associate.beacon_interval =
+	    cpu_to_le16(tmp_associate.beacon_interval);
+	tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window);
+
 	if (!priv || !associate) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	memcpy(&cmd.param, associate, sizeof(*associate));
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send ASSOCIATE command\n");
-		return -1;
-	}
-
-	return 0;
+	memcpy(cmd.param, &tmp_associate, sizeof(*associate));
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_send_supported_rates(struct ipw_priv *priv,
@@ -1413,13 +2145,8 @@
 		return -1;
 	}
 
-	memcpy(&cmd.param, rates, sizeof(*rates));
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send SUPPORTED_RATES command\n");
-		return -1;
-	}
-
-	return 0;
+	memcpy(cmd.param, rates, sizeof(*rates));
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_set_random_seed(struct ipw_priv *priv)
@@ -1436,15 +2163,9 @@
 
 	get_random_bytes(&cmd.param, sizeof(u32));
 
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send SEED_NUMBER command\n");
-		return -1;
-	}
-
-	return 0;
+	return ipw_send_cmd(priv, &cmd);
 }
 
-#if 0
 static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
 {
 	struct host_cmd cmd = {
@@ -1459,14 +2180,8 @@
 
 	*((u32 *) & cmd.param) = phy_off;
 
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send CARD_DISABLE command\n");
-		return -1;
-	}
-
-	return 0;
+	return ipw_send_cmd(priv, &cmd);
 }
-#endif
 
 static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
 {
@@ -1480,12 +2195,51 @@
 		return -1;
 	}
 
-	memcpy(&cmd.param, power, sizeof(*power));
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send TX_POWER command\n");
-		return -1;
-	}
+	memcpy(cmd.param, power, sizeof(*power));
+	return ipw_send_cmd(priv, &cmd);
+}
 
+static int ipw_set_tx_power(struct ipw_priv *priv)
+{
+	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+	struct ipw_tx_power tx_power;
+	s8 max_power;
+	int i;
+
+	memset(&tx_power, 0, sizeof(tx_power));
+
+	/* configure device for 'G' band */
+	tx_power.ieee_mode = IPW_G_MODE;
+	tx_power.num_channels = geo->bg_channels;
+	for (i = 0; i < geo->bg_channels; i++) {
+		max_power = geo->bg[i].max_power;
+		tx_power.channels_tx_power[i].channel_number =
+		    geo->bg[i].channel;
+		tx_power.channels_tx_power[i].tx_power = max_power ?
+		    min(max_power, priv->tx_power) : priv->tx_power;
+	}
+	if (ipw_send_tx_power(priv, &tx_power))
+		return -EIO;
+
+	/* configure device to also handle 'B' band */
+	tx_power.ieee_mode = IPW_B_MODE;
+	if (ipw_send_tx_power(priv, &tx_power))
+		return -EIO;
+
+	/* configure device to also handle 'A' band */
+	if (priv->ieee->abg_true) {
+		tx_power.ieee_mode = IPW_A_MODE;
+		tx_power.num_channels = geo->a_channels;
+		for (i = 0; i < tx_power.num_channels; i++) {
+			max_power = geo->a[i].max_power;
+			tx_power.channels_tx_power[i].channel_number =
+			    geo->a[i].channel;
+			tx_power.channels_tx_power[i].tx_power = max_power ?
+			    min(max_power, priv->tx_power) : priv->tx_power;
+		}
+		if (ipw_send_tx_power(priv, &tx_power))
+			return -EIO;
+	}
 	return 0;
 }
 
@@ -1504,13 +2258,8 @@
 		return -1;
 	}
 
-	memcpy(&cmd.param, &rts_threshold, sizeof(rts_threshold));
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send RTS_THRESHOLD command\n");
-		return -1;
-	}
-
-	return 0;
+	memcpy(cmd.param, &rts_threshold, sizeof(rts_threshold));
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
@@ -1528,13 +2277,8 @@
 		return -1;
 	}
 
-	memcpy(&cmd.param, &frag_threshold, sizeof(frag_threshold));
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send FRAG_THRESHOLD command\n");
-		return -1;
-	}
-
-	return 0;
+	memcpy(cmd.param, &frag_threshold, sizeof(frag_threshold));
+	return ipw_send_cmd(priv, &cmd);
 }
 
 static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
@@ -1564,12 +2308,27 @@
 		break;
 	}
 
-	if (ipw_send_cmd(priv, &cmd)) {
-		IPW_ERROR("failed to send POWER_MODE command\n");
+	return ipw_send_cmd(priv, &cmd);
+}
+
+static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit)
+{
+	struct ipw_retry_limit retry_limit = {
+		.short_retry_limit = slimit,
+		.long_retry_limit = llimit
+	};
+	struct host_cmd cmd = {
+		.cmd = IPW_CMD_RETRY_LIMIT,
+		.len = sizeof(retry_limit)
+	};
+
+	if (!priv) {
+		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	return 0;
+	memcpy(cmd.param, &retry_limit, sizeof(retry_limit));
+	return ipw_send_cmd(priv, &cmd);
 }
 
 /*
@@ -1671,8 +2430,7 @@
 /* data's copy of the eeprom data                                 */
 static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
 {
-	u8 *ee = (u8 *) priv->eeprom;
-	memcpy(mac, &ee[EEPROM_MAC_ADDRESS], 6);
+	memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6);
 }
 
 /*
@@ -1692,7 +2450,7 @@
 
 	/* read entire contents of eeprom into private buffer */
 	for (i = 0; i < 128; i++)
-		eeprom[i] = eeprom_read_u16(priv, (u8) i);
+		eeprom[i] = le16_to_cpu(eeprom_read_u16(priv, (u8) i));
 
 	/*
 	   If the data looks correct, then copy it to our private
@@ -1703,7 +2461,7 @@
 		IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n");
 
 		/* write the eeprom data to sram */
-		for (i = 0; i < CX2_EEPROM_IMAGE_SIZE; i++)
+		for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++)
 			ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]);
 
 		/* Do not load eeprom data on fatal error or suspend */
@@ -1723,14 +2481,14 @@
 	count >>= 2;
 	if (!count)
 		return;
-	_ipw_write32(priv, CX2_AUTOINC_ADDR, start);
+	_ipw_write32(priv, IPW_AUTOINC_ADDR, start);
 	while (count--)
-		_ipw_write32(priv, CX2_AUTOINC_DATA, 0);
+		_ipw_write32(priv, IPW_AUTOINC_DATA, 0);
 }
 
 static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv)
 {
-	ipw_zero_memory(priv, CX2_SHARED_SRAM_DMA_CONTROL,
+	ipw_zero_memory(priv, IPW_SHARED_SRAM_DMA_CONTROL,
 			CB_NUMBER_OF_ELEMENTS_SMALL *
 			sizeof(struct command_block));
 }
@@ -1744,7 +2502,7 @@
 	ipw_fw_dma_reset_command_blocks(priv);
 
 	/* Write CB base address */
-	ipw_write_reg32(priv, CX2_DMA_I_CB_BASE, CX2_SHARED_SRAM_DMA_CONTROL);
+	ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL);
 
 	IPW_DEBUG_FW("<< : \n");
 	return 0;
@@ -1758,7 +2516,7 @@
 
 	//set the Stop and Abort bit
 	control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
-	ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control);
+	ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
 	priv->sram_desc.last_cb_index = 0;
 
 	IPW_DEBUG_FW("<< \n");
@@ -1768,7 +2526,7 @@
 					  struct command_block *cb)
 {
 	u32 address =
-	    CX2_SHARED_SRAM_DMA_CONTROL +
+	    IPW_SHARED_SRAM_DMA_CONTROL +
 	    (sizeof(struct command_block) * index);
 	IPW_DEBUG_FW(">> :\n");
 
@@ -1792,13 +2550,13 @@
 					       &priv->sram_desc.cb_list[index]);
 
 	/* Enable the DMA in the CSR register */
-	ipw_clear_bit(priv, CX2_RESET_REG,
-		      CX2_RESET_REG_MASTER_DISABLED |
-		      CX2_RESET_REG_STOP_MASTER);
+	ipw_clear_bit(priv, IPW_RESET_REG,
+		      IPW_RESET_REG_MASTER_DISABLED |
+		      IPW_RESET_REG_STOP_MASTER);
 
 	/* Set the Start bit. */
 	control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START;
-	ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control);
+	ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
 
 	IPW_DEBUG_FW("<< :\n");
 	return 0;
@@ -1811,12 +2569,12 @@
 	u32 cb_fields_address = 0;
 
 	IPW_DEBUG_FW(">> :\n");
-	address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB);
+	address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
 	IPW_DEBUG_FW_INFO("Current CB is 0x%x \n", address);
 
 	/* Read the DMA Controlor register */
-	register_value = ipw_read_reg32(priv, CX2_DMA_I_DMA_CONTROL);
-	IPW_DEBUG_FW_INFO("CX2_DMA_I_DMA_CONTROL is 0x%x \n", register_value);
+	register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL);
+	IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x \n", register_value);
 
 	/* Print the CB values */
 	cb_fields_address = address;
@@ -1845,9 +2603,9 @@
 	u32 current_cb_index = 0;
 
 	IPW_DEBUG_FW("<< :\n");
-	current_cb_address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB);
+	current_cb_address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
 
-	current_cb_index = (current_cb_address - CX2_SHARED_SRAM_DMA_CONTROL) /
+	current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) /
 	    sizeof(struct command_block);
 
 	IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n",
@@ -1976,8 +2734,8 @@
 	ipw_fw_dma_abort(priv);
 
 	/*Disable the DMA in the CSR register */
-	ipw_set_bit(priv, CX2_RESET_REG,
-		    CX2_RESET_REG_MASTER_DISABLED | CX2_RESET_REG_STOP_MASTER);
+	ipw_set_bit(priv, IPW_RESET_REG,
+		    IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER);
 
 	IPW_DEBUG_FW("<< dmaWaitSync \n");
 	return 0;
@@ -1987,6 +2745,9 @@
 {
 	struct list_head *element, *safe;
 	struct ieee80211_network *network = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->ieee->lock, flags);
 	list_for_each_safe(element, safe, &priv->ieee->network_list) {
 		network = list_entry(element, struct ieee80211_network, list);
 		if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
@@ -1995,6 +2756,7 @@
 				      &priv->ieee->network_free_list);
 		}
 	}
+	spin_unlock_irqrestore(&priv->ieee->lock, flags);
 }
 
 /**
@@ -2037,10 +2799,10 @@
 
 	IPW_DEBUG_TRACE(">> \n");
 	/* stop master. typical delay - 0 */
-	ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER);
+	ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
 
-	rc = ipw_poll_bit(priv, CX2_RESET_REG,
-			  CX2_RESET_REG_MASTER_DISABLED, 100);
+	rc = ipw_poll_bit(priv, IPW_RESET_REG,
+			  IPW_RESET_REG_MASTER_DISABLED, 100);
 	if (rc < 0) {
 		IPW_ERROR("stop master failed in 10ms\n");
 		return -1;
@@ -2056,7 +2818,7 @@
 	IPW_DEBUG_TRACE(">> \n");
 	mdelay(5);
 
-	ipw_clear_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
+	ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
 
 	/* no one knows timing, for safety add some delay */
 	mdelay(5);
@@ -2073,13 +2835,12 @@
 };
 
 #define IPW_FW_MAJOR_VERSION 2
-#define IPW_FW_MINOR_VERSION 2
+#define IPW_FW_MINOR_VERSION 4
 
 #define IPW_FW_MINOR(x) ((x & 0xff) >> 8)
 #define IPW_FW_MAJOR(x) (x & 0xff)
 
-#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | \
-                         IPW_FW_MAJOR_VERSION)
+#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | IPW_FW_MAJOR_VERSION)
 
 #define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \
 "." __stringify(IPW_FW_MINOR_VERSION) "-"
@@ -2107,8 +2868,8 @@
 
 //      spin_lock_irqsave(&priv->lock, flags);
 
-	for (addr = CX2_SHARED_LOWER_BOUND;
-	     addr < CX2_REGISTER_DOMAIN1_END; addr += 4) {
+	for (addr = IPW_SHARED_LOWER_BOUND;
+	     addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
 		ipw_write32(priv, addr, 0);
 	}
 
@@ -2117,16 +2878,16 @@
 	/* destroy DMA queues */
 	/* reset sequence */
 
-	ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_ON);
+	ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_ON);
 	ipw_arc_release(priv);
-	ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_OFF);
+	ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_OFF);
 	mdelay(1);
 
 	/* reset PHY */
-	ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, CX2_BASEBAND_POWER_DOWN);
+	ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, IPW_BASEBAND_POWER_DOWN);
 	mdelay(1);
 
-	ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, 0);
+	ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, 0);
 	mdelay(1);
 
 	/* enable ucode store */
@@ -2144,18 +2905,19 @@
 	 */
 	/* load new ipw uCode */
 	for (i = 0; i < len / 2; i++)
-		ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, image[i]);
+		ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE,
+				cpu_to_le16(image[i]));
 
 	/* enable DINO */
-	ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0);
-	ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM);
+	ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
+	ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM);
 
 	/* this is where the igx / win driver deveates from the VAP driver. */
 
 	/* wait for alive response */
 	for (i = 0; i < 100; i++) {
 		/* poll for incoming data */
-		cr = ipw_read_reg8(priv, CX2_BASEBAND_CONTROL_STATUS);
+		cr = ipw_read_reg8(priv, IPW_BASEBAND_CONTROL_STATUS);
 		if (cr & DINO_RXFIFO_DATA)
 			break;
 		mdelay(1);
@@ -2167,7 +2929,8 @@
 
 		for (i = 0; i < ARRAY_SIZE(response_buffer); i++)
 			response_buffer[i] =
-			    ipw_read_reg32(priv, CX2_BASEBAND_RX_FIFO_READ);
+			    le32_to_cpu(ipw_read_reg32(priv,
+						       IPW_BASEBAND_RX_FIFO_READ));
 		memcpy(&priv->dino_alive, response_buffer,
 		       sizeof(priv->dino_alive));
 		if (priv->dino_alive.alive_command == 1
@@ -2196,7 +2959,7 @@
 
 	/* disable DINO, otherwise for some reason
 	   firmware have problem getting alive resp. */
-	ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0);
+	ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
 
 //      spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -2236,13 +2999,14 @@
 		 * offeset*/
 		/* Dma loading */
 		rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset,
-					   chunk->address, chunk->length);
+					   le32_to_cpu(chunk->address),
+					   le32_to_cpu(chunk->length));
 		if (rc) {
 			IPW_DEBUG_INFO("dmaAddBuffer Failed\n");
 			goto out;
 		}
 
-		offset += chunk->length;
+		offset += le32_to_cpu(chunk->length);
 	} while (offset < len);
 
 	/* Run the DMA and wait for the answer */
@@ -2268,16 +3032,16 @@
 	int rc = 0;
 
 	/* stop */
-	ipw_write32(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER);
+	ipw_write32(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
 
-	rc = ipw_poll_bit(priv, CX2_RESET_REG,
-			  CX2_RESET_REG_MASTER_DISABLED, 500);
+	rc = ipw_poll_bit(priv, IPW_RESET_REG,
+			  IPW_RESET_REG_MASTER_DISABLED, 500);
 	if (rc < 0) {
 		IPW_ERROR("wait for reg master disabled failed\n");
 		return rc;
 	}
 
-	ipw_set_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
+	ipw_set_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
 
 	return rc;
 }
@@ -2287,14 +3051,14 @@
 	IPW_DEBUG_TRACE(">>\n");
 
 	/* prvHwStartNic  release ARC */
-	ipw_clear_bit(priv, CX2_RESET_REG,
-		      CX2_RESET_REG_MASTER_DISABLED |
-		      CX2_RESET_REG_STOP_MASTER |
+	ipw_clear_bit(priv, IPW_RESET_REG,
+		      IPW_RESET_REG_MASTER_DISABLED |
+		      IPW_RESET_REG_STOP_MASTER |
 		      CBD_RESET_REG_PRINCETON_RESET);
 
 	/* enable power management */
-	ipw_set_bit(priv, CX2_GP_CNTRL_RW,
-		    CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
+	ipw_set_bit(priv, IPW_GP_CNTRL_RW,
+		    IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
 
 	IPW_DEBUG_TRACE("<<\n");
 }
@@ -2307,25 +3071,25 @@
 	/* reset */
 	/*prvHwInitNic */
 	/* set "initialization complete" bit to move adapter to D0 state */
-	ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE);
+	ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
 
 	/* low-level PLL activation */
-	ipw_write32(priv, CX2_READ_INT_REGISTER,
-		    CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER);
+	ipw_write32(priv, IPW_READ_INT_REGISTER,
+		    IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER);
 
 	/* wait for clock stabilization */
-	rc = ipw_poll_bit(priv, CX2_GP_CNTRL_RW,
-			  CX2_GP_CNTRL_BIT_CLOCK_READY, 250);
+	rc = ipw_poll_bit(priv, IPW_GP_CNTRL_RW,
+			  IPW_GP_CNTRL_BIT_CLOCK_READY, 250);
 	if (rc < 0)
 		IPW_DEBUG_INFO("FAILED wait for clock stablization\n");
 
 	/* assert SW reset */
-	ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_SW_RESET);
+	ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_SW_RESET);
 
 	udelay(10);
 
 	/* set "initialization complete" bit to move adapter to D0 state */
-	ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE);
+	ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
 
 	IPW_DEBUG_TRACE(">>\n");
 	return 0;
@@ -2337,14 +3101,19 @@
 static int ipw_reset_nic(struct ipw_priv *priv)
 {
 	int rc = 0;
+	unsigned long flags;
 
 	IPW_DEBUG_TRACE(">>\n");
 
 	rc = ipw_init_nic(priv);
 
+	spin_lock_irqsave(&priv->lock, flags);
 	/* Clear the 'host command active' bit... */
 	priv->status &= ~STATUS_HCMD_ACTIVE;
 	wake_up_interruptible(&priv->wait_command_queue);
+	priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
+	wake_up_interruptible(&priv->wait_state);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	IPW_DEBUG_TRACE("<<\n");
 	return rc;
@@ -2364,22 +3133,23 @@
 	}
 
 	header = (struct fw_header *)(*fw)->data;
-	if (IPW_FW_MAJOR(header->version) != IPW_FW_MAJOR_VERSION) {
+	if (IPW_FW_MAJOR(le32_to_cpu(header->version)) != IPW_FW_MAJOR_VERSION) {
 		IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n",
 			  name,
-			  IPW_FW_MAJOR(header->version), IPW_FW_MAJOR_VERSION);
+			  IPW_FW_MAJOR(le32_to_cpu(header->version)),
+			  IPW_FW_MAJOR_VERSION);
 		return -EINVAL;
 	}
 
 	IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n",
 		       name,
-		       IPW_FW_MAJOR(header->version),
-		       IPW_FW_MINOR(header->version),
+		       IPW_FW_MAJOR(le32_to_cpu(header->version)),
+		       IPW_FW_MINOR(le32_to_cpu(header->version)),
 		       (*fw)->size - sizeof(struct fw_header));
 	return 0;
 }
 
-#define CX2_RX_BUF_SIZE (3000)
+#define IPW_RX_BUF_SIZE (3000)
 
 static inline void ipw_rx_queue_reset(struct ipw_priv *priv,
 				      struct ipw_rx_queue *rxq)
@@ -2398,8 +3168,9 @@
 		 * to an SKB, so we need to unmap and free potential storage */
 		if (rxq->pool[i].skb != NULL) {
 			pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
-					 CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+					 IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(rxq->pool[i].skb);
+			rxq->pool[i].skb = NULL;
 		}
 		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
 	}
@@ -2417,6 +3188,19 @@
 static const struct firmware *bootfw = NULL;
 static const struct firmware *firmware = NULL;
 static const struct firmware *ucode = NULL;
+
+static void free_firmware(void)
+{
+	if (fw_loaded) {
+		release_firmware(bootfw);
+		release_firmware(ucode);
+		release_firmware(firmware);
+		bootfw = ucode = firmware = NULL;
+		fw_loaded = 0;
+	}
+}
+#else
+#define free_firmware() do {} while (0)
 #endif
 
 static int ipw_load(struct ipw_priv *priv)
@@ -2445,10 +3229,10 @@
 			rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss"));
 			break;
 
-#ifdef CONFIG_IPW_PROMISC
+#ifdef CONFIG_IPW2200_MONITOR
 		case IW_MODE_MONITOR:
 			rc = ipw_get_fw(priv, &ucode,
-					IPW_FW_NAME("ibss_ucode"));
+					IPW_FW_NAME("sniffer_ucode"));
 			if (rc)
 				goto error;
 
@@ -2487,11 +3271,11 @@
 
       retry:
 	/* Ensure interrupts are disabled */
-	ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+	ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
 	priv->status &= ~STATUS_INT_ENABLED;
 
 	/* ack pending interrupts */
-	ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL);
+	ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
 
 	ipw_stop_nic(priv);
 
@@ -2501,14 +3285,14 @@
 		goto error;
 	}
 
-	ipw_zero_memory(priv, CX2_NIC_SRAM_LOWER_BOUND,
-			CX2_NIC_SRAM_UPPER_BOUND - CX2_NIC_SRAM_LOWER_BOUND);
+	ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND,
+			IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND);
 
 	/* DMA the initial boot firmware into the device */
 	rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header),
 			       bootfw->size - sizeof(struct fw_header));
 	if (rc < 0) {
-		IPW_ERROR("Unable to load boot firmware\n");
+		IPW_ERROR("Unable to load boot firmware: %d\n", rc);
 		goto error;
 	}
 
@@ -2516,8 +3300,8 @@
 	ipw_start_nic(priv);
 
 	/* wait for the device to finish it's initial startup sequence */
-	rc = ipw_poll_bit(priv, CX2_INTA_RW,
-			  CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500);
+	rc = ipw_poll_bit(priv, IPW_INTA_RW,
+			  IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
 	if (rc < 0) {
 		IPW_ERROR("device failed to boot initial fw image\n");
 		goto error;
@@ -2525,13 +3309,13 @@
 	IPW_DEBUG_INFO("initial device response after %dms\n", rc);
 
 	/* ack fw init done interrupt */
-	ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE);
+	ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
 
 	/* DMA the ucode into the device */
 	rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header),
 			    ucode->size - sizeof(struct fw_header));
 	if (rc < 0) {
-		IPW_ERROR("Unable to load ucode\n");
+		IPW_ERROR("Unable to load ucode: %d\n", rc);
 		goto error;
 	}
 
@@ -2543,7 +3327,7 @@
 			       sizeof(struct fw_header),
 			       firmware->size - sizeof(struct fw_header));
 	if (rc < 0) {
-		IPW_ERROR("Unable to load firmware\n");
+		IPW_ERROR("Unable to load firmware: %d\n", rc);
 		goto error;
 	}
 
@@ -2556,12 +3340,14 @@
 	}
 
 	/* Ensure interrupts are disabled */
-	ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+	ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
+	/* ack pending interrupts */
+	ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
 
 	/* kick start the device */
 	ipw_start_nic(priv);
 
-	if (ipw_read32(priv, CX2_INTA_RW) & CX2_INTA_BIT_PARITY_ERROR) {
+	if (ipw_read32(priv, IPW_INTA_RW) & IPW_INTA_BIT_PARITY_ERROR) {
 		if (retries > 0) {
 			IPW_WARNING("Parity error.  Retrying init.\n");
 			retries--;
@@ -2574,8 +3360,8 @@
 	}
 
 	/* wait for the device */
-	rc = ipw_poll_bit(priv, CX2_INTA_RW,
-			  CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500);
+	rc = ipw_poll_bit(priv, IPW_INTA_RW,
+			  IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
 	if (rc < 0) {
 		IPW_ERROR("device failed to start after 500ms\n");
 		goto error;
@@ -2583,7 +3369,7 @@
 	IPW_DEBUG_INFO("device response after %dms\n", rc);
 
 	/* ack fw init done interrupt */
-	ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE);
+	ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
 
 	/* read eeprom data and initialize the eeprom region of sram */
 	priv->eeprom_delay = 1;
@@ -2595,10 +3381,10 @@
 	/* Ensure our queue has valid packets */
 	ipw_rx_queue_replenish(priv);
 
-	ipw_write32(priv, CX2_RX_READ_INDEX, priv->rxq->read);
+	ipw_write32(priv, IPW_RX_READ_INDEX, priv->rxq->read);
 
 	/* ack pending interrupts */
-	ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL);
+	ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
 
 #ifndef CONFIG_PM
 	release_firmware(bootfw);
@@ -2755,16 +3541,18 @@
 		return;
 
 	/* sanity check */
-	if (bd->u.data.num_chunks > NUM_TFD_CHUNKS) {
-		IPW_ERROR("Too many chunks: %i\n", bd->u.data.num_chunks);
+	if (le32_to_cpu(bd->u.data.num_chunks) > NUM_TFD_CHUNKS) {
+		IPW_ERROR("Too many chunks: %i\n",
+			  le32_to_cpu(bd->u.data.num_chunks));
 		/** @todo issue fatal error, it is quite serious situation */
 		return;
 	}
 
 	/* unmap chunks if any */
-	for (i = 0; i < bd->u.data.num_chunks; i++) {
-		pci_unmap_single(dev, bd->u.data.chunk_ptr[i],
-				 bd->u.data.chunk_len[i], PCI_DMA_TODEVICE);
+	for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) {
+		pci_unmap_single(dev, le32_to_cpu(bd->u.data.chunk_ptr[i]),
+				 le16_to_cpu(bd->u.data.chunk_len[i]),
+				 PCI_DMA_TODEVICE);
 		if (txq->txb[txq->q.last_used]) {
 			ieee80211_txb_free(txq->txb[txq->q.last_used]);
 			txq->txb[txq->q.last_used] = NULL;
@@ -2821,21 +3609,6 @@
 	ipw_queue_tx_free(priv, &priv->txq[3]);
 }
 
-static void inline __maybe_wake_tx(struct ipw_priv *priv)
-{
-	if (netif_running(priv->net_dev)) {
-		switch (priv->port_type) {
-		case DCR_TYPE_MU_BSS:
-		case DCR_TYPE_MU_IBSS:
-			if (!(priv->status & STATUS_ASSOCIATED)) {
-				return;
-			}
-		}
-		netif_wake_queue(priv->net_dev);
-	}
-
-}
-
 static inline void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
 {
 	/* First 3 bytes are manufacturer */
@@ -2898,7 +3671,13 @@
 {
 	int err;
 
-	if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))) {
+	if (priv->status & STATUS_ASSOCIATING) {
+		IPW_DEBUG_ASSOC("Disassociating while associating.\n");
+		queue_work(priv->workqueue, &priv->disassociate);
+		return;
+	}
+
+	if (!(priv->status & STATUS_ASSOCIATED)) {
 		IPW_DEBUG_ASSOC("Disassociating while not associated.\n");
 		return;
 	}
@@ -2915,6 +3694,7 @@
 		priv->assoc_request.assoc_type = HC_DISASSOC_QUIET;
 	else
 		priv->assoc_request.assoc_type = HC_DISASSOCIATE;
+
 	err = ipw_send_associate(priv, &priv->assoc_request);
 	if (err) {
 		IPW_DEBUG_HC("Attempt to send [dis]associate command "
@@ -2924,20 +3704,27 @@
 
 }
 
-static void ipw_disassociate(void *data)
+static int ipw_disassociate(void *data)
 {
+	struct ipw_priv *priv = data;
+	if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
+		return 0;
 	ipw_send_disassociate(data, 0);
+	return 1;
 }
 
-static void notify_wx_assoc_event(struct ipw_priv *priv)
+static void ipw_bg_disassociate(void *data)
 {
-	union iwreq_data wrqu;
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-	if (priv->status & STATUS_ASSOCIATED)
-		memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
-	else
-		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
-	wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_disassociate(data);
+	up(&priv->sem);
+}
+
+static void ipw_system_config(void *data)
+{
+	struct ipw_priv *priv = data;
+	ipw_send_system_config(priv, &priv->sys_config);
 }
 
 struct ipw_status_code {
@@ -2997,7 +3784,7 @@
 {
 	int i;
 	for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++)
-		if (ipw_status_codes[i].status == status)
+		if (ipw_status_codes[i].status == (status & 0xff))
 			return ipw_status_codes[i].reason;
 	return "Unknown status value.";
 }
@@ -3076,18 +3863,30 @@
 	while (i && !(mask & i))
 		i >>= 1;
 	switch (i) {
-	case IEEE80211_CCK_RATE_1MB_MASK:	return 1000000;
-	case IEEE80211_CCK_RATE_2MB_MASK:	return 2000000;
-	case IEEE80211_CCK_RATE_5MB_MASK:	return 5500000;
-	case IEEE80211_OFDM_RATE_6MB_MASK:	return 6000000;
-	case IEEE80211_OFDM_RATE_9MB_MASK:	return 9000000;
-	case IEEE80211_CCK_RATE_11MB_MASK:	return 11000000;
-	case IEEE80211_OFDM_RATE_12MB_MASK:	return 12000000;
-	case IEEE80211_OFDM_RATE_18MB_MASK:	return 18000000;
-	case IEEE80211_OFDM_RATE_24MB_MASK:	return 24000000;
-	case IEEE80211_OFDM_RATE_36MB_MASK:	return 36000000;
-	case IEEE80211_OFDM_RATE_48MB_MASK:	return 48000000;
-	case IEEE80211_OFDM_RATE_54MB_MASK:	return 54000000;
+	case IEEE80211_CCK_RATE_1MB_MASK:
+		return 1000000;
+	case IEEE80211_CCK_RATE_2MB_MASK:
+		return 2000000;
+	case IEEE80211_CCK_RATE_5MB_MASK:
+		return 5500000;
+	case IEEE80211_OFDM_RATE_6MB_MASK:
+		return 6000000;
+	case IEEE80211_OFDM_RATE_9MB_MASK:
+		return 9000000;
+	case IEEE80211_CCK_RATE_11MB_MASK:
+		return 11000000;
+	case IEEE80211_OFDM_RATE_12MB_MASK:
+		return 12000000;
+	case IEEE80211_OFDM_RATE_18MB_MASK:
+		return 18000000;
+	case IEEE80211_OFDM_RATE_24MB_MASK:
+		return 24000000;
+	case IEEE80211_OFDM_RATE_36MB_MASK:
+		return 36000000;
+	case IEEE80211_OFDM_RATE_48MB_MASK:
+		return 48000000;
+	case IEEE80211_OFDM_RATE_54MB_MASK:
+		return 54000000;
 	}
 
 	if (priv->ieee->mode == IEEE_B)
@@ -3115,25 +3914,35 @@
 		return ipw_get_max_rate(priv);
 
 	switch (rate) {
-	case IPW_TX_RATE_1MB:	return 1000000;
-	case IPW_TX_RATE_2MB:	return 2000000;
-	case IPW_TX_RATE_5MB:	return 5500000;
-	case IPW_TX_RATE_6MB:	return 6000000;
-	case IPW_TX_RATE_9MB:	return 9000000;
-	case IPW_TX_RATE_11MB:	return 11000000;
-	case IPW_TX_RATE_12MB:	return 12000000;
-	case IPW_TX_RATE_18MB:	return 18000000;
-	case IPW_TX_RATE_24MB:	return 24000000;
-	case IPW_TX_RATE_36MB:	return 36000000;
-	case IPW_TX_RATE_48MB:	return 48000000;
-	case IPW_TX_RATE_54MB:	return 54000000;
+	case IPW_TX_RATE_1MB:
+		return 1000000;
+	case IPW_TX_RATE_2MB:
+		return 2000000;
+	case IPW_TX_RATE_5MB:
+		return 5500000;
+	case IPW_TX_RATE_6MB:
+		return 6000000;
+	case IPW_TX_RATE_9MB:
+		return 9000000;
+	case IPW_TX_RATE_11MB:
+		return 11000000;
+	case IPW_TX_RATE_12MB:
+		return 12000000;
+	case IPW_TX_RATE_18MB:
+		return 18000000;
+	case IPW_TX_RATE_24MB:
+		return 24000000;
+	case IPW_TX_RATE_36MB:
+		return 36000000;
+	case IPW_TX_RATE_48MB:
+		return 48000000;
+	case IPW_TX_RATE_54MB:
+		return 54000000;
 	}
 
 	return 0;
 }
 
-#define PERFECT_RSSI (-50)
-#define WORST_RSSI   (-85)
 #define IPW_STATS_INTERVAL (2 * HZ)
 static void ipw_gather_stats(struct ipw_priv *priv)
 {
@@ -3145,6 +3954,7 @@
 	s16 rssi;
 	u32 beacon_quality, signal_quality, tx_quality, rx_quality,
 	    rate_quality;
+	u32 max_rate;
 
 	if (!(priv->status & STATUS_ASSOCIATED)) {
 		priv->quality = 0;
@@ -3201,7 +4011,8 @@
 			beacon_quality, missed_beacons_percent);
 
 	priv->last_rate = ipw_get_current_rate(priv);
-	rate_quality = priv->last_rate * 40 / priv->last_rate + 60;
+	max_rate = ipw_get_max_rate(priv);
+	rate_quality = priv->last_rate * 40 / max_rate + 60;
 	IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n",
 			rate_quality, priv->last_rate / 1000000);
 
@@ -3222,13 +4033,20 @@
 			tx_quality, tx_failures_delta, tx_packets_delta);
 
 	rssi = average_value(&priv->average_rssi);
-	if (rssi > PERFECT_RSSI)
+	signal_quality =
+	    (100 *
+	     (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
+	     (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) -
+	     (priv->ieee->perfect_rssi - rssi) *
+	     (15 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) +
+	      62 * (priv->ieee->perfect_rssi - rssi))) /
+	    ((priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
+	     (priv->ieee->perfect_rssi - priv->ieee->worst_rssi));
+	if (signal_quality > 100)
 		signal_quality = 100;
-	else if (rssi < WORST_RSSI)
+	else if (signal_quality < 1)
 		signal_quality = 0;
-	else
-		signal_quality = (rssi - WORST_RSSI) * 100 /
-		    (PERFECT_RSSI - WORST_RSSI);
+
 	IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n",
 			signal_quality, rssi);
 
@@ -3257,6 +4075,85 @@
 			   IPW_STATS_INTERVAL);
 }
 
+static void ipw_bg_gather_stats(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_gather_stats(data);
+	up(&priv->sem);
+}
+
+/* Missed beacon behavior:
+ * 1st missed -> roaming_threshold, just wait, don't do any scan/roam.
+ * roaming_threshold -> disassociate_threshold, scan and roam for better signal.
+ * Above disassociate threshold, give up and stop scanning.
+ * Roaming is disabled if disassociate_threshold <= roaming_threshold  */
+static inline void ipw_handle_missed_beacon(struct ipw_priv *priv,
+					    int missed_count)
+{
+	priv->notif_missed_beacons = missed_count;
+
+	if (missed_count > priv->disassociate_threshold &&
+	    priv->status & STATUS_ASSOCIATED) {
+		/* If associated and we've hit the missed
+		 * beacon threshold, disassociate, turn
+		 * off roaming, and abort any active scans */
+		IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
+			  IPW_DL_STATE | IPW_DL_ASSOC,
+			  "Missed beacon: %d - disassociate\n", missed_count);
+		priv->status &= ~STATUS_ROAMING;
+		if (priv->status & STATUS_SCANNING) {
+			IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
+				  IPW_DL_STATE,
+				  "Aborting scan with missed beacon.\n");
+			queue_work(priv->workqueue, &priv->abort_scan);
+		}
+
+		queue_work(priv->workqueue, &priv->disassociate);
+		return;
+	}
+
+	if (priv->status & STATUS_ROAMING) {
+		/* If we are currently roaming, then just
+		 * print a debug statement... */
+		IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+			  "Missed beacon: %d - roam in progress\n",
+			  missed_count);
+		return;
+	}
+
+	if (missed_count > priv->roaming_threshold &&
+	    missed_count <= priv->disassociate_threshold) {
+		/* If we are not already roaming, set the ROAM
+		 * bit in the status and kick off a scan.
+		 * This can happen several times before we reach
+		 * disassociate_threshold. */
+		IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+			  "Missed beacon: %d - initiate "
+			  "roaming\n", missed_count);
+		if (!(priv->status & STATUS_ROAMING)) {
+			priv->status |= STATUS_ROAMING;
+			if (!(priv->status & STATUS_SCANNING))
+				queue_work(priv->workqueue,
+					   &priv->request_scan);
+		}
+		return;
+	}
+
+	if (priv->status & STATUS_SCANNING) {
+		/* Stop scan to keep fw from getting
+		 * stuck (only if we aren't roaming --
+		 * otherwise we'll never scan more than 2 or 3
+		 * channels..) */
+		IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | IPW_DL_STATE,
+			  "Aborting scan with missed beacon.\n");
+		queue_work(priv->workqueue, &priv->abort_scan);
+	}
+
+	IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
+
+}
+
 /**
  * Handle host notification packet.
  * Called from interrupt routine
@@ -3264,6 +4161,8 @@
 static inline void ipw_rx_notification(struct ipw_priv *priv,
 				       struct ipw_rx_notification *notif)
 {
+	notif->size = le16_to_cpu(notif->size);
+
 	IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size);
 
 	switch (notif->subtype) {
@@ -3307,30 +4206,44 @@
 
 					priv->status &= ~STATUS_ASSOCIATING;
 					priv->status |= STATUS_ASSOCIATED;
+					queue_work(priv->workqueue,
+						   &priv->system_config);
 
-					netif_carrier_on(priv->net_dev);
-					if (netif_queue_stopped(priv->net_dev)) {
-						IPW_DEBUG_NOTIF
-						    ("waking queue\n");
-						netif_wake_queue(priv->net_dev);
-					} else {
-						IPW_DEBUG_NOTIF
-						    ("starting queue\n");
-						netif_start_queue(priv->
-								  net_dev);
+#ifdef CONFIG_IPW_QOS
+#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
+			 le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl))
+					if ((priv->status & STATUS_AUTH) &&
+					    (IPW_GET_PACKET_STYPE(&notif->u.raw)
+					     == IEEE80211_STYPE_ASSOC_RESP)) {
+						if ((sizeof
+						     (struct
+						      ieee80211_assoc_response)
+						     <= notif->size)
+						    && (notif->size <= 2314)) {
+							struct
+							ieee80211_rx_stats
+							    stats = {
+								.len =
+								    notif->
+								    size - 1,
+							};
+
+							IPW_DEBUG_QOS
+							    ("QoS Associate "
+							     "size %d\n",
+							     notif->size);
+							ieee80211_rx_mgt(priv->
+									 ieee,
+									 (struct
+									  ieee80211_hdr_4addr
+									  *)
+									 &notif->u.raw, &stats);
+						}
 					}
+#endif
 
-					ipw_reset_stats(priv);
-					/* Ensure the rate is updated immediately */
-					priv->last_rate =
-					    ipw_get_current_rate(priv);
-					schedule_work(&priv->gather_stats);
-					notify_wx_assoc_event(priv);
+					schedule_work(&priv->link_up);
 
-/*			queue_delayed_work(priv->workqueue,
-					   &priv->request_scan,
-					   SCAN_ASSOCIATED_INTERVAL);
-*/
 					break;
 				}
 
@@ -3363,12 +4276,7 @@
 						      STATUS_AUTH |
 						      STATUS_ASSOCIATED);
 
-						netif_carrier_off(priv->
-								  net_dev);
-						netif_stop_queue(priv->net_dev);
-						queue_work(priv->workqueue,
-							   &priv->request_scan);
-						notify_wx_assoc_event(priv);
+						schedule_work(&priv->link_down);
 						break;
 					}
 
@@ -3383,6 +4291,24 @@
 				}
 
 			case CMAS_INIT:{
+					if (priv->status & STATUS_AUTH) {
+						struct
+						    ieee80211_assoc_response
+						*resp;
+						resp =
+						    (struct
+						     ieee80211_assoc_response
+						     *)&notif->u.raw;
+						IPW_DEBUG(IPW_DL_NOTIF |
+							  IPW_DL_STATE |
+							  IPW_DL_ASSOC,
+							  "association failed (0x%04X): %s\n",
+							  ntohs(resp->status),
+							  ipw_get_status_code
+							  (ntohs
+							   (resp->status)));
+					}
+
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
 						  "disassociated: '%s' " MAC_FMT
@@ -3395,35 +4321,21 @@
 					    ~(STATUS_DISASSOCIATING |
 					      STATUS_ASSOCIATING |
 					      STATUS_ASSOCIATED | STATUS_AUTH);
+					if (priv->assoc_network
+					    && (priv->assoc_network->
+						capability &
+						WLAN_CAPABILITY_IBSS))
+						ipw_remove_current_network
+						    (priv);
 
-					netif_stop_queue(priv->net_dev);
-					if (!(priv->status & STATUS_ROAMING)) {
-						netif_carrier_off(priv->
-								  net_dev);
-						notify_wx_assoc_event(priv);
+					schedule_work(&priv->link_down);
 
-						/* Cancel any queued work ... */
-						cancel_delayed_work(&priv->
-								    request_scan);
-						cancel_delayed_work(&priv->
-								    adhoc_check);
-
-						/* Queue up another scan... */
-						queue_work(priv->workqueue,
-							   &priv->request_scan);
-
-						cancel_delayed_work(&priv->
-								    gather_stats);
-					} else {
-						priv->status |= STATUS_ROAMING;
-						queue_work(priv->workqueue,
-							   &priv->request_scan);
-					}
-
-					ipw_reset_stats(priv);
 					break;
 				}
 
+			case CMAS_RX_ASSOC_RESP:
+				break;
+
 			default:
 				IPW_ERROR("assoc: unknown (%d)\n",
 					  assoc->state);
@@ -3466,11 +4378,7 @@
 						  STATUS_AUTH |
 						  STATUS_ASSOCIATED);
 
-				netif_carrier_off(priv->net_dev);
-				netif_stop_queue(priv->net_dev);
-				queue_work(priv->workqueue,
-					   &priv->request_scan);
-				notify_wx_assoc_event(priv);
+				schedule_work(&priv->link_down);
 				break;
 
 			case CMAS_TX_AUTH_SEQ_1:
@@ -3512,6 +4420,7 @@
 			case CMAS_RX_ASSOC_RESP:
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 					  IPW_DL_ASSOC, "RX_ASSOC_RESP\n");
+
 				break;
 			case CMAS_ASSOCIATED:
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
@@ -3556,43 +4465,67 @@
 			priv->status &=
 			    ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
 
+			wake_up_interruptible(&priv->wait_state);
 			cancel_delayed_work(&priv->scan_check);
 
+			if (priv->status & STATUS_EXIT_PENDING)
+				break;
+
+			priv->ieee->scans++;
+
+#ifdef CONFIG_IPW2200_MONITOR
+			if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+				priv->status |= STATUS_SCAN_FORCED;
+				queue_work(priv->workqueue,
+					   &priv->request_scan);
+				break;
+			}
+			priv->status &= ~STATUS_SCAN_FORCED;
+#endif				/* CONFIG_IPW2200_MONITOR */
+
 			if (!(priv->status & (STATUS_ASSOCIATED |
 					      STATUS_ASSOCIATING |
 					      STATUS_ROAMING |
 					      STATUS_DISASSOCIATING)))
 				queue_work(priv->workqueue, &priv->associate);
 			else if (priv->status & STATUS_ROAMING) {
-				/* If a scan completed and we are in roam mode, then
-				 * the scan that completed was the one requested as a
-				 * result of entering roam... so, schedule the
-				 * roam work */
-				queue_work(priv->workqueue, &priv->roam);
+				if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
+					/* If a scan completed and we are in roam mode, then
+					 * the scan that completed was the one requested as a
+					 * result of entering roam... so, schedule the
+					 * roam work */
+					queue_work(priv->workqueue,
+						   &priv->roam);
+				else
+					/* Don't schedule if we aborted the scan */
+					priv->status &= ~STATUS_ROAMING;
 			} else if (priv->status & STATUS_SCAN_PENDING)
 				queue_work(priv->workqueue,
 					   &priv->request_scan);
-
-			priv->ieee->scans++;
+			else if (priv->config & CFG_BACKGROUND_SCAN
+				 && priv->status & STATUS_ASSOCIATED)
+				queue_delayed_work(priv->workqueue,
+						   &priv->request_scan, HZ);
 			break;
 		}
 
 	case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{
 			struct notif_frag_length *x = &notif->u.frag_len;
 
-			if (notif->size == sizeof(*x)) {
-				IPW_ERROR("Frag length: %d\n", x->frag_length);
-			} else {
+			if (notif->size == sizeof(*x))
+				IPW_ERROR("Frag length: %d\n",
+					  le16_to_cpu(x->frag_length));
+			else
 				IPW_ERROR("Frag length of wrong size %d "
 					  "(should be %zd)\n",
 					  notif->size, sizeof(*x));
-			}
 			break;
 		}
 
 	case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{
 			struct notif_link_deterioration *x =
 			    &notif->u.link_deterioration;
+
 			if (notif->size == sizeof(*x)) {
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
 					  "link deterioration: '%s' " MAC_FMT
@@ -3612,11 +4545,9 @@
 	case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{
 			IPW_ERROR("Dino config\n");
 			if (priv->hcmd
-			    && priv->hcmd->cmd == HOST_CMD_DINO_CONFIG) {
-				/* TODO: Do anything special? */
-			} else {
+			    && priv->hcmd->cmd != HOST_CMD_DINO_CONFIG)
 				IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n");
-			}
+
 			break;
 		}
 
@@ -3629,36 +4560,11 @@
 				break;
 			}
 
-			if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) {
-				if (priv->status & STATUS_SCANNING) {
-					/* Stop scan to keep fw from getting
-					 * stuck... */
-					queue_work(priv->workqueue,
-						   &priv->abort_scan);
-				}
-
-				if (x->number > priv->missed_beacon_threshold &&
-				    priv->status & STATUS_ASSOCIATED) {
-					IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
-						  IPW_DL_STATE,
-						  "Missed beacon: %d - disassociate\n",
-						  x->number);
-					queue_work(priv->workqueue,
-						   &priv->disassociate);
-				} else if (x->number > priv->roaming_threshold) {
-					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
-						  "Missed beacon: %d - initiate "
-						  "roaming\n", x->number);
-					queue_work(priv->workqueue,
-						   &priv->roam);
-				} else {
-					IPW_DEBUG_NOTIF("Missed beacon: %d\n",
-							x->number);
-				}
-
-				priv->notif_missed_beacons = x->number;
-
-			}
+			if (le32_to_cpu(x->state) ==
+			    HOST_NOTIFICATION_STATUS_BEACON_MISSING)
+				ipw_handle_missed_beacon(priv,
+							 le32_to_cpu(x->
+								     number));
 
 			break;
 		}
@@ -3697,7 +4603,8 @@
 	case HOST_NOTIFICATION_NOISE_STATS:{
 			if (notif->size == sizeof(u32)) {
 				priv->last_noise =
-				    (u8) (notif->u.noise.value & 0xff);
+				    (u8) (le32_to_cpu(notif->u.noise.value) &
+					  0xff);
 				average_add(&priv->average_noise,
 					    priv->last_noise);
 				break;
@@ -3730,43 +4637,43 @@
 	ipw_tx_queue_free(priv);
 	/* Tx CMD queue */
 	rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd,
-			       CX2_TX_CMD_QUEUE_READ_INDEX,
-			       CX2_TX_CMD_QUEUE_WRITE_INDEX,
-			       CX2_TX_CMD_QUEUE_BD_BASE,
-			       CX2_TX_CMD_QUEUE_BD_SIZE);
+			       IPW_TX_CMD_QUEUE_READ_INDEX,
+			       IPW_TX_CMD_QUEUE_WRITE_INDEX,
+			       IPW_TX_CMD_QUEUE_BD_BASE,
+			       IPW_TX_CMD_QUEUE_BD_SIZE);
 	if (rc) {
 		IPW_ERROR("Tx Cmd queue init failed\n");
 		goto error;
 	}
 	/* Tx queue(s) */
 	rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx,
-			       CX2_TX_QUEUE_0_READ_INDEX,
-			       CX2_TX_QUEUE_0_WRITE_INDEX,
-			       CX2_TX_QUEUE_0_BD_BASE, CX2_TX_QUEUE_0_BD_SIZE);
+			       IPW_TX_QUEUE_0_READ_INDEX,
+			       IPW_TX_QUEUE_0_WRITE_INDEX,
+			       IPW_TX_QUEUE_0_BD_BASE, IPW_TX_QUEUE_0_BD_SIZE);
 	if (rc) {
 		IPW_ERROR("Tx 0 queue init failed\n");
 		goto error;
 	}
 	rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx,
-			       CX2_TX_QUEUE_1_READ_INDEX,
-			       CX2_TX_QUEUE_1_WRITE_INDEX,
-			       CX2_TX_QUEUE_1_BD_BASE, CX2_TX_QUEUE_1_BD_SIZE);
+			       IPW_TX_QUEUE_1_READ_INDEX,
+			       IPW_TX_QUEUE_1_WRITE_INDEX,
+			       IPW_TX_QUEUE_1_BD_BASE, IPW_TX_QUEUE_1_BD_SIZE);
 	if (rc) {
 		IPW_ERROR("Tx 1 queue init failed\n");
 		goto error;
 	}
 	rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx,
-			       CX2_TX_QUEUE_2_READ_INDEX,
-			       CX2_TX_QUEUE_2_WRITE_INDEX,
-			       CX2_TX_QUEUE_2_BD_BASE, CX2_TX_QUEUE_2_BD_SIZE);
+			       IPW_TX_QUEUE_2_READ_INDEX,
+			       IPW_TX_QUEUE_2_WRITE_INDEX,
+			       IPW_TX_QUEUE_2_BD_BASE, IPW_TX_QUEUE_2_BD_SIZE);
 	if (rc) {
 		IPW_ERROR("Tx 2 queue init failed\n");
 		goto error;
 	}
 	rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx,
-			       CX2_TX_QUEUE_3_READ_INDEX,
-			       CX2_TX_QUEUE_3_WRITE_INDEX,
-			       CX2_TX_QUEUE_3_BD_BASE, CX2_TX_QUEUE_3_BD_SIZE);
+			       IPW_TX_QUEUE_3_READ_INDEX,
+			       IPW_TX_QUEUE_3_WRITE_INDEX,
+			       IPW_TX_QUEUE_3_BD_BASE, IPW_TX_QUEUE_3_BD_SIZE);
 	if (rc) {
 		IPW_ERROR("Tx 3 queue init failed\n");
 		goto error;
@@ -3814,9 +4721,10 @@
 		priv->tx_packets++;
 	}
       done:
-	if (ipw_queue_space(q) > q->low_mark && qindex >= 0) {
-		__maybe_wake_tx(priv);
-	}
+	if ((ipw_queue_space(q) > q->low_mark) &&
+	    (qindex >= 0) &&
+	    (priv->status & STATUS_ASSOCIATED) && netif_running(priv->net_dev))
+		netif_wake_queue(priv->net_dev);
 	used = q->first_empty - q->last_used;
 	if (used < 0)
 		used += q->n_bd;
@@ -3857,7 +4765,7 @@
  * Rx theory of operation
  *
  * The host allocates 32 DMA target addresses and passes the host address
- * to the firmware at register CX2_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * to the firmware at register IPW_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
  * 0 to 31
  *
  * Rx Queue Indexes
@@ -3941,7 +4849,7 @@
 		rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
 		list_del(element);
 
-		ipw_write32(priv, CX2_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE,
+		ipw_write32(priv, IPW_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE,
 			    rxb->dma_addr);
 		rxq->queue[rxq->write] = rxb;
 		rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE;
@@ -3956,7 +4864,7 @@
 
 	/* If we've added more space for the firmware to place data, tell it */
 	if (write != rxq->write)
-		ipw_write32(priv, CX2_RX_WRITE_INDEX, rxq->write);
+		ipw_write32(priv, IPW_RX_WRITE_INDEX, rxq->write);
 }
 
 /*
@@ -3977,7 +4885,7 @@
 	while (!list_empty(&rxq->rx_used)) {
 		element = rxq->rx_used.next;
 		rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
-		rxb->skb = alloc_skb(CX2_RX_BUF_SIZE, GFP_ATOMIC);
+		rxb->skb = alloc_skb(IPW_RX_BUF_SIZE, GFP_ATOMIC);
 		if (!rxb->skb) {
 			printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n",
 			       priv->net_dev->name);
@@ -3991,7 +4899,7 @@
 		rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data;
 		rxb->dma_addr =
 		    pci_map_single(priv->pci_dev, rxb->skb->data,
-				   CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+				   IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
 
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
@@ -4001,6 +4909,14 @@
 	ipw_rx_queue_restock(priv);
 }
 
+static void ipw_bg_rx_queue_replenish(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_rx_queue_replenish(data);
+	up(&priv->sem);
+}
+
 /* Assumes that the skb field of the buffers in 'pool' is kept accurate.
  * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
  * This free routine walks the list of POOL entries and if SKB is set to
@@ -4016,7 +4932,7 @@
 	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
 		if (rxq->pool[i].skb != NULL) {
 			pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
-					 CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+					 IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(rxq->pool[i].skb);
 		}
 	}
@@ -4135,8 +5051,18 @@
 	num_rates = min(network->rates_len, (u8) IPW_MAX_RATES);
 	rates->num_rates = 0;
 	for (i = 0; i < num_rates; i++) {
-		if (!ipw_is_rate_in_mask
-		    (priv, network->mode, network->rates[i])) {
+		if (!ipw_is_rate_in_mask(priv, network->mode,
+					 network->rates[i])) {
+
+			if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) {
+				IPW_DEBUG_SCAN("Adding masked mandatory "
+					       "rate %02X\n",
+					       network->rates[i]);
+				rates->supported_rates[rates->num_rates++] =
+				    network->rates[i];
+				continue;
+			}
+
 			IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
 				       network->rates[i], priv->rates_mask);
 			continue;
@@ -4145,11 +5071,20 @@
 		rates->supported_rates[rates->num_rates++] = network->rates[i];
 	}
 
-	num_rates =
-	    min(network->rates_ex_len, (u8) (IPW_MAX_RATES - num_rates));
+	num_rates = min(network->rates_ex_len,
+			(u8) (IPW_MAX_RATES - num_rates));
 	for (i = 0; i < num_rates; i++) {
-		if (!ipw_is_rate_in_mask
-		    (priv, network->mode, network->rates_ex[i])) {
+		if (!ipw_is_rate_in_mask(priv, network->mode,
+					 network->rates_ex[i])) {
+			if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) {
+				IPW_DEBUG_SCAN("Adding masked mandatory "
+					       "rate %02X\n",
+					       network->rates_ex[i]);
+				rates->supported_rates[rates->num_rates++] =
+				    network->rates[i];
+				continue;
+			}
+
 			IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
 				       network->rates_ex[i], priv->rates_mask);
 			continue;
@@ -4159,7 +5094,7 @@
 		    network->rates_ex[i];
 	}
 
-	return rates->num_rates;
+	return 1;
 }
 
 static inline void ipw_copy_rates(struct ipw_supported_rates *dest,
@@ -4241,6 +5176,216 @@
 	struct ipw_supported_rates rates;
 };
 
+static int ipw_find_adhoc_network(struct ipw_priv *priv,
+				  struct ipw_network_match *match,
+				  struct ieee80211_network *network,
+				  int roaming)
+{
+	struct ipw_supported_rates rates;
+
+	/* Verify that this network's capability is compatible with the
+	 * current mode (AdHoc or Infrastructure) */
+	if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
+	     !(network->capability & WLAN_CAPABILITY_IBSS))) {
+		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded due to "
+				"capability mismatch.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid));
+		return 0;
+	}
+
+	/* If we do not have an ESSID for this AP, we can not associate with
+	 * it */
+	if (network->flags & NETWORK_EMPTY_ESSID) {
+		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+				"because of hidden ESSID.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid));
+		return 0;
+	}
+
+	if (unlikely(roaming)) {
+		/* If we are roaming, then ensure check if this is a valid
+		 * network to try and roam to */
+		if ((network->ssid_len != match->network->ssid_len) ||
+		    memcmp(network->ssid, match->network->ssid,
+			   network->ssid_len)) {
+			IPW_DEBUG_MERGE("Netowrk '%s (" MAC_FMT ")' excluded "
+					"because of non-network ESSID.\n",
+					escape_essid(network->ssid,
+						     network->ssid_len),
+					MAC_ARG(network->bssid));
+			return 0;
+		}
+	} else {
+		/* If an ESSID has been configured then compare the broadcast
+		 * ESSID to ours */
+		if ((priv->config & CFG_STATIC_ESSID) &&
+		    ((network->ssid_len != priv->essid_len) ||
+		     memcmp(network->ssid, priv->essid,
+			    min(network->ssid_len, priv->essid_len)))) {
+			char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+
+			strncpy(escaped,
+				escape_essid(network->ssid, network->ssid_len),
+				sizeof(escaped));
+			IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+					"because of ESSID mismatch: '%s'.\n",
+					escaped, MAC_ARG(network->bssid),
+					escape_essid(priv->essid,
+						     priv->essid_len));
+			return 0;
+		}
+	}
+
+	/* If the old network rate is better than this one, don't bother
+	 * testing everything else. */
+
+	if (network->time_stamp[0] < match->network->time_stamp[0]) {
+		IPW_DEBUG_MERGE("Network '%s excluded because newer than "
+				"current network.\n",
+				escape_essid(match->network->ssid,
+					     match->network->ssid_len));
+		return 0;
+	} else if (network->time_stamp[1] < match->network->time_stamp[1]) {
+		IPW_DEBUG_MERGE("Network '%s excluded because newer than "
+				"current network.\n",
+				escape_essid(match->network->ssid,
+					     match->network->ssid_len));
+		return 0;
+	}
+
+	/* Now go through and see if the requested network is valid... */
+	if (priv->ieee->scan_age != 0 &&
+	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
+		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+				"because of age: %lums.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid),
+				1000 * (jiffies - network->last_scanned) / HZ);
+		return 0;
+	}
+
+	if ((priv->config & CFG_STATIC_CHANNEL) &&
+	    (network->channel != priv->channel)) {
+		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+				"because of channel mismatch: %d != %d.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid),
+				network->channel, priv->channel);
+		return 0;
+	}
+
+	/* Verify privacy compatability */
+	if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
+	    ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
+		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+				"because of privacy mismatch: %s != %s.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid),
+				priv->
+				capability & CAP_PRIVACY_ON ? "on" : "off",
+				network->
+				capability & WLAN_CAPABILITY_PRIVACY ? "on" :
+				"off");
+		return 0;
+	}
+
+	if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
+		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+				"because of the same BSSID match: " MAC_FMT
+				".\n", escape_essid(network->ssid,
+						    network->ssid_len),
+				MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+		return 0;
+	}
+
+	/* Filter out any incompatible freq / mode combinations */
+	if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
+		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+				"because of invalid frequency/mode "
+				"combination.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid));
+		return 0;
+	}
+
+	/* Ensure that the rates supported by the driver are compatible with
+	 * this AP, including verification of basic rates (mandatory) */
+	if (!ipw_compatible_rates(priv, network, &rates)) {
+		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+				"because configured rate mask excludes "
+				"AP mandatory rate.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid));
+		return 0;
+	}
+
+	if (rates.num_rates == 0) {
+		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+				"because of no compatible rates.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid));
+		return 0;
+	}
+
+	/* TODO: Perform any further minimal comparititive tests.  We do not
+	 * want to put too much policy logic here; intelligent scan selection
+	 * should occur within a generic IEEE 802.11 user space tool.  */
+
+	/* Set up 'new' AP to this network */
+	ipw_copy_rates(&match->rates, &rates);
+	match->network = network;
+	IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' is a viable match.\n",
+			escape_essid(network->ssid, network->ssid_len),
+			MAC_ARG(network->bssid));
+
+	return 1;
+}
+
+static void ipw_merge_adhoc_network(void *data)
+{
+	struct ipw_priv *priv = data;
+	struct ieee80211_network *network = NULL;
+	struct ipw_network_match match = {
+		.network = priv->assoc_network
+	};
+
+	if ((priv->status & STATUS_ASSOCIATED) &&
+	    (priv->ieee->iw_mode == IW_MODE_ADHOC)) {
+		/* First pass through ROAM process -- look for a better
+		 * network */
+		unsigned long flags;
+
+		spin_lock_irqsave(&priv->ieee->lock, flags);
+		list_for_each_entry(network, &priv->ieee->network_list, list) {
+			if (network != priv->assoc_network)
+				ipw_find_adhoc_network(priv, &match, network,
+						       1);
+		}
+		spin_unlock_irqrestore(&priv->ieee->lock, flags);
+
+		if (match.network == priv->assoc_network) {
+			IPW_DEBUG_MERGE("No better ADHOC in this network to "
+					"merge to.\n");
+			return;
+		}
+
+		down(&priv->sem);
+		if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
+			IPW_DEBUG_MERGE("remove network %s\n",
+					escape_essid(priv->essid,
+						     priv->essid_len));
+			ipw_remove_current_network(priv);
+		}
+
+		ipw_disassociate(priv);
+		priv->assoc_network = match.network;
+		up(&priv->sem);
+		return;
+	}
+}
+
 static int ipw_best_network(struct ipw_priv *priv,
 			    struct ipw_network_match *match,
 			    struct ieee80211_network *network, int roaming)
@@ -4322,9 +5467,9 @@
 	/* If this network has already had an association attempt within the
 	 * last 3 seconds, do not try and associate again... */
 	if (network->last_associate &&
-	    time_after(network->last_associate + (HZ * 5UL), jiffies)) {
+	    time_after(network->last_associate + (HZ * 3UL), jiffies)) {
 		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
-				"because of storming (%lu since last "
+				"because of storming (%lus since last "
 				"assoc attempt).\n",
 				escape_essid(network->ssid, network->ssid_len),
 				MAC_ARG(network->bssid),
@@ -4334,12 +5479,12 @@
 
 	/* Now go through and see if the requested network is valid... */
 	if (priv->ieee->scan_age != 0 &&
-	    jiffies - network->last_scanned > priv->ieee->scan_age) {
+	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
 		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
 				"because of age: %lums.\n",
 				escape_essid(network->ssid, network->ssid_len),
 				MAC_ARG(network->bssid),
-				(jiffies - network->last_scanned) / (HZ / 100));
+				1000 * (jiffies - network->last_scanned) / HZ);
 		return 0;
 	}
 
@@ -4367,6 +5512,15 @@
 		return 0;
 	}
 
+	if (!priv->ieee->wpa_enabled && (network->wpa_ie_len > 0 ||
+					 network->rsn_ie_len > 0)) {
+		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+				"because of WPA capability mismatch.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid));
+		return 0;
+	}
+
 	if ((priv->config & CFG_STATIC_BSSID) &&
 	    memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
 		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
@@ -4386,7 +5540,26 @@
 		return 0;
 	}
 
-	ipw_compatible_rates(priv, network, &rates);
+	/* Filter out invalid channel in current GEO */
+	if (!ipw_is_valid_channel(priv->ieee, network->channel)) {
+		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+				"because of invalid channel in current GEO\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid));
+		return 0;
+	}
+
+	/* Ensure that the rates supported by the driver are compatible with
+	 * this AP, including verification of basic rates (mandatory) */
+	if (!ipw_compatible_rates(priv, network, &rates)) {
+		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+				"because configured rate mask excludes "
+				"AP mandatory rate.\n",
+				escape_essid(network->ssid, network->ssid_len),
+				MAC_ARG(network->bssid));
+		return 0;
+	}
+
 	if (rates.num_rates == 0) {
 		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
 				"because of no compatible rates.\n",
@@ -4413,6 +5586,9 @@
 static void ipw_adhoc_create(struct ipw_priv *priv,
 			     struct ieee80211_network *network)
 {
+	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+	int i;
+
 	/*
 	 * For the purposes of scanning, we can set our wireless mode
 	 * to trigger scans across combinations of bands, but when it
@@ -4423,22 +5599,47 @@
 	 * chossen band.  Attempting to create a new ad-hoc network
 	 * with an invalid channel for wireless mode will trigger a
 	 * FW fatal error.
+	 *
 	 */
-	network->mode = is_valid_channel(priv->ieee->mode, priv->channel);
-	if (network->mode) {
-		network->channel = priv->channel;
-	} else {
+	switch (ipw_is_valid_channel(priv->ieee, priv->channel)) {
+	case IEEE80211_52GHZ_BAND:
+		network->mode = IEEE_A;
+		i = ipw_channel_to_index(priv->ieee, priv->channel);
+		if (i == -1)
+			BUG();
+		if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
+			IPW_WARNING("Overriding invalid channel\n");
+			priv->channel = geo->a[0].channel;
+		}
+		break;
+
+	case IEEE80211_24GHZ_BAND:
+		if (priv->ieee->mode & IEEE_G)
+			network->mode = IEEE_G;
+		else
+			network->mode = IEEE_B;
+		i = ipw_channel_to_index(priv->ieee, priv->channel);
+		if (i == -1)
+			BUG();
+		if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
+			IPW_WARNING("Overriding invalid channel\n");
+			priv->channel = geo->bg[0].channel;
+		}
+		break;
+
+	default:
 		IPW_WARNING("Overriding invalid channel\n");
 		if (priv->ieee->mode & IEEE_A) {
 			network->mode = IEEE_A;
-			priv->channel = band_a_active_channel[0];
+			priv->channel = geo->a[0].channel;
 		} else if (priv->ieee->mode & IEEE_G) {
 			network->mode = IEEE_G;
-			priv->channel = band_b_active_channel[0];
+			priv->channel = geo->bg[0].channel;
 		} else {
 			network->mode = IEEE_B;
-			priv->channel = band_b_active_channel[0];
+			priv->channel = geo->bg[0].channel;
 		}
+		break;
 	}
 
 	network->channel = priv->channel;
@@ -4448,6 +5649,8 @@
 	memcpy(network->ssid, priv->essid, priv->essid_len);
 	memset(&network->stats, 0, sizeof(network->stats));
 	network->capability = WLAN_CAPABILITY_IBSS;
+	if (!(priv->config & CFG_PREAMBLE_LONG))
+		network->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE;
 	if (priv->capability & CAP_PRIVACY_ON)
 		network->capability |= WLAN_CAPABILITY_PRIVACY;
 	network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH);
@@ -4464,13 +5667,35 @@
 	network->beacon_interval = 100;	/* Default */
 	network->listen_interval = 10;	/* Default */
 	network->atim_window = 0;	/* Default */
-#ifdef CONFIG_IEEE80211_WPA
 	network->wpa_ie_len = 0;
 	network->rsn_ie_len = 0;
-#endif				/* CONFIG_IEEE80211_WPA */
 }
 
-static void ipw_send_wep_keys(struct ipw_priv *priv)
+static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index)
+{
+	struct ipw_tgi_tx_key *key;
+	struct host_cmd cmd = {
+		.cmd = IPW_CMD_TGI_TX_KEY,
+		.len = sizeof(*key)
+	};
+
+	if (!(priv->ieee->sec.flags & (1 << index)))
+		return;
+
+	key = (struct ipw_tgi_tx_key *)&cmd.param;
+	key->key_id = index;
+	memcpy(key->key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH);
+	key->security_type = type;
+	key->station_index = 0;	/* always 0 for BSS */
+	key->flags = 0;
+	/* 0 for new key; previous value of counter (after fatal error) */
+	key->tx_counter[0] = 0;
+	key->tx_counter[1] = 0;
+
+	ipw_send_cmd(priv, &cmd);
+}
+
+static void ipw_send_wep_keys(struct ipw_priv *priv, int type)
 {
 	struct ipw_wep_key *key;
 	int i;
@@ -4483,19 +5708,97 @@
 	key->cmd_id = DINO_CMD_WEP_KEY;
 	key->seq_num = 0;
 
+	/* Note: AES keys cannot be set for multiple times.
+	 * Only set it at the first time. */
 	for (i = 0; i < 4; i++) {
-		key->key_index = i;
-		if (!(priv->sec.flags & (1 << i))) {
+		key->key_index = i | type;
+		if (!(priv->ieee->sec.flags & (1 << i))) {
 			key->key_size = 0;
-		} else {
-			key->key_size = priv->sec.key_sizes[i];
-			memcpy(key->key, priv->sec.keys[i], key->key_size);
+			continue;
 		}
 
-		if (ipw_send_cmd(priv, &cmd)) {
-			IPW_ERROR("failed to send WEP_KEY command\n");
-			return;
-		}
+		key->key_size = priv->ieee->sec.key_sizes[i];
+		memcpy(key->key, priv->ieee->sec.keys[i], key->key_size);
+
+		ipw_send_cmd(priv, &cmd);
+	}
+}
+
+static void ipw_set_hw_decrypt_unicast(struct ipw_priv *priv, int level)
+{
+	if (priv->ieee->host_encrypt)
+		return;
+
+	switch (level) {
+	case SEC_LEVEL_3:
+		priv->sys_config.disable_unicast_decryption = 0;
+		priv->ieee->host_decrypt = 0;
+		break;
+	case SEC_LEVEL_2:
+		priv->sys_config.disable_unicast_decryption = 1;
+		priv->ieee->host_decrypt = 1;
+		break;
+	case SEC_LEVEL_1:
+		priv->sys_config.disable_unicast_decryption = 0;
+		priv->ieee->host_decrypt = 0;
+		break;
+	case SEC_LEVEL_0:
+		priv->sys_config.disable_unicast_decryption = 1;
+		break;
+	default:
+		break;
+	}
+}
+
+static void ipw_set_hw_decrypt_multicast(struct ipw_priv *priv, int level)
+{
+	if (priv->ieee->host_encrypt)
+		return;
+
+	switch (level) {
+	case SEC_LEVEL_3:
+		priv->sys_config.disable_multicast_decryption = 0;
+		break;
+	case SEC_LEVEL_2:
+		priv->sys_config.disable_multicast_decryption = 1;
+		break;
+	case SEC_LEVEL_1:
+		priv->sys_config.disable_multicast_decryption = 0;
+		break;
+	case SEC_LEVEL_0:
+		priv->sys_config.disable_multicast_decryption = 1;
+		break;
+	default:
+		break;
+	}
+}
+
+static void ipw_set_hwcrypto_keys(struct ipw_priv *priv)
+{
+	switch (priv->ieee->sec.level) {
+	case SEC_LEVEL_3:
+		if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
+			ipw_send_tgi_tx_key(priv,
+					    DCT_FLAG_EXT_SECURITY_CCM,
+					    priv->ieee->sec.active_key);
+
+		if (!priv->ieee->host_mc_decrypt)
+			ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM);
+		break;
+	case SEC_LEVEL_2:
+		if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
+			ipw_send_tgi_tx_key(priv,
+					    DCT_FLAG_EXT_SECURITY_TKIP,
+					    priv->ieee->sec.active_key);
+		break;
+	case SEC_LEVEL_1:
+		ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
+		ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level);
+		ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level);
+		break;
+	case SEC_LEVEL_0:
+	default:
+		break;
 	}
 }
 
@@ -4503,9 +5806,12 @@
 {
 	struct ipw_priv *priv = data;
 
-	if (priv->missed_adhoc_beacons++ > priv->missed_beacon_threshold &&
+	if (priv->missed_adhoc_beacons++ > priv->disassociate_threshold &&
 	    !(priv->config & CFG_ADHOC_PERSIST)) {
-		IPW_DEBUG_SCAN("Disassociating due to missed beacons\n");
+		IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
+			  IPW_DL_STATE | IPW_DL_ASSOC,
+			  "Missed beacon: %d - disassociate\n",
+			  priv->missed_adhoc_beacons);
 		ipw_remove_current_network(priv);
 		ipw_disassociate(priv);
 		return;
@@ -4515,6 +5821,14 @@
 			   priv->assoc_request.beacon_interval);
 }
 
+static void ipw_bg_adhoc_check(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_adhoc_check(data);
+	up(&priv->sem);
+}
+
 #ifdef CONFIG_IPW_DEBUG
 static void ipw_debug_config(struct ipw_priv *priv)
 {
@@ -4530,7 +5844,8 @@
 	else
 		IPW_DEBUG_INFO("ESSID unlocked.\n");
 	if (priv->config & CFG_STATIC_BSSID)
-		IPW_DEBUG_INFO("BSSID locked to %d\n", priv->channel);
+		IPW_DEBUG_INFO("BSSID locked to " MAC_FMT "\n",
+			       MAC_ARG(priv->bssid));
 	else
 		IPW_DEBUG_INFO("BSSID unlocked.\n");
 	if (priv->capability & CAP_PRIVACY_ON)
@@ -4543,8 +5858,7 @@
 #define ipw_debug_config(x) do {} while (0)
 #endif
 
-static inline void ipw_set_fixed_rate(struct ipw_priv *priv,
-				      struct ieee80211_network *network)
+static inline void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
 {
 	/* TODO: Verify that this works... */
 	struct ipw_fixed_rate fr = {
@@ -4561,6 +5875,8 @@
 		/* IEEE_A */
 		if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) {
 			/* Invalid fixed rate mask */
+			IPW_DEBUG_WX
+			    ("invalid fixed rate mask in ipw_set_fixed_rate\n");
 			fr.tx_rates = 0;
 			break;
 		}
@@ -4570,9 +5886,11 @@
 
 	default:		/* 2.4Ghz or Mixed */
 		/* IEEE_B */
-		if (network->mode == IEEE_B) {
+		if (mode == IEEE_B) {
 			if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) {
 				/* Invalid fixed rate mask */
+				IPW_DEBUG_WX
+				    ("invalid fixed rate mask in ipw_set_fixed_rate\n");
 				fr.tx_rates = 0;
 			}
 			break;
@@ -4582,6 +5900,8 @@
 		if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK |
 				    IEEE80211_OFDM_RATES_MASK)) {
 			/* Invalid fixed rate mask */
+			IPW_DEBUG_WX
+			    ("invalid fixed rate mask in ipw_set_fixed_rate\n");
 			fr.tx_rates = 0;
 			break;
 		}
@@ -4609,6 +5929,1112 @@
 	ipw_write_reg32(priv, reg, *(u32 *) & fr);
 }
 
+static void ipw_abort_scan(struct ipw_priv *priv)
+{
+	int err;
+
+	if (priv->status & STATUS_SCAN_ABORTING) {
+		IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n");
+		return;
+	}
+	priv->status |= STATUS_SCAN_ABORTING;
+
+	err = ipw_send_scan_abort(priv);
+	if (err)
+		IPW_DEBUG_HC("Request to abort scan failed.\n");
+}
+
+static void ipw_add_scan_channels(struct ipw_priv *priv,
+				  struct ipw_scan_request_ext *scan,
+				  int scan_type)
+{
+	int channel_index = 0;
+	const struct ieee80211_geo *geo;
+	int i;
+
+	geo = ipw_get_geo(priv->ieee);
+
+	if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) {
+		int start = channel_index;
+		for (i = 0; i < geo->a_channels; i++) {
+			if ((priv->status & STATUS_ASSOCIATED) &&
+			    geo->a[i].channel == priv->channel)
+				continue;
+			channel_index++;
+			scan->channels_list[channel_index] = geo->a[i].channel;
+			ipw_set_scan_type(scan, channel_index,
+					  geo->a[i].
+					  flags & IEEE80211_CH_PASSIVE_ONLY ?
+					  IPW_SCAN_PASSIVE_FULL_DWELL_SCAN :
+					  scan_type);
+		}
+
+		if (start != channel_index) {
+			scan->channels_list[start] = (u8) (IPW_A_MODE << 6) |
+			    (channel_index - start);
+			channel_index++;
+		}
+	}
+
+	if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) {
+		int start = channel_index;
+		if (priv->config & CFG_SPEED_SCAN) {
+			int index;
+			u8 channels[IEEE80211_24GHZ_CHANNELS] = {
+				/* nop out the list */
+				[0] = 0
+			};
+
+			u8 channel;
+			while (channel_index < IPW_SCAN_CHANNELS) {
+				channel =
+				    priv->speed_scan[priv->speed_scan_pos];
+				if (channel == 0) {
+					priv->speed_scan_pos = 0;
+					channel = priv->speed_scan[0];
+				}
+				if ((priv->status & STATUS_ASSOCIATED) &&
+				    channel == priv->channel) {
+					priv->speed_scan_pos++;
+					continue;
+				}
+
+				/* If this channel has already been
+				 * added in scan, break from loop
+				 * and this will be the first channel
+				 * in the next scan.
+				 */
+				if (channels[channel - 1] != 0)
+					break;
+
+				channels[channel - 1] = 1;
+				priv->speed_scan_pos++;
+				channel_index++;
+				scan->channels_list[channel_index] = channel;
+				index =
+				    ipw_channel_to_index(priv->ieee, channel);
+				ipw_set_scan_type(scan, channel_index,
+						  geo->bg[index].
+						  flags &
+						  IEEE80211_CH_PASSIVE_ONLY ?
+						  IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
+						  : scan_type);
+			}
+		} else {
+			for (i = 0; i < geo->bg_channels; i++) {
+				if ((priv->status & STATUS_ASSOCIATED) &&
+				    geo->bg[i].channel == priv->channel)
+					continue;
+				channel_index++;
+				scan->channels_list[channel_index] =
+				    geo->bg[i].channel;
+				ipw_set_scan_type(scan, channel_index,
+						  geo->bg[i].
+						  flags &
+						  IEEE80211_CH_PASSIVE_ONLY ?
+						  IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
+						  : scan_type);
+			}
+		}
+
+		if (start != channel_index) {
+			scan->channels_list[start] = (u8) (IPW_B_MODE << 6) |
+			    (channel_index - start);
+		}
+	}
+}
+
+static int ipw_request_scan(struct ipw_priv *priv)
+{
+	struct ipw_scan_request_ext scan;
+	int err = 0, scan_type;
+
+	if (!(priv->status & STATUS_INIT) ||
+	    (priv->status & STATUS_EXIT_PENDING))
+		return 0;
+
+	down(&priv->sem);
+
+	if (priv->status & STATUS_SCANNING) {
+		IPW_DEBUG_HC("Concurrent scan requested.  Ignoring.\n");
+		priv->status |= STATUS_SCAN_PENDING;
+		goto done;
+	}
+
+	if (!(priv->status & STATUS_SCAN_FORCED) &&
+	    priv->status & STATUS_SCAN_ABORTING) {
+		IPW_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
+		priv->status |= STATUS_SCAN_PENDING;
+		goto done;
+	}
+
+	if (priv->status & STATUS_RF_KILL_MASK) {
+		IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+		priv->status |= STATUS_SCAN_PENDING;
+		goto done;
+	}
+
+	memset(&scan, 0, sizeof(scan));
+
+	if (priv->config & CFG_SPEED_SCAN)
+		scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+		    cpu_to_le16(30);
+	else
+		scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+		    cpu_to_le16(20);
+
+	scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
+	    cpu_to_le16(20);
+	scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
+
+	scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
+
+#ifdef CONFIG_IPW2200_MONITOR
+	if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+		u8 channel;
+		u8 band = 0;
+
+		switch (ipw_is_valid_channel(priv->ieee, priv->channel)) {
+		case IEEE80211_52GHZ_BAND:
+			band = (u8) (IPW_A_MODE << 6) | 1;
+			channel = priv->channel;
+			break;
+
+		case IEEE80211_24GHZ_BAND:
+			band = (u8) (IPW_B_MODE << 6) | 1;
+			channel = priv->channel;
+			break;
+
+		default:
+			band = (u8) (IPW_B_MODE << 6) | 1;
+			channel = 9;
+			break;
+		}
+
+		scan.channels_list[0] = band;
+		scan.channels_list[1] = channel;
+		ipw_set_scan_type(&scan, 1, IPW_SCAN_PASSIVE_FULL_DWELL_SCAN);
+
+		/* NOTE:  The card will sit on this channel for this time
+		 * period.  Scan aborts are timing sensitive and frequently
+		 * result in firmware restarts.  As such, it is best to
+		 * set a small dwell_time here and just keep re-issuing
+		 * scans.  Otherwise fast channel hopping will not actually
+		 * hop channels.
+		 *
+		 * TODO: Move SPEED SCAN support to all modes and bands */
+		scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
+		    cpu_to_le16(2000);
+	} else {
+#endif				/* CONFIG_IPW2200_MONITOR */
+		/* If we are roaming, then make this a directed scan for the
+		 * current network.  Otherwise, ensure that every other scan
+		 * is a fast channel hop scan */
+		if ((priv->status & STATUS_ROAMING)
+		    || (!(priv->status & STATUS_ASSOCIATED)
+			&& (priv->config & CFG_STATIC_ESSID)
+			&& (le32_to_cpu(scan.full_scan_index) % 2))) {
+			err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
+			if (err) {
+				IPW_DEBUG_HC("Attempt to send SSID command "
+					     "failed.\n");
+				goto done;
+			}
+
+			scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
+		} else
+			scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN;
+
+		ipw_add_scan_channels(priv, &scan, scan_type);
+#ifdef CONFIG_IPW2200_MONITOR
+	}
+#endif
+
+	err = ipw_send_scan_request_ext(priv, &scan);
+	if (err) {
+		IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
+		goto done;
+	}
+
+	priv->status |= STATUS_SCANNING;
+	priv->status &= ~STATUS_SCAN_PENDING;
+	queue_delayed_work(priv->workqueue, &priv->scan_check,
+			   IPW_SCAN_CHECK_WATCHDOG);
+      done:
+	up(&priv->sem);
+	return err;
+}
+
+static void ipw_bg_abort_scan(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_abort_scan(data);
+	up(&priv->sem);
+}
+
+static int ipw_wpa_enable(struct ipw_priv *priv, int value)
+{
+	/* This is called when wpa_supplicant loads and closes the driver
+	 * interface. */
+	priv->ieee->wpa_enabled = value;
+	return 0;
+}
+
+static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value)
+{
+	struct ieee80211_device *ieee = priv->ieee;
+	struct ieee80211_security sec = {
+		.flags = SEC_AUTH_MODE,
+	};
+	int ret = 0;
+
+	if (value & IW_AUTH_ALG_SHARED_KEY) {
+		sec.auth_mode = WLAN_AUTH_SHARED_KEY;
+		ieee->open_wep = 0;
+	} else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
+		sec.auth_mode = WLAN_AUTH_OPEN;
+		ieee->open_wep = 1;
+	} else
+		return -EINVAL;
+
+	if (ieee->set_security)
+		ieee->set_security(ieee->dev, &sec);
+	else
+		ret = -EOPNOTSUPP;
+
+	return ret;
+}
+
+void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len)
+{
+	/* make sure WPA is enabled */
+	ipw_wpa_enable(priv, 1);
+
+	ipw_disassociate(priv);
+}
+
+static int ipw_set_rsn_capa(struct ipw_priv *priv,
+			    char *capabilities, int length)
+{
+	struct host_cmd cmd = {
+		.cmd = IPW_CMD_RSN_CAPABILITIES,
+		.len = length,
+	};
+
+	IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n");
+
+	memcpy(cmd.param, capabilities, length);
+	return ipw_send_cmd(priv, &cmd);
+}
+
+/*
+ * WE-18 support
+ */
+
+/* SIOCSIWGENIE */
+static int ipw_wx_set_genie(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	struct ieee80211_device *ieee = priv->ieee;
+	u8 *buf;
+	int err = 0;
+
+	if (wrqu->data.length > MAX_WPA_IE_LEN ||
+	    (wrqu->data.length && extra == NULL))
+		return -EINVAL;
+
+	//down(&priv->sem);
+
+	//if (!ieee->wpa_enabled) {
+	//      err = -EOPNOTSUPP;
+	//      goto out;
+	//}
+
+	if (wrqu->data.length) {
+		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+		if (buf == NULL) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		memcpy(buf, extra, wrqu->data.length);
+		kfree(ieee->wpa_ie);
+		ieee->wpa_ie = buf;
+		ieee->wpa_ie_len = wrqu->data.length;
+	} else {
+		kfree(ieee->wpa_ie);
+		ieee->wpa_ie = NULL;
+		ieee->wpa_ie_len = 0;
+	}
+
+	ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
+      out:
+	//up(&priv->sem);
+	return err;
+}
+
+/* SIOCGIWGENIE */
+static int ipw_wx_get_genie(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	struct ieee80211_device *ieee = priv->ieee;
+	int err = 0;
+
+	//down(&priv->sem);
+
+	//if (!ieee->wpa_enabled) {
+	//      err = -EOPNOTSUPP;
+	//      goto out;
+	//}
+
+	if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
+		wrqu->data.length = 0;
+		goto out;
+	}
+
+	if (wrqu->data.length < ieee->wpa_ie_len) {
+		err = -E2BIG;
+		goto out;
+	}
+
+	wrqu->data.length = ieee->wpa_ie_len;
+	memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
+
+      out:
+	//up(&priv->sem);
+	return err;
+}
+
+static int wext_cipher2level(int cipher)
+{
+	switch (cipher) {
+	case IW_AUTH_CIPHER_NONE:
+		return SEC_LEVEL_0;
+	case IW_AUTH_CIPHER_WEP40:
+	case IW_AUTH_CIPHER_WEP104:
+		return SEC_LEVEL_1;
+	case IW_AUTH_CIPHER_TKIP:
+		return SEC_LEVEL_2;
+	case IW_AUTH_CIPHER_CCMP:
+		return SEC_LEVEL_3;
+	default:
+		return -1;
+	}
+}
+
+/* SIOCSIWAUTH */
+static int ipw_wx_set_auth(struct net_device *dev,
+			   struct iw_request_info *info,
+			   union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	struct ieee80211_device *ieee = priv->ieee;
+	struct iw_param *param = &wrqu->param;
+	struct ieee80211_crypt_data *crypt;
+	unsigned long flags;
+	int ret = 0;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+		break;
+	case IW_AUTH_CIPHER_PAIRWISE:
+		ipw_set_hw_decrypt_unicast(priv,
+					   wext_cipher2level(param->value));
+		break;
+	case IW_AUTH_CIPHER_GROUP:
+		ipw_set_hw_decrypt_multicast(priv,
+					     wext_cipher2level(param->value));
+		break;
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 * ipw2200 does not use these parameters
+		 */
+		break;
+
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+		if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
+			break;
+
+		flags = crypt->ops->get_flags(crypt->priv);
+
+		if (param->value)
+			flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+		else
+			flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+
+		crypt->ops->set_flags(flags, crypt->priv);
+
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:{
+			/* HACK:
+			 *
+			 * wpa_supplicant calls set_wpa_enabled when the driver
+			 * is loaded and unloaded, regardless of if WPA is being
+			 * used.  No other calls are made which can be used to
+			 * determine if encryption will be used or not prior to
+			 * association being expected.  If encryption is not being
+			 * used, drop_unencrypted is set to false, else true -- we
+			 * can use this to determine if the CAP_PRIVACY_ON bit should
+			 * be set.
+			 */
+			struct ieee80211_security sec = {
+				.flags = SEC_ENABLED,
+				.enabled = param->value,
+			};
+			priv->ieee->drop_unencrypted = param->value;
+			/* We only change SEC_LEVEL for open mode. Others
+			 * are set by ipw_wpa_set_encryption.
+			 */
+			if (!param->value) {
+				sec.flags |= SEC_LEVEL;
+				sec.level = SEC_LEVEL_0;
+			} else {
+				sec.flags |= SEC_LEVEL;
+				sec.level = SEC_LEVEL_1;
+			}
+			if (priv->ieee->set_security)
+				priv->ieee->set_security(priv->ieee->dev, &sec);
+			break;
+		}
+
+	case IW_AUTH_80211_AUTH_ALG:
+		ret = ipw_wpa_set_auth_algs(priv, param->value);
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		ret = ipw_wpa_enable(priv, param->value);
+		break;
+
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		ieee->ieee802_1x = param->value;
+		break;
+
+		//case IW_AUTH_ROAMING_CONTROL:
+	case IW_AUTH_PRIVACY_INVOKED:
+		ieee->privacy_invoked = param->value;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+/* SIOCGIWAUTH */
+static int ipw_wx_get_auth(struct net_device *dev,
+			   struct iw_request_info *info,
+			   union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	struct ieee80211_device *ieee = priv->ieee;
+	struct ieee80211_crypt_data *crypt;
+	struct iw_param *param = &wrqu->param;
+	int ret = 0;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 * wpa_supplicant will control these internally
+		 */
+		ret = -EOPNOTSUPP;
+		break;
+
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+		if (!crypt || !crypt->ops->get_flags)
+			break;
+
+		param->value = (crypt->ops->get_flags(crypt->priv) &
+				IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
+
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		param->value = ieee->drop_unencrypted;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		param->value = ieee->sec.auth_mode;
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		param->value = ieee->wpa_enabled;
+		break;
+
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		param->value = ieee->ieee802_1x;
+		break;
+
+	case IW_AUTH_ROAMING_CONTROL:
+	case IW_AUTH_PRIVACY_INVOKED:
+		param->value = ieee->privacy_invoked;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+/* SIOCSIWENCODEEXT */
+static int ipw_wx_set_encodeext(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+
+	if (hwcrypto) {
+		if (ext->alg == IW_ENCODE_ALG_TKIP) {
+			/* IPW HW can't build TKIP MIC,
+			   host decryption still needed */
+			if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+				priv->ieee->host_mc_decrypt = 1;
+			else {
+				priv->ieee->host_encrypt = 0;
+				priv->ieee->host_encrypt_msdu = 1;
+				priv->ieee->host_decrypt = 1;
+			}
+		} else {
+			priv->ieee->host_encrypt = 0;
+			priv->ieee->host_encrypt_msdu = 0;
+			priv->ieee->host_decrypt = 0;
+			priv->ieee->host_mc_decrypt = 0;
+		}
+	}
+
+	return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra);
+}
+
+/* SIOCGIWENCODEEXT */
+static int ipw_wx_get_encodeext(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra);
+}
+
+/* SIOCSIWMLME */
+static int ipw_wx_set_mlme(struct net_device *dev,
+			   struct iw_request_info *info,
+			   union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	struct iw_mlme *mlme = (struct iw_mlme *)extra;
+	u16 reason;
+
+	reason = cpu_to_le16(mlme->reason_code);
+
+	switch (mlme->cmd) {
+	case IW_MLME_DEAUTH:
+		// silently ignore
+		break;
+
+	case IW_MLME_DISASSOC:
+		ipw_disassociate(priv);
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_IPW_QOS
+
+/* QoS */
+/*
+* get the modulation type of the current network or
+* the card current mode
+*/
+u8 ipw_qos_current_mode(struct ipw_priv * priv)
+{
+	u8 mode = 0;
+
+	if (priv->status & STATUS_ASSOCIATED) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&priv->ieee->lock, flags);
+		mode = priv->assoc_network->mode;
+		spin_unlock_irqrestore(&priv->ieee->lock, flags);
+	} else {
+		mode = priv->ieee->mode;
+	}
+	IPW_DEBUG_QOS("QoS network/card mode %d \n", mode);
+	return mode;
+}
+
+/*
+* Handle management frame beacon and probe response
+*/
+static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
+					 int active_network,
+					 struct ieee80211_network *network)
+{
+	u32 size = sizeof(struct ieee80211_qos_parameters);
+
+	if (network->capability & WLAN_CAPABILITY_IBSS)
+		network->qos_data.active = network->qos_data.supported;
+
+	if (network->flags & NETWORK_HAS_QOS_MASK) {
+		if (active_network &&
+		    (network->flags & NETWORK_HAS_QOS_PARAMETERS))
+			network->qos_data.active = network->qos_data.supported;
+
+		if ((network->qos_data.active == 1) && (active_network == 1) &&
+		    (network->flags & NETWORK_HAS_QOS_PARAMETERS) &&
+		    (network->qos_data.old_param_count !=
+		     network->qos_data.param_count)) {
+			network->qos_data.old_param_count =
+			    network->qos_data.param_count;
+			schedule_work(&priv->qos_activate);
+			IPW_DEBUG_QOS("QoS parameters change call "
+				      "qos_activate\n");
+		}
+	} else {
+		if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B))
+			memcpy(&network->qos_data.parameters,
+			       &def_parameters_CCK, size);
+		else
+			memcpy(&network->qos_data.parameters,
+			       &def_parameters_OFDM, size);
+
+		if ((network->qos_data.active == 1) && (active_network == 1)) {
+			IPW_DEBUG_QOS("QoS was disabled call qos_activate \n");
+			schedule_work(&priv->qos_activate);
+		}
+
+		network->qos_data.active = 0;
+		network->qos_data.supported = 0;
+	}
+	if ((priv->status & STATUS_ASSOCIATED) &&
+	    (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) {
+		if (memcmp(network->bssid, priv->bssid, ETH_ALEN))
+			if ((network->capability & WLAN_CAPABILITY_IBSS) &&
+			    !(network->flags & NETWORK_EMPTY_ESSID))
+				if ((network->ssid_len ==
+				     priv->assoc_network->ssid_len) &&
+				    !memcmp(network->ssid,
+					    priv->assoc_network->ssid,
+					    network->ssid_len)) {
+					queue_work(priv->workqueue,
+						   &priv->merge_networks);
+				}
+	}
+
+	return 0;
+}
+
+/*
+* This function set up the firmware to support QoS. It sends
+* IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO
+*/
+static int ipw_qos_activate(struct ipw_priv *priv,
+			    struct ieee80211_qos_data *qos_network_data)
+{
+	int err;
+	struct ieee80211_qos_parameters qos_parameters[QOS_QOS_SETS];
+	struct ieee80211_qos_parameters *active_one = NULL;
+	u32 size = sizeof(struct ieee80211_qos_parameters);
+	u32 burst_duration;
+	int i;
+	u8 type;
+
+	type = ipw_qos_current_mode(priv);
+
+	active_one = &(qos_parameters[QOS_PARAM_SET_DEF_CCK]);
+	memcpy(active_one, priv->qos_data.def_qos_parm_CCK, size);
+	active_one = &(qos_parameters[QOS_PARAM_SET_DEF_OFDM]);
+	memcpy(active_one, priv->qos_data.def_qos_parm_OFDM, size);
+
+	if (qos_network_data == NULL) {
+		if (type == IEEE_B) {
+			IPW_DEBUG_QOS("QoS activate network mode %d\n", type);
+			active_one = &def_parameters_CCK;
+		} else
+			active_one = &def_parameters_OFDM;
+
+		memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
+		burst_duration = ipw_qos_get_burst_duration(priv);
+		for (i = 0; i < QOS_QUEUE_NUM; i++)
+			qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] =
+			    (u16) burst_duration;
+	} else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+		if (type == IEEE_B) {
+			IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n",
+				      type);
+			if (priv->qos_data.qos_enable == 0)
+				active_one = &def_parameters_CCK;
+			else
+				active_one = priv->qos_data.def_qos_parm_CCK;
+		} else {
+			if (priv->qos_data.qos_enable == 0)
+				active_one = &def_parameters_OFDM;
+			else
+				active_one = priv->qos_data.def_qos_parm_OFDM;
+		}
+		memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
+	} else {
+		unsigned long flags;
+		int active;
+
+		spin_lock_irqsave(&priv->ieee->lock, flags);
+		active_one = &(qos_network_data->parameters);
+		qos_network_data->old_param_count =
+		    qos_network_data->param_count;
+		memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
+		active = qos_network_data->supported;
+		spin_unlock_irqrestore(&priv->ieee->lock, flags);
+
+		if (active == 0) {
+			burst_duration = ipw_qos_get_burst_duration(priv);
+			for (i = 0; i < QOS_QUEUE_NUM; i++)
+				qos_parameters[QOS_PARAM_SET_ACTIVE].
+				    tx_op_limit[i] = (u16) burst_duration;
+		}
+	}
+
+	IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
+	err = ipw_send_qos_params_command(priv,
+					  (struct ieee80211_qos_parameters *)
+					  &(qos_parameters[0]));
+	if (err)
+		IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n");
+
+	return err;
+}
+
+/*
+* send IPW_CMD_WME_INFO to the firmware
+*/
+static int ipw_qos_set_info_element(struct ipw_priv *priv)
+{
+	int ret = 0;
+	struct ieee80211_qos_information_element qos_info;
+
+	if (priv == NULL)
+		return -1;
+
+	qos_info.elementID = QOS_ELEMENT_ID;
+	qos_info.length = sizeof(struct ieee80211_qos_information_element) - 2;
+
+	qos_info.version = QOS_VERSION_1;
+	qos_info.ac_info = 0;
+
+	memcpy(qos_info.qui, qos_oui, QOS_OUI_LEN);
+	qos_info.qui_type = QOS_OUI_TYPE;
+	qos_info.qui_subtype = QOS_OUI_INFO_SUB_TYPE;
+
+	ret = ipw_send_qos_info_command(priv, &qos_info);
+	if (ret != 0) {
+		IPW_DEBUG_QOS("QoS error calling ipw_send_qos_info_command\n");
+	}
+	return ret;
+}
+
+/*
+* Set the QoS parameter with the association request structure
+*/
+static int ipw_qos_association(struct ipw_priv *priv,
+			       struct ieee80211_network *network)
+{
+	int err = 0;
+	struct ieee80211_qos_data *qos_data = NULL;
+	struct ieee80211_qos_data ibss_data = {
+		.supported = 1,
+		.active = 1,
+	};
+
+	switch (priv->ieee->iw_mode) {
+	case IW_MODE_ADHOC:
+		if (!(network->capability & WLAN_CAPABILITY_IBSS))
+			BUG();
+
+		qos_data = &ibss_data;
+		break;
+
+	case IW_MODE_INFRA:
+		qos_data = &network->qos_data;
+		break;
+
+	default:
+		BUG();
+		break;
+	}
+
+	err = ipw_qos_activate(priv, qos_data);
+	if (err) {
+		priv->assoc_request.policy_support &= ~HC_QOS_SUPPORT_ASSOC;
+		return err;
+	}
+
+	if (priv->qos_data.qos_enable && qos_data->supported) {
+		IPW_DEBUG_QOS("QoS will be enabled for this association\n");
+		priv->assoc_request.policy_support |= HC_QOS_SUPPORT_ASSOC;
+		return ipw_qos_set_info_element(priv);
+	}
+
+	return 0;
+}
+
+/*
+* handling the beaconing responces. if we get different QoS setting
+* of the network from the the associated setting adjust the QoS
+* setting
+*/
+static int ipw_qos_association_resp(struct ipw_priv *priv,
+				    struct ieee80211_network *network)
+{
+	int ret = 0;
+	unsigned long flags;
+	u32 size = sizeof(struct ieee80211_qos_parameters);
+	int set_qos_param = 0;
+
+	if ((priv == NULL) || (network == NULL) ||
+	    (priv->assoc_network == NULL))
+		return ret;
+
+	if (!(priv->status & STATUS_ASSOCIATED))
+		return ret;
+
+	if ((priv->ieee->iw_mode != IW_MODE_INFRA))
+		return ret;
+
+	spin_lock_irqsave(&priv->ieee->lock, flags);
+	if (network->flags & NETWORK_HAS_QOS_PARAMETERS) {
+		memcpy(&priv->assoc_network->qos_data, &network->qos_data,
+		       sizeof(struct ieee80211_qos_data));
+		priv->assoc_network->qos_data.active = 1;
+		if ((network->qos_data.old_param_count !=
+		     network->qos_data.param_count)) {
+			set_qos_param = 1;
+			network->qos_data.old_param_count =
+			    network->qos_data.param_count;
+		}
+
+	} else {
+		if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B))
+			memcpy(&priv->assoc_network->qos_data.parameters,
+			       &def_parameters_CCK, size);
+		else
+			memcpy(&priv->assoc_network->qos_data.parameters,
+			       &def_parameters_OFDM, size);
+		priv->assoc_network->qos_data.active = 0;
+		priv->assoc_network->qos_data.supported = 0;
+		set_qos_param = 1;
+	}
+
+	spin_unlock_irqrestore(&priv->ieee->lock, flags);
+
+	if (set_qos_param == 1)
+		schedule_work(&priv->qos_activate);
+
+	return ret;
+}
+
+static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv)
+{
+	u32 ret = 0;
+
+	if ((priv == NULL))
+		return 0;
+
+	if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION))
+		ret = priv->qos_data.burst_duration_CCK;
+	else
+		ret = priv->qos_data.burst_duration_OFDM;
+
+	return ret;
+}
+
+/*
+* Initialize the setting of QoS global
+*/
+static void ipw_qos_init(struct ipw_priv *priv, int enable,
+			 int burst_enable, u32 burst_duration_CCK,
+			 u32 burst_duration_OFDM)
+{
+	priv->qos_data.qos_enable = enable;
+
+	if (priv->qos_data.qos_enable) {
+		priv->qos_data.def_qos_parm_CCK = &def_qos_parameters_CCK;
+		priv->qos_data.def_qos_parm_OFDM = &def_qos_parameters_OFDM;
+		IPW_DEBUG_QOS("QoS is enabled\n");
+	} else {
+		priv->qos_data.def_qos_parm_CCK = &def_parameters_CCK;
+		priv->qos_data.def_qos_parm_OFDM = &def_parameters_OFDM;
+		IPW_DEBUG_QOS("QoS is not enabled\n");
+	}
+
+	priv->qos_data.burst_enable = burst_enable;
+
+	if (burst_enable) {
+		priv->qos_data.burst_duration_CCK = burst_duration_CCK;
+		priv->qos_data.burst_duration_OFDM = burst_duration_OFDM;
+	} else {
+		priv->qos_data.burst_duration_CCK = 0;
+		priv->qos_data.burst_duration_OFDM = 0;
+	}
+}
+
+/*
+* map the packet priority to the right TX Queue
+*/
+static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority)
+{
+	if (priority > 7 || !priv->qos_data.qos_enable)
+		priority = 0;
+
+	return from_priority_to_tx_queue[priority] - 1;
+}
+
+/*
+* add QoS parameter to the TX command
+*/
+static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv,
+					u16 priority,
+					struct tfd_data *tfd, u8 unicast)
+{
+	int ret = 0;
+	int tx_queue_id = 0;
+	struct ieee80211_qos_data *qos_data = NULL;
+	int active, supported;
+	unsigned long flags;
+
+	if (!(priv->status & STATUS_ASSOCIATED))
+		return 0;
+
+	qos_data = &priv->assoc_network->qos_data;
+
+	spin_lock_irqsave(&priv->ieee->lock, flags);
+
+	if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+		if (unicast == 0)
+			qos_data->active = 0;
+		else
+			qos_data->active = qos_data->supported;
+	}
+
+	active = qos_data->active;
+	supported = qos_data->supported;
+
+	spin_unlock_irqrestore(&priv->ieee->lock, flags);
+
+	IPW_DEBUG_QOS("QoS  %d network is QoS active %d  supported %d  "
+		      "unicast %d\n",
+		      priv->qos_data.qos_enable, active, supported, unicast);
+	if (active && priv->qos_data.qos_enable) {
+		ret = from_priority_to_tx_queue[priority];
+		tx_queue_id = ret - 1;
+		IPW_DEBUG_QOS("QoS packet priority is %d \n", priority);
+		if (priority <= 7) {
+			tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED;
+			tfd->tfd.tfd_26.mchdr.qos_ctrl = priority;
+			tfd->tfd.tfd_26.mchdr.frame_ctl |=
+			    IEEE80211_STYPE_QOS_DATA;
+
+			if (priv->qos_data.qos_no_ack_mask &
+			    (1UL << tx_queue_id)) {
+				tfd->tx_flags &= ~DCT_FLAG_ACK_REQD;
+				tfd->tfd.tfd_26.mchdr.qos_ctrl |=
+				    CTRL_QOS_NO_ACK;
+			}
+		}
+	}
+
+	return ret;
+}
+
+/*
+* background support to run QoS activate functionality
+*/
+static void ipw_bg_qos_activate(void *data)
+{
+	struct ipw_priv *priv = data;
+
+	if (priv == NULL)
+		return;
+
+	down(&priv->sem);
+
+	if (priv->status & STATUS_ASSOCIATED)
+		ipw_qos_activate(priv, &(priv->assoc_network->qos_data));
+
+	up(&priv->sem);
+}
+
+static int ipw_handle_probe_response(struct net_device *dev,
+				     struct ieee80211_probe_response *resp,
+				     struct ieee80211_network *network)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	int active_network = ((priv->status & STATUS_ASSOCIATED) &&
+			      (network == priv->assoc_network));
+
+	ipw_qos_handle_probe_response(priv, active_network, network);
+
+	return 0;
+}
+
+static int ipw_handle_beacon(struct net_device *dev,
+			     struct ieee80211_beacon *resp,
+			     struct ieee80211_network *network)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	int active_network = ((priv->status & STATUS_ASSOCIATED) &&
+			      (network == priv->assoc_network));
+
+	ipw_qos_handle_probe_response(priv, active_network, network);
+
+	return 0;
+}
+
+static int ipw_handle_assoc_response(struct net_device *dev,
+				     struct ieee80211_assoc_response *resp,
+				     struct ieee80211_network *network)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	ipw_qos_association_resp(priv, network);
+	return 0;
+}
+
+static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters
+				       *qos_param)
+{
+	struct host_cmd cmd = {
+		.cmd = IPW_CMD_QOS_PARAMETERS,
+		.len = (sizeof(struct ieee80211_qos_parameters) * 3)
+	};
+
+	memcpy(cmd.param, qos_param, sizeof(*qos_param) * 3);
+	return ipw_send_cmd(priv, &cmd);
+}
+
+static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element
+				     *qos_param)
+{
+	struct host_cmd cmd = {
+		.cmd = IPW_CMD_WME_INFO,
+		.len = sizeof(*qos_param)
+	};
+
+	memcpy(cmd.param, qos_param, sizeof(*qos_param));
+	return ipw_send_cmd(priv, &cmd);
+}
+
+#endif				/* CONFIG_IPW_QOS */
+
 static int ipw_associate_network(struct ipw_priv *priv,
 				 struct ieee80211_network *network,
 				 struct ipw_supported_rates *rates, int roaming)
@@ -4616,7 +7042,7 @@
 	int err;
 
 	if (priv->config & CFG_FIXED_RATE)
-		ipw_set_fixed_rate(priv, network);
+		ipw_set_fixed_rate(priv, network->mode);
 
 	if (!(priv->config & CFG_STATIC_ESSID)) {
 		priv->essid_len = min(network->ssid_len,
@@ -4631,14 +7057,22 @@
 	if ((priv->capability & CAP_PRIVACY_ON) &&
 	    (priv->capability & CAP_SHARED_KEY)) {
 		priv->assoc_request.auth_type = AUTH_SHARED_KEY;
-		priv->assoc_request.auth_key = priv->sec.active_key;
+		priv->assoc_request.auth_key = priv->ieee->sec.active_key;
+
+		if ((priv->capability & CAP_PRIVACY_ON) &&
+		    (priv->ieee->sec.level == SEC_LEVEL_1) &&
+		    !(priv->ieee->host_encrypt || priv->ieee->host_decrypt))
+			ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
 	} else {
 		priv->assoc_request.auth_type = AUTH_OPEN;
 		priv->assoc_request.auth_key = 0;
 	}
 
-	if (priv->capability & CAP_PRIVACY_ON)
-		ipw_send_wep_keys(priv);
+	if (priv->ieee->wpa_ie_len) {
+		priv->assoc_request.policy_support = 0x02;	/* RSN active */
+		ipw_set_rsn_capa(priv, priv->ieee->wpa_ie,
+				 priv->ieee->wpa_ie_len);
+	}
 
 	/*
 	 * It is valid for our ieee device to support multiple modes, but
@@ -4652,20 +7086,41 @@
 	else if (network->mode & priv->ieee->mode & IEEE_B)
 		priv->assoc_request.ieee_mode = IPW_B_MODE;
 
+	priv->assoc_request.capability = network->capability;
+	if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+	    && !(priv->config & CFG_PREAMBLE_LONG)) {
+		priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE;
+	} else {
+		priv->assoc_request.preamble_length = DCT_FLAG_LONG_PREAMBLE;
+
+		/* Clear the short preamble if we won't be supporting it */
+		priv->assoc_request.capability &=
+		    ~WLAN_CAPABILITY_SHORT_PREAMBLE;
+	}
+
+	/* Clear capability bits that aren't used in Ad Hoc */
+	if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+		priv->assoc_request.capability &=
+		    ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
 	IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, "
-			"802.11%c [%d], enc=%s%s%s%c%c\n",
+			"802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
 			roaming ? "Rea" : "A",
 			escape_essid(priv->essid, priv->essid_len),
 			network->channel,
 			ipw_modes[priv->assoc_request.ieee_mode],
 			rates->num_rates,
+			(priv->assoc_request.preamble_length ==
+			 DCT_FLAG_LONG_PREAMBLE) ? "long" : "short",
+			network->capability &
+			WLAN_CAPABILITY_SHORT_PREAMBLE ? "short" : "long",
 			priv->capability & CAP_PRIVACY_ON ? "on " : "off",
 			priv->capability & CAP_PRIVACY_ON ?
 			(priv->capability & CAP_SHARED_KEY ? "(shared)" :
 			 "(open)") : "",
 			priv->capability & CAP_PRIVACY_ON ? " key=" : "",
 			priv->capability & CAP_PRIVACY_ON ?
-			'1' + priv->sec.active_key : '.',
+			'1' + priv->ieee->sec.active_key : '.',
 			priv->capability & CAP_PRIVACY_ON ? '.' : ' ');
 
 	priv->assoc_request.beacon_interval = network->beacon_interval;
@@ -4683,17 +7138,16 @@
 		priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0];
 	}
 
-	memcpy(&priv->assoc_request.bssid, network->bssid, ETH_ALEN);
+	memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN);
 
 	if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
 		memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN);
 		priv->assoc_request.atim_window = network->atim_window;
 	} else {
-		memcpy(&priv->assoc_request.dest, network->bssid, ETH_ALEN);
+		memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN);
 		priv->assoc_request.atim_window = 0;
 	}
 
-	priv->assoc_request.capability = network->capability;
 	priv->assoc_request.listen_interval = network->listen_interval;
 
 	err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
@@ -4710,6 +7164,12 @@
 		priv->sys_config.dot11g_auto_detection = 1;
 	else
 		priv->sys_config.dot11g_auto_detection = 0;
+
+	if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+		priv->sys_config.answer_broadcast_ssid_probe = 1;
+	else
+		priv->sys_config.answer_broadcast_ssid_probe = 0;
+
 	err = ipw_send_system_config(priv, &priv->sys_config);
 	if (err) {
 		IPW_DEBUG_HC("Attempt to send sys config command failed.\n");
@@ -4717,7 +7177,7 @@
 	}
 
 	IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi);
-	err = ipw_set_sensitivity(priv, network->stats.rssi);
+	err = ipw_set_sensitivity(priv, network->stats.rssi + IPW_RSSI_TO_DBM);
 	if (err) {
 		IPW_DEBUG_HC("Attempt to send associate command failed.\n");
 		return err;
@@ -4735,6 +7195,10 @@
 
 	priv->assoc_network = network;
 
+#ifdef CONFIG_IPW_QOS
+	ipw_qos_association(priv, network);
+#endif
+
 	err = ipw_send_associate(priv, &priv->assoc_request);
 	if (err) {
 		IPW_DEBUG_HC("Attempt to send associate command failed.\n");
@@ -4782,12 +7246,15 @@
 	if (priv->status & STATUS_ASSOCIATED) {
 		/* First pass through ROAM process -- look for a better
 		 * network */
+		unsigned long flags;
 		u8 rssi = priv->assoc_network->stats.rssi;
 		priv->assoc_network->stats.rssi = -128;
+		spin_lock_irqsave(&priv->ieee->lock, flags);
 		list_for_each_entry(network, &priv->ieee->network_list, list) {
 			if (network != priv->assoc_network)
 				ipw_best_network(priv, &match, network, 1);
 		}
+		spin_unlock_irqrestore(&priv->ieee->lock, flags);
 		priv->assoc_network->stats.rssi = rssi;
 
 		if (match.network == priv->assoc_network) {
@@ -4810,7 +7277,15 @@
 	priv->status &= ~STATUS_ROAMING;
 }
 
-static void ipw_associate(void *data)
+static void ipw_bg_roam(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_roam(data);
+	up(&priv->sem);
+}
+
+static int ipw_associate(void *data)
 {
 	struct ipw_priv *priv = data;
 
@@ -4820,14 +7295,41 @@
 	};
 	struct ipw_supported_rates *rates;
 	struct list_head *element;
+	unsigned long flags;
+
+	if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+		IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
+		return 0;
+	}
+
+	if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+		IPW_DEBUG_ASSOC("Not attempting association (already in "
+				"progress)\n");
+		return 0;
+	}
+
+	if (priv->status & STATUS_DISASSOCIATING) {
+		IPW_DEBUG_ASSOC("Not attempting association (in "
+				"disassociating)\n ");
+		queue_work(priv->workqueue, &priv->associate);
+		return 0;
+	}
+
+	if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) {
+		IPW_DEBUG_ASSOC("Not attempting association (scanning or not "
+				"initialized)\n");
+		return 0;
+	}
 
 	if (!(priv->config & CFG_ASSOCIATE) &&
 	    !(priv->config & (CFG_STATIC_ESSID |
 			      CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) {
 		IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n");
-		return;
+		return 0;
 	}
 
+	/* Protect our use of the network_list */
+	spin_lock_irqsave(&priv->ieee->lock, flags);
 	list_for_each_entry(network, &priv->ieee->network_list, list)
 	    ipw_best_network(priv, &match, network, 0);
 
@@ -4838,6 +7340,7 @@
 	    priv->ieee->iw_mode == IW_MODE_ADHOC &&
 	    priv->config & CFG_ADHOC_CREATE &&
 	    priv->config & CFG_STATIC_ESSID &&
+	    priv->config & CFG_STATIC_CHANNEL &&
 	    !list_empty(&priv->ieee->network_free_list)) {
 		element = priv->ieee->network_free_list.next;
 		network = list_entry(element, struct ieee80211_network, list);
@@ -4846,25 +7349,83 @@
 		list_del(element);
 		list_add_tail(&network->list, &priv->ieee->network_list);
 	}
+	spin_unlock_irqrestore(&priv->ieee->lock, flags);
 
 	/* If we reached the end of the list, then we don't have any valid
 	 * matching APs */
 	if (!network) {
 		ipw_debug_config(priv);
 
-		queue_delayed_work(priv->workqueue, &priv->request_scan,
-				   SCAN_INTERVAL);
+		if (!(priv->status & STATUS_SCANNING)) {
+			if (!(priv->config & CFG_SPEED_SCAN))
+				queue_delayed_work(priv->workqueue,
+						   &priv->request_scan,
+						   SCAN_INTERVAL);
+			else
+				queue_work(priv->workqueue,
+					   &priv->request_scan);
+		}
 
-		return;
+		return 0;
 	}
 
 	ipw_associate_network(priv, network, rates, 0);
+
+	return 1;
 }
 
-static inline void ipw_handle_data_packet(struct ipw_priv *priv,
-					  struct ipw_rx_mem_buffer *rxb,
-					  struct ieee80211_rx_stats *stats)
+static void ipw_bg_associate(void *data)
 {
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_associate(data);
+	up(&priv->sem);
+}
+
+static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
+				      struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+	fc = le16_to_cpu(hdr->frame_ctl);
+	if (!(fc & IEEE80211_FCTL_PROTECTED))
+		return;
+
+	fc &= ~IEEE80211_FCTL_PROTECTED;
+	hdr->frame_ctl = cpu_to_le16(fc);
+	switch (priv->ieee->sec.level) {
+	case SEC_LEVEL_3:
+		/* Remove CCMP HDR */
+		memmove(skb->data + IEEE80211_3ADDR_LEN,
+			skb->data + IEEE80211_3ADDR_LEN + 8,
+			skb->len - IEEE80211_3ADDR_LEN - 8);
+		skb_trim(skb, skb->len - 16);	/* CCMP_HDR_LEN + CCMP_MIC_LEN */
+		break;
+	case SEC_LEVEL_2:
+		break;
+	case SEC_LEVEL_1:
+		/* Remove IV */
+		memmove(skb->data + IEEE80211_3ADDR_LEN,
+			skb->data + IEEE80211_3ADDR_LEN + 4,
+			skb->len - IEEE80211_3ADDR_LEN - 4);
+		skb_trim(skb, skb->len - 8);	/* IV + ICV */
+		break;
+	case SEC_LEVEL_0:
+		break;
+	default:
+		printk(KERN_ERR "Unknow security level %d\n",
+		       priv->ieee->sec.level);
+		break;
+	}
+}
+
+static void ipw_handle_data_packet(struct ipw_priv *priv,
+				   struct ipw_rx_mem_buffer *rxb,
+				   struct ieee80211_rx_stats *stats)
+{
+	struct ieee80211_hdr_4addr *hdr;
 	struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
 
 	/* We received data from the HW, so stop the watchdog */
@@ -4872,7 +7433,7 @@
 
 	/* We only process data packets if the
 	 * interface is open */
-	if (unlikely((pkt->u.frame.length + IPW_RX_FRAME_SIZE) >
+	if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
 		     skb_tailroom(rxb->skb))) {
 		priv->ieee->stats.rx_errors++;
 		priv->wstats.discard.misc++;
@@ -4889,14 +7450,351 @@
 	skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data));
 
 	/* Set the size of the skb to the size of the frame */
-	skb_put(rxb->skb, pkt->u.frame.length);
+	skb_put(rxb->skb, le16_to_cpu(pkt->u.frame.length));
+
+	IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+	/* HW decrypt will not clear the WEP bit, MIC, PN, etc. */
+	hdr = (struct ieee80211_hdr_4addr *)rxb->skb->data;
+	if (priv->ieee->iw_mode != IW_MODE_MONITOR &&
+	    ((is_multicast_ether_addr(hdr->addr1) ||
+	      is_broadcast_ether_addr(hdr->addr1)) ?
+	     !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt))
+		ipw_rebuild_decrypted_skb(priv, rxb->skb);
+
+	if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
+		priv->ieee->stats.rx_errors++;
+	else {			/* ieee80211_rx succeeded, so it now owns the SKB */
+		rxb->skb = NULL;
+		__ipw_led_activity_on(priv);
+	}
+}
+
+#ifdef CONFIG_IEEE80211_RADIOTAP
+static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
+					   struct ipw_rx_mem_buffer *rxb,
+					   struct ieee80211_rx_stats *stats)
+{
+	struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
+	struct ipw_rx_frame *frame = &pkt->u.frame;
+
+	/* initial pull of some data */
+	u16 received_channel = frame->received_channel;
+	u8 antennaAndPhy = frame->antennaAndPhy;
+	s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM;	/* call it signed anyhow */
+	u16 pktrate = frame->rate;
+
+	/* Magic struct that slots into the radiotap header -- no reason
+	 * to build this manually element by element, we can write it much
+	 * more efficiently than we can parse it. ORDER MATTERS HERE */
+	struct ipw_rt_hdr {
+		struct ieee80211_radiotap_header rt_hdr;
+		u8 rt_flags;	/* radiotap packet flags */
+		u8 rt_rate;	/* rate in 500kb/s */
+		u16 rt_channel;	/* channel in mhz */
+		u16 rt_chbitmask;	/* channel bitfield */
+		s8 rt_dbmsignal;	/* signal in dbM, kluged to signed */
+		u8 rt_antenna;	/* antenna number */
+	} *ipw_rt;
+
+	short len = le16_to_cpu(pkt->u.frame.length);
+
+	/* We received data from the HW, so stop the watchdog */
+	priv->net_dev->trans_start = jiffies;
+
+	/* We only process data packets if the
+	 * interface is open */
+	if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
+		     skb_tailroom(rxb->skb))) {
+		priv->ieee->stats.rx_errors++;
+		priv->wstats.discard.misc++;
+		IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
+		return;
+	} else if (unlikely(!netif_running(priv->net_dev))) {
+		priv->ieee->stats.rx_dropped++;
+		priv->wstats.discard.misc++;
+		IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
+		return;
+	}
+
+	/* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
+	 * that now */
+	if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
+		/* FIXME: Should alloc bigger skb instead */
+		priv->ieee->stats.rx_dropped++;
+		priv->wstats.discard.misc++;
+		IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
+		return;
+	}
+
+	/* copy the frame itself */
+	memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr),
+		rxb->skb->data + IPW_RX_FRAME_SIZE, len);
+
+	/* Zero the radiotap static buffer  ...  We only need to zero the bytes NOT
+	 * part of our real header, saves a little time.
+	 *
+	 * No longer necessary since we fill in all our data.  Purge before merging
+	 * patch officially.
+	 * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0,
+	 *        IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr));
+	 */
+
+	ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data;
+
+	ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+	ipw_rt->rt_hdr.it_pad = 0;	/* always good to zero */
+	ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr);	/* total header+data */
+
+	/* Big bitfield of all the fields we provide in radiotap */
+	ipw_rt->rt_hdr.it_present =
+	    ((1 << IEEE80211_RADIOTAP_FLAGS) |
+	     (1 << IEEE80211_RADIOTAP_RATE) |
+	     (1 << IEEE80211_RADIOTAP_CHANNEL) |
+	     (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+	     (1 << IEEE80211_RADIOTAP_ANTENNA));
+
+	/* Zero the flags, we'll add to them as we go */
+	ipw_rt->rt_flags = 0;
+
+	/* Convert signal to DBM */
+	ipw_rt->rt_dbmsignal = antsignal;
+
+	/* Convert the channel data and set the flags */
+	ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
+	if (received_channel > 14) {	/* 802.11a */
+		ipw_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+	} else if (antennaAndPhy & 32) {	/* 802.11b */
+		ipw_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+	} else {		/* 802.11g */
+		ipw_rt->rt_chbitmask =
+		    (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
+	}
+
+	/* set the rate in multiples of 500k/s */
+	switch (pktrate) {
+	case IPW_TX_RATE_1MB:
+		ipw_rt->rt_rate = 2;
+		break;
+	case IPW_TX_RATE_2MB:
+		ipw_rt->rt_rate = 4;
+		break;
+	case IPW_TX_RATE_5MB:
+		ipw_rt->rt_rate = 10;
+		break;
+	case IPW_TX_RATE_6MB:
+		ipw_rt->rt_rate = 12;
+		break;
+	case IPW_TX_RATE_9MB:
+		ipw_rt->rt_rate = 18;
+		break;
+	case IPW_TX_RATE_11MB:
+		ipw_rt->rt_rate = 22;
+		break;
+	case IPW_TX_RATE_12MB:
+		ipw_rt->rt_rate = 24;
+		break;
+	case IPW_TX_RATE_18MB:
+		ipw_rt->rt_rate = 36;
+		break;
+	case IPW_TX_RATE_24MB:
+		ipw_rt->rt_rate = 48;
+		break;
+	case IPW_TX_RATE_36MB:
+		ipw_rt->rt_rate = 72;
+		break;
+	case IPW_TX_RATE_48MB:
+		ipw_rt->rt_rate = 96;
+		break;
+	case IPW_TX_RATE_54MB:
+		ipw_rt->rt_rate = 108;
+		break;
+	default:
+		ipw_rt->rt_rate = 0;
+		break;
+	}
+
+	/* antenna number */
+	ipw_rt->rt_antenna = (antennaAndPhy & 3);	/* Is this right? */
+
+	/* set the preamble flag if we have it */
+	if ((antennaAndPhy & 64))
+		ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+	/* Set the size of the skb to the size of the frame */
+	skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr));
 
 	IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
 
 	if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
 		priv->ieee->stats.rx_errors++;
-	else			/* ieee80211_rx succeeded, so it now owns the SKB */
+	else {			/* ieee80211_rx succeeded, so it now owns the SKB */
 		rxb->skb = NULL;
+		/* no LED during capture */
+	}
+}
+#endif
+
+static inline int is_network_packet(struct ipw_priv *priv,
+				    struct ieee80211_hdr_4addr *header)
+{
+	/* Filter incoming packets to determine if they are targetted toward
+	 * this network, discarding packets coming from ourselves */
+	switch (priv->ieee->iw_mode) {
+	case IW_MODE_ADHOC:	/* Header: Dest. | Source    | BSSID */
+		/* packets from our adapter are dropped (echo) */
+		if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN))
+			return 0;
+
+		/* {broad,multi}cast packets to our BSSID go through */
+		if (is_multicast_ether_addr(header->addr1) ||
+		    is_broadcast_ether_addr(header->addr1))
+			return !memcmp(header->addr3, priv->bssid, ETH_ALEN);
+
+		/* packets to our adapter go through */
+		return !memcmp(header->addr1, priv->net_dev->dev_addr,
+			       ETH_ALEN);
+
+	case IW_MODE_INFRA:	/* Header: Dest. | BSSID | Source */
+		/* packets from our adapter are dropped (echo) */
+		if (!memcmp(header->addr3, priv->net_dev->dev_addr, ETH_ALEN))
+			return 0;
+
+		/* {broad,multi}cast packets to our BSS go through */
+		if (is_multicast_ether_addr(header->addr1) ||
+		    is_broadcast_ether_addr(header->addr1))
+			return !memcmp(header->addr2, priv->bssid, ETH_ALEN);
+
+		/* packets to our adapter go through */
+		return !memcmp(header->addr1, priv->net_dev->dev_addr,
+			       ETH_ALEN);
+	}
+
+	return 1;
+}
+
+#define IPW_PACKET_RETRY_TIME HZ
+
+static inline int is_duplicate_packet(struct ipw_priv *priv,
+				      struct ieee80211_hdr_4addr *header)
+{
+	u16 sc = le16_to_cpu(header->seq_ctl);
+	u16 seq = WLAN_GET_SEQ_SEQ(sc);
+	u16 frag = WLAN_GET_SEQ_FRAG(sc);
+	u16 *last_seq, *last_frag;
+	unsigned long *last_time;
+
+	switch (priv->ieee->iw_mode) {
+	case IW_MODE_ADHOC:
+		{
+			struct list_head *p;
+			struct ipw_ibss_seq *entry = NULL;
+			u8 *mac = header->addr2;
+			int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE;
+
+			__list_for_each(p, &priv->ibss_mac_hash[index]) {
+				entry =
+				    list_entry(p, struct ipw_ibss_seq, list);
+				if (!memcmp(entry->mac, mac, ETH_ALEN))
+					break;
+			}
+			if (p == &priv->ibss_mac_hash[index]) {
+				entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+				if (!entry) {
+					IPW_ERROR
+					    ("Cannot malloc new mac entry\n");
+					return 0;
+				}
+				memcpy(entry->mac, mac, ETH_ALEN);
+				entry->seq_num = seq;
+				entry->frag_num = frag;
+				entry->packet_time = jiffies;
+				list_add(&entry->list,
+					 &priv->ibss_mac_hash[index]);
+				return 0;
+			}
+			last_seq = &entry->seq_num;
+			last_frag = &entry->frag_num;
+			last_time = &entry->packet_time;
+			break;
+		}
+	case IW_MODE_INFRA:
+		last_seq = &priv->last_seq_num;
+		last_frag = &priv->last_frag_num;
+		last_time = &priv->last_packet_time;
+		break;
+	default:
+		return 0;
+	}
+	if ((*last_seq == seq) &&
+	    time_after(*last_time + IPW_PACKET_RETRY_TIME, jiffies)) {
+		if (*last_frag == frag)
+			goto drop;
+		if (*last_frag + 1 != frag)
+			/* out-of-order fragment */
+			goto drop;
+	} else
+		*last_seq = seq;
+
+	*last_frag = frag;
+	*last_time = jiffies;
+	return 0;
+
+      drop:
+	/* Comment this line now since we observed the card receives
+	 * duplicate packets but the FCTL_RETRY bit is not set in the
+	 * IBSS mode with fragmentation enabled.
+	 BUG_ON(!(le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_RETRY)); */
+	return 1;
+}
+
+static void ipw_handle_mgmt_packet(struct ipw_priv *priv,
+				   struct ipw_rx_mem_buffer *rxb,
+				   struct ieee80211_rx_stats *stats)
+{
+	struct sk_buff *skb = rxb->skb;
+	struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data;
+	struct ieee80211_hdr_4addr *header = (struct ieee80211_hdr_4addr *)
+	    (skb->data + IPW_RX_FRAME_SIZE);
+
+	ieee80211_rx_mgt(priv->ieee, header, stats);
+
+	if (priv->ieee->iw_mode == IW_MODE_ADHOC &&
+	    ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
+	      IEEE80211_STYPE_PROBE_RESP) ||
+	     (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
+	      IEEE80211_STYPE_BEACON))) {
+		if (!memcmp(header->addr3, priv->bssid, ETH_ALEN))
+			ipw_add_station(priv, header->addr2);
+	}
+
+	if (priv->config & CFG_NET_STATS) {
+		IPW_DEBUG_HC("sending stat packet\n");
+
+		/* Set the size of the skb to the size of the full
+		 * ipw header and 802.11 frame */
+		skb_put(skb, le16_to_cpu(pkt->u.frame.length) +
+			IPW_RX_FRAME_SIZE);
+
+		/* Advance past the ipw packet header to the 802.11 frame */
+		skb_pull(skb, IPW_RX_FRAME_SIZE);
+
+		/* Push the ieee80211_rx_stats before the 802.11 frame */
+		memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats));
+
+		skb->dev = priv->ieee->dev;
+
+		/* Point raw at the ieee80211_stats */
+		skb->mac.raw = skb->data;
+
+		skb->pkt_type = PACKET_OTHERHOST;
+		skb->protocol = __constant_htons(ETH_P_80211_STATS);
+		memset(skb->cb, 0, sizeof(rxb->skb->cb));
+		netif_rx(skb);
+		rxb->skb = NULL;
+	}
 }
 
 /*
@@ -4912,8 +7810,8 @@
 	u32 r, w, i;
 	u8 network_packet;
 
-	r = ipw_read32(priv, CX2_RX_READ_INDEX);
-	w = ipw_read32(priv, CX2_RX_WRITE_INDEX);
+	r = ipw_read32(priv, IPW_RX_READ_INDEX);
+	w = ipw_read32(priv, IPW_RX_WRITE_INDEX);
 	i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE;
 
 	while (i != r) {
@@ -4927,7 +7825,7 @@
 		priv->rxq->queue[i] = NULL;
 
 		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
-					    CX2_RX_BUF_SIZE,
+					    IPW_RX_BUF_SIZE,
 					    PCI_DMA_FROMDEVICE);
 
 		pkt = (struct ipw_rx_packet *)rxb->skb->data;
@@ -4938,9 +7836,13 @@
 		switch (pkt->header.message_type) {
 		case RX_FRAME_TYPE:	/* 802.11 frame */  {
 				struct ieee80211_rx_stats stats = {
-					.rssi = pkt->u.frame.rssi_dbm -
+					.rssi =
+					    le16_to_cpu(pkt->u.frame.rssi_dbm) -
 					    IPW_RSSI_TO_DBM,
-					.signal = pkt->u.frame.signal,
+					.signal =
+					    le16_to_cpu(pkt->u.frame.signal),
+					.noise =
+					    le16_to_cpu(pkt->u.frame.noise),
 					.rate = pkt->u.frame.rate,
 					.mac_time = jiffies,
 					.received_channel =
@@ -4950,22 +7852,30 @@
 					     control & (1 << 0)) ?
 					    IEEE80211_24GHZ_BAND :
 					    IEEE80211_52GHZ_BAND,
-					.len = pkt->u.frame.length,
+					.len = le16_to_cpu(pkt->u.frame.length),
 				};
 
 				if (stats.rssi != 0)
 					stats.mask |= IEEE80211_STATMASK_RSSI;
 				if (stats.signal != 0)
 					stats.mask |= IEEE80211_STATMASK_SIGNAL;
+				if (stats.noise != 0)
+					stats.mask |= IEEE80211_STATMASK_NOISE;
 				if (stats.rate != 0)
 					stats.mask |= IEEE80211_STATMASK_RATE;
 
 				priv->rx_packets++;
 
-#ifdef CONFIG_IPW_PROMISC
+#ifdef CONFIG_IPW2200_MONITOR
 				if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+#ifdef CONFIG_IEEE80211_RADIOTAP
+					ipw_handle_data_packet_monitor(priv,
+								       rxb,
+								       &stats);
+#else
 					ipw_handle_data_packet(priv, rxb,
 							       &stats);
+#endif
 					break;
 				}
 #endif
@@ -4979,35 +7889,9 @@
 				 * correctly -- we should probably use the
 				 * frame control of the packet and disregard
 				 * the current iw_mode */
-				switch (priv->ieee->iw_mode) {
-				case IW_MODE_ADHOC:
-					network_packet =
-					    !memcmp(header->addr1,
-						    priv->net_dev->dev_addr,
-						    ETH_ALEN) ||
-					    !memcmp(header->addr3,
-						    priv->bssid, ETH_ALEN) ||
-					    is_broadcast_ether_addr(header->
-								    addr1)
-					    || is_multicast_ether_addr(header->
-								       addr1);
-					break;
 
-				case IW_MODE_INFRA:
-				default:
-					network_packet =
-					    !memcmp(header->addr3,
-						    priv->bssid, ETH_ALEN) ||
-					    !memcmp(header->addr1,
-						    priv->net_dev->dev_addr,
-						    ETH_ALEN) ||
-					    is_broadcast_ether_addr(header->
-								    addr1)
-					    || is_multicast_ether_addr(header->
-								       addr1);
-					break;
-				}
-
+				network_packet =
+				    is_network_packet(priv, header);
 				if (network_packet && priv->assoc_network) {
 					priv->assoc_network->stats.rssi =
 					    stats.rssi;
@@ -5017,9 +7901,10 @@
 				}
 
 				IPW_DEBUG_RX("Frame: len=%u\n",
-					     pkt->u.frame.length);
+					     le16_to_cpu(pkt->u.frame.length));
 
-				if (pkt->u.frame.length < frame_hdr_len(header)) {
+				if (le16_to_cpu(pkt->u.frame.length) <
+				    frame_hdr_len(header)) {
 					IPW_DEBUG_DROP
 					    ("Received packet is too small. "
 					     "Dropping.\n");
@@ -5028,34 +7913,22 @@
 					break;
 				}
 
-				switch (WLAN_FC_GET_TYPE(header->frame_ctl)) {
+				switch (WLAN_FC_GET_TYPE
+					(le16_to_cpu(header->frame_ctl))) {
+
 				case IEEE80211_FTYPE_MGMT:
-					ieee80211_rx_mgt(priv->ieee, header,
-							 &stats);
-					if (priv->ieee->iw_mode == IW_MODE_ADHOC
-					    &&
-					    ((WLAN_FC_GET_STYPE
-					      (header->frame_ctl) ==
-					      IEEE80211_STYPE_PROBE_RESP)
-					     ||
-					     (WLAN_FC_GET_STYPE
-					      (header->frame_ctl) ==
-					      IEEE80211_STYPE_BEACON))
-					    && !memcmp(header->addr3,
-						       priv->bssid, ETH_ALEN))
-						ipw_add_station(priv,
-								header->addr2);
+					ipw_handle_mgmt_packet(priv, rxb,
+							       &stats);
 					break;
 
 				case IEEE80211_FTYPE_CTL:
 					break;
 
 				case IEEE80211_FTYPE_DATA:
-					if (network_packet)
-						ipw_handle_data_packet(priv,
-								       rxb,
-								       &stats);
-					else
+					if (unlikely(!network_packet ||
+						     is_duplicate_packet(priv,
+									 header)))
+					{
 						IPW_DEBUG_DROP("Dropping: "
 							       MAC_FMT ", "
 							       MAC_FMT ", "
@@ -5066,6 +7939,12 @@
 								       addr2),
 							       MAC_ARG(header->
 								       addr3));
+						break;
+					}
+
+					ipw_handle_data_packet(priv, rxb,
+							       &stats);
+
 					break;
 				}
 				break;
@@ -5096,7 +7975,7 @@
 		}
 
 		pci_unmap_single(priv->pci_dev, rxb->dma_addr,
-				 CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+				 IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
 		list_add_tail(&rxb->list, &priv->rxq->rx_used);
 
 		i = (i + 1) % RX_QUEUE_SIZE;
@@ -5108,128 +7987,129 @@
 	ipw_rx_queue_restock(priv);
 }
 
-static void ipw_abort_scan(struct ipw_priv *priv)
+#define DEFAULT_RTS_THRESHOLD     2304U
+#define MIN_RTS_THRESHOLD         1U
+#define MAX_RTS_THRESHOLD         2304U
+#define DEFAULT_BEACON_INTERVAL   100U
+#define	DEFAULT_SHORT_RETRY_LIMIT 7U
+#define	DEFAULT_LONG_RETRY_LIMIT  4U
+
+static int ipw_sw_reset(struct ipw_priv *priv, int init)
 {
-	int err;
+	int band, modulation;
+	int old_mode = priv->ieee->iw_mode;
 
-	if (priv->status & STATUS_SCAN_ABORTING) {
-		IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n");
-		return;
-	}
-	priv->status |= STATUS_SCAN_ABORTING;
+	/* Initialize module parameter values here */
+	priv->config = 0;
 
-	err = ipw_send_scan_abort(priv);
-	if (err)
-		IPW_DEBUG_HC("Request to abort scan failed.\n");
-}
+	/* We default to disabling the LED code as right now it causes
+	 * too many systems to lock up... */
+	if (!led)
+		priv->config |= CFG_NO_LED;
 
-static int ipw_request_scan(struct ipw_priv *priv)
-{
-	struct ipw_scan_request_ext scan;
-	int channel_index = 0;
-	int i, err, scan_type;
+	if (associate)
+		priv->config |= CFG_ASSOCIATE;
+	else
+		IPW_DEBUG_INFO("Auto associate disabled.\n");
 
-	if (priv->status & STATUS_EXIT_PENDING) {
-		IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n");
-		priv->status |= STATUS_SCAN_PENDING;
-		return 0;
+	if (auto_create)
+		priv->config |= CFG_ADHOC_CREATE;
+	else
+		IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
+
+	if (disable) {
+		priv->status |= STATUS_RF_KILL_SW;
+		IPW_DEBUG_INFO("Radio disabled.\n");
 	}
 
-	if (priv->status & STATUS_SCANNING) {
-		IPW_DEBUG_HC("Concurrent scan requested.  Aborting first.\n");
-		priv->status |= STATUS_SCAN_PENDING;
-		ipw_abort_scan(priv);
-		return 0;
+	if (channel != 0) {
+		priv->config |= CFG_STATIC_CHANNEL;
+		priv->channel = channel;
+		IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
+		/* TODO: Validate that provided channel is in range */
+	}
+#ifdef CONFIG_IPW_QOS
+	ipw_qos_init(priv, qos_enable, qos_burst_enable,
+		     burst_duration_CCK, burst_duration_OFDM);
+#endif				/* CONFIG_IPW_QOS */
+
+	switch (mode) {
+	case 1:
+		priv->ieee->iw_mode = IW_MODE_ADHOC;
+		priv->net_dev->type = ARPHRD_ETHER;
+
+		break;
+#ifdef CONFIG_IPW2200_MONITOR
+	case 2:
+		priv->ieee->iw_mode = IW_MODE_MONITOR;
+#ifdef CONFIG_IEEE80211_RADIOTAP
+		priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+#else
+		priv->net_dev->type = ARPHRD_IEEE80211;
+#endif
+		break;
+#endif
+	default:
+	case 0:
+		priv->net_dev->type = ARPHRD_ETHER;
+		priv->ieee->iw_mode = IW_MODE_INFRA;
+		break;
 	}
 
-	if (priv->status & STATUS_SCAN_ABORTING) {
-		IPW_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
-		priv->status |= STATUS_SCAN_PENDING;
-		return 0;
+	if (hwcrypto) {
+		priv->ieee->host_encrypt = 0;
+		priv->ieee->host_encrypt_msdu = 0;
+		priv->ieee->host_decrypt = 0;
+		priv->ieee->host_mc_decrypt = 0;
 	}
+	IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off");
 
-	if (priv->status & STATUS_RF_KILL_MASK) {
-		IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n");
-		priv->status |= STATUS_SCAN_PENDING;
-		return 0;
-	}
+	/* IPW2200/2915 is abled to do hardware fragmentation. */
+	priv->ieee->host_open_frag = 0;
 
-	memset(&scan, 0, sizeof(scan));
-
-	scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20;
-	scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20;
-	scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20;
-
-	scan.full_scan_index = ieee80211_get_scans(priv->ieee);
-	/* If we are roaming, then make this a directed scan for the current
-	 * network.  Otherwise, ensure that every other scan is a fast
-	 * channel hop scan */
-	if ((priv->status & STATUS_ROAMING)
-	    || (!(priv->status & STATUS_ASSOCIATED)
-		&& (priv->config & CFG_STATIC_ESSID)
-		&& (scan.full_scan_index % 2))) {
-		err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
-		if (err) {
-			IPW_DEBUG_HC("Attempt to send SSID command failed.\n");
-			return err;
-		}
-
-		scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
+	if ((priv->pci_dev->device == 0x4223) ||
+	    (priv->pci_dev->device == 0x4224)) {
+		if (init)
+			printk(KERN_INFO DRV_NAME
+			       ": Detected Intel PRO/Wireless 2915ABG Network "
+			       "Connection\n");
+		priv->ieee->abg_true = 1;
+		band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND;
+		modulation = IEEE80211_OFDM_MODULATION |
+		    IEEE80211_CCK_MODULATION;
+		priv->adapter = IPW_2915ABG;
+		priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
 	} else {
-		scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN;
+		if (init)
+			printk(KERN_INFO DRV_NAME
+			       ": Detected Intel PRO/Wireless 2200BG Network "
+			       "Connection\n");
+
+		priv->ieee->abg_true = 0;
+		band = IEEE80211_24GHZ_BAND;
+		modulation = IEEE80211_OFDM_MODULATION |
+		    IEEE80211_CCK_MODULATION;
+		priv->adapter = IPW_2200BG;
+		priv->ieee->mode = IEEE_G | IEEE_B;
 	}
 
-	if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) {
-		int start = channel_index;
-		for (i = 0; i < MAX_A_CHANNELS; i++) {
-			if (band_a_active_channel[i] == 0)
-				break;
-			if ((priv->status & STATUS_ASSOCIATED) &&
-			    band_a_active_channel[i] == priv->channel)
-				continue;
-			channel_index++;
-			scan.channels_list[channel_index] =
-			    band_a_active_channel[i];
-			ipw_set_scan_type(&scan, channel_index, scan_type);
-		}
+	priv->ieee->freq_band = band;
+	priv->ieee->modulation = modulation;
 
-		if (start != channel_index) {
-			scan.channels_list[start] = (u8) (IPW_A_MODE << 6) |
-			    (channel_index - start);
-			channel_index++;
-		}
-	}
+	priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK;
 
-	if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) {
-		int start = channel_index;
-		for (i = 0; i < MAX_B_CHANNELS; i++) {
-			if (band_b_active_channel[i] == 0)
-				break;
-			if ((priv->status & STATUS_ASSOCIATED) &&
-			    band_b_active_channel[i] == priv->channel)
-				continue;
-			channel_index++;
-			scan.channels_list[channel_index] =
-			    band_b_active_channel[i];
-			ipw_set_scan_type(&scan, channel_index, scan_type);
-		}
+	priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
+	priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
 
-		if (start != channel_index) {
-			scan.channels_list[start] = (u8) (IPW_B_MODE << 6) |
-			    (channel_index - start);
-		}
-	}
+	priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
+	priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
+	priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
 
-	err = ipw_send_scan_request_ext(priv, &scan);
-	if (err) {
-		IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
-		return -EIO;
-	}
+	/* If power management is turned on, default to AC mode */
+	priv->power_mode = IPW_POWER_AC;
+	priv->tx_power = IPW_TX_POWER_DEFAULT;
 
-	priv->status |= STATUS_SCANNING;
-	priv->status &= ~STATUS_SCAN_PENDING;
-
-	return 0;
+	return old_mode == priv->ieee->iw_mode;
 }
 
 /*
@@ -5247,12 +8127,16 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	if (!(priv->status & STATUS_ASSOCIATED))
+	down(&priv->sem);
+	if (priv->status & STATUS_RF_KILL_MASK)
+		strcpy(wrqu->name, "radio off");
+	else if (!(priv->status & STATUS_ASSOCIATED))
 		strcpy(wrqu->name, "unassociated");
 	else
 		snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c",
 			 ipw_modes[priv->assoc_request.ieee_mode]);
 	IPW_DEBUG_WX("Name: %s\n", wrqu->name);
+	up(&priv->sem);
 	return 0;
 }
 
@@ -5261,13 +8145,9 @@
 	if (channel == 0) {
 		IPW_DEBUG_INFO("Setting channel to ANY (0)\n");
 		priv->config &= ~CFG_STATIC_CHANNEL;
-		if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
-				      STATUS_ASSOCIATING))) {
-			IPW_DEBUG_ASSOC("Attempting to associate with new "
-					"parameters.\n");
-			ipw_associate(priv);
-		}
-
+		IPW_DEBUG_ASSOC("Attempting to associate with new "
+				"parameters.\n");
+		ipw_associate(priv);
 		return 0;
 	}
 
@@ -5282,14 +8162,32 @@
 	IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel);
 	priv->channel = channel;
 
-	/* If we are currently associated, or trying to associate
-	 * then see if this is a new channel (causing us to disassociate) */
-	if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
-		IPW_DEBUG_ASSOC("Disassociating due to channel change.\n");
-		ipw_disassociate(priv);
-	} else {
-		ipw_associate(priv);
+#ifdef CONFIG_IPW2200_MONITOR
+	if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+		int i;
+		if (priv->status & STATUS_SCANNING) {
+			IPW_DEBUG_SCAN("Scan abort triggered due to "
+				       "channel change.\n");
+			ipw_abort_scan(priv);
+		}
+
+		for (i = 1000; i && (priv->status & STATUS_SCANNING); i--)
+			udelay(10);
+
+		if (priv->status & STATUS_SCANNING)
+			IPW_DEBUG_SCAN("Still scanning...\n");
+		else
+			IPW_DEBUG_SCAN("Took %dms to abort current scan\n",
+				       1000 - i);
+
+		return 0;
 	}
+#endif				/* CONFIG_IPW2200_MONITOR */
+
+	/* Network configuration changed -- force [re]association */
+	IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n");
+	if (!ipw_disassociate(priv))
+		ipw_associate(priv);
 
 	return 0;
 }
@@ -5299,29 +8197,48 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
+	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
 	struct iw_freq *fwrq = &wrqu->freq;
+	int ret = 0, i;
+	u8 channel, flags;
+	int band;
 
+	if (fwrq->m == 0) {
+		IPW_DEBUG_WX("SET Freq/Channel -> any\n");
+		down(&priv->sem);
+		ret = ipw_set_channel(priv, 0);
+		up(&priv->sem);
+		return ret;
+	}
 	/* if setting by freq convert to channel */
 	if (fwrq->e == 1) {
-		if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
-			int f = fwrq->m / 100000;
-			int c = 0;
+		channel = ipw_freq_to_channel(priv->ieee, fwrq->m);
+		if (channel == 0)
+			return -EINVAL;
+	} else
+		channel = fwrq->m;
 
-			while ((c < REG_MAX_CHANNEL) &&
-			       (f != ipw_frequencies[c]))
-				c++;
+	if (!(band = ipw_is_valid_channel(priv->ieee, channel)))
+		return -EINVAL;
 
-			/* hack to fall through */
-			fwrq->e = 0;
-			fwrq->m = c + 1;
+	if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+		i = ipw_channel_to_index(priv->ieee, channel);
+		if (i == -1)
+			return -EINVAL;
+
+		flags = (band == IEEE80211_24GHZ_BAND) ?
+		    geo->bg[i].flags : geo->a[i].flags;
+		if (flags & IEEE80211_CH_PASSIVE_ONLY) {
+			IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n");
+			return -EINVAL;
 		}
 	}
 
-	if (fwrq->e > 0 || fwrq->m > 1000)
-		return -EOPNOTSUPP;
-
 	IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
-	return ipw_set_channel(priv, (u8) fwrq->m);
+	down(&priv->sem);
+	ret = ipw_set_channel(priv, channel);
+	up(&priv->sem);
+	return ret;
 }
 
 static int ipw_wx_get_freq(struct net_device *dev,
@@ -5334,12 +8251,14 @@
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured CHANNEL then return that; otherwise return ANY */
+	down(&priv->sem);
 	if (priv->config & CFG_STATIC_CHANNEL ||
 	    priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))
 		wrqu->freq.m = priv->channel;
 	else
 		wrqu->freq.m = 0;
 
+	up(&priv->sem);
 	IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
 	return 0;
 }
@@ -5353,11 +8272,8 @@
 
 	IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode);
 
-	if (wrqu->mode == priv->ieee->iw_mode)
-		return 0;
-
 	switch (wrqu->mode) {
-#ifdef CONFIG_IPW_PROMISC
+#ifdef CONFIG_IPW2200_MONITOR
 	case IW_MODE_MONITOR:
 #endif
 	case IW_MODE_ADHOC:
@@ -5369,31 +8285,33 @@
 	default:
 		return -EINVAL;
 	}
+	if (wrqu->mode == priv->ieee->iw_mode)
+		return 0;
 
-#ifdef CONFIG_IPW_PROMISC
+	down(&priv->sem);
+
+	ipw_sw_reset(priv, 0);
+
+#ifdef CONFIG_IPW2200_MONITOR
 	if (priv->ieee->iw_mode == IW_MODE_MONITOR)
 		priv->net_dev->type = ARPHRD_ETHER;
 
 	if (wrqu->mode == IW_MODE_MONITOR)
+#ifdef CONFIG_IEEE80211_RADIOTAP
+		priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+#else
 		priv->net_dev->type = ARPHRD_IEEE80211;
-#endif				/* CONFIG_IPW_PROMISC */
+#endif
+#endif				/* CONFIG_IPW2200_MONITOR */
 
-#ifdef CONFIG_PM
 	/* Free the existing firmware and reset the fw_loaded
 	 * flag so ipw_load() will bring in the new firmawre */
-	if (fw_loaded) {
-		fw_loaded = 0;
-	}
-
-	release_firmware(bootfw);
-	release_firmware(ucode);
-	release_firmware(firmware);
-	bootfw = ucode = firmware = NULL;
-#endif
+	free_firmware();
 
 	priv->ieee->iw_mode = wrqu->mode;
-	ipw_adapter_restart(priv);
 
+	queue_work(priv->workqueue, &priv->adapter_restart);
+	up(&priv->sem);
 	return err;
 }
 
@@ -5402,20 +8320,13 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-
+	down(&priv->sem);
 	wrqu->mode = priv->ieee->iw_mode;
 	IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode);
-
+	up(&priv->sem);
 	return 0;
 }
 
-#define DEFAULT_RTS_THRESHOLD     2304U
-#define MIN_RTS_THRESHOLD         1U
-#define MAX_RTS_THRESHOLD         2304U
-#define DEFAULT_BEACON_INTERVAL   100U
-#define	DEFAULT_SHORT_RETRY_LIMIT 7U
-#define	DEFAULT_LONG_RETRY_LIMIT  4U
-
 /* Values are in microsecond */
 static const s32 timeout_duration[] = {
 	350000,
@@ -5439,8 +8350,8 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	struct iw_range *range = (struct iw_range *)extra;
-	u16 val;
-	int i;
+	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+	int i = 0, j;
 
 	wrqu->data.length = sizeof(*range);
 	memset(range, 0, sizeof(*range));
@@ -5451,7 +8362,7 @@
 	range->max_qual.qual = 100;
 	/* TODO: Find real max RSSI and stick here */
 	range->max_qual.level = 0;
-	range->max_qual.noise = 0;
+	range->max_qual.noise = priv->ieee->worst_rssi + 0x100;
 	range->max_qual.updated = 7;	/* Updated all three */
 
 	range->avg_qual.qual = 70;
@@ -5459,7 +8370,7 @@
 	range->avg_qual.level = 0;	/* FIXME to real average level */
 	range->avg_qual.noise = 0;
 	range->avg_qual.updated = 7;	/* Updated all three */
-
+	down(&priv->sem);
 	range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES);
 
 	for (i = 0; i < range->num_bitrates; i++)
@@ -5479,19 +8390,35 @@
 	range->we_version_compiled = WIRELESS_EXT;
 	range->we_version_source = 16;
 
-	range->num_channels = FREQ_COUNT;
-
-	val = 0;
-	for (i = 0; i < FREQ_COUNT; i++) {
-		range->freq[val].i = i + 1;
-		range->freq[val].m = ipw_frequencies[i] * 100000;
-		range->freq[val].e = 1;
-		val++;
-
-		if (val == IW_MAX_FREQUENCIES)
-			break;
+	i = 0;
+	if (priv->ieee->mode & (IEEE_B | IEEE_G)) {
+		for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES;
+		     i++, j++) {
+			range->freq[i].i = geo->bg[j].channel;
+			range->freq[i].m = geo->bg[j].freq * 100000;
+			range->freq[i].e = 1;
+		}
 	}
-	range->num_frequency = val;
+
+	if (priv->ieee->mode & IEEE_A) {
+		for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES;
+		     i++, j++) {
+			range->freq[i].i = geo->a[j].channel;
+			range->freq[i].m = geo->a[j].freq * 100000;
+			range->freq[i].e = 1;
+		}
+	}
+
+	range->num_channels = i;
+	range->num_frequency = i;
+
+	up(&priv->sem);
+
+	/* Event capability (kernel + driver) */
+	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+				IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+				IW_EVENT_CAPA_MASK(SIOCGIWAP));
+	range->event_capa[1] = IW_EVENT_CAPA_K_1;
 
 	IPW_DEBUG_WX("GET Range\n");
 	return 0;
@@ -5512,25 +8439,23 @@
 
 	if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
 		return -EINVAL;
-
+	down(&priv->sem);
 	if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
 	    !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
 		/* we disable mandatory BSSID association */
 		IPW_DEBUG_WX("Setting AP BSSID to ANY\n");
 		priv->config &= ~CFG_STATIC_BSSID;
-		if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
-				      STATUS_ASSOCIATING))) {
-			IPW_DEBUG_ASSOC("Attempting to associate with new "
-					"parameters.\n");
-			ipw_associate(priv);
-		}
-
+		IPW_DEBUG_ASSOC("Attempting to associate with new "
+				"parameters.\n");
+		ipw_associate(priv);
+		up(&priv->sem);
 		return 0;
 	}
 
 	priv->config |= CFG_STATIC_BSSID;
 	if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) {
 		IPW_DEBUG_WX("BSSID set to current BSSID.\n");
+		up(&priv->sem);
 		return 0;
 	}
 
@@ -5539,15 +8464,12 @@
 
 	memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
 
-	/* If we are currently associated, or trying to associate
-	 * then see if this is a new BSSID (causing us to disassociate) */
-	if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
-		IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n");
-		ipw_disassociate(priv);
-	} else {
+	/* Network configuration changed -- force [re]association */
+	IPW_DEBUG_ASSOC("[re]association triggered due to BSSID change.\n");
+	if (!ipw_disassociate(priv))
 		ipw_associate(priv);
-	}
 
+	up(&priv->sem);
 	return 0;
 }
 
@@ -5558,15 +8480,17 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	/* If we are associated, trying to associate, or have a statically
 	 * configured BSSID then return that; otherwise return ANY */
+	down(&priv->sem);
 	if (priv->config & CFG_STATIC_BSSID ||
 	    priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
 		wrqu->ap_addr.sa_family = ARPHRD_ETHER;
-		memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN);
+		memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
 	} else
 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
 
 	IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
 		     MAC_ARG(wrqu->ap_addr.sa_data));
+	up(&priv->sem);
 	return 0;
 }
 
@@ -5577,21 +8501,22 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	char *essid = "";	/* ANY */
 	int length = 0;
-
+	down(&priv->sem);
 	if (wrqu->essid.flags && wrqu->essid.length) {
 		length = wrqu->essid.length - 1;
 		essid = extra;
 	}
 	if (length == 0) {
 		IPW_DEBUG_WX("Setting ESSID to ANY\n");
-		priv->config &= ~CFG_STATIC_ESSID;
-		if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
+		if ((priv->config & CFG_STATIC_ESSID) &&
+		    !(priv->status & (STATUS_ASSOCIATED |
 				      STATUS_ASSOCIATING))) {
 			IPW_DEBUG_ASSOC("Attempting to associate with new "
 					"parameters.\n");
+			priv->config &= ~CFG_STATIC_ESSID;
 			ipw_associate(priv);
 		}
-
+		up(&priv->sem);
 		return 0;
 	}
 
@@ -5601,6 +8526,7 @@
 
 	if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
 		IPW_DEBUG_WX("ESSID set to current ESSID.\n");
+		up(&priv->sem);
 		return 0;
 	}
 
@@ -5610,15 +8536,12 @@
 	priv->essid_len = length;
 	memcpy(priv->essid, essid, priv->essid_len);
 
-	/* If we are currently associated, or trying to associate
-	 * then see if this is a new ESSID (causing us to disassociate) */
-	if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
-		IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n");
-		ipw_disassociate(priv);
-	} else {
+	/* Network configuration changed -- force [re]association */
+	IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n");
+	if (!ipw_disassociate(priv))
 		ipw_associate(priv);
-	}
 
+	up(&priv->sem);
 	return 0;
 }
 
@@ -5630,6 +8553,7 @@
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured ESSID then return that; otherwise return ANY */
+	down(&priv->sem);
 	if (priv->config & CFG_STATIC_ESSID ||
 	    priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
 		IPW_DEBUG_WX("Getting essid: '%s'\n",
@@ -5642,7 +8566,7 @@
 		wrqu->essid.length = 0;
 		wrqu->essid.flags = 0;	/* active */
 	}
-
+	up(&priv->sem);
 	return 0;
 }
 
@@ -5655,11 +8579,12 @@
 	IPW_DEBUG_WX("Setting nick to '%s'\n", extra);
 	if (wrqu->data.length > IW_ESSID_MAX_SIZE)
 		return -E2BIG;
-
+	down(&priv->sem);
 	wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
 	memset(priv->nick, 0, sizeof(priv->nick));
 	memcpy(priv->nick, extra, wrqu->data.length);
 	IPW_DEBUG_TRACE("<<\n");
+	up(&priv->sem);
 	return 0;
 
 }
@@ -5670,9 +8595,11 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	IPW_DEBUG_WX("Getting nick\n");
+	down(&priv->sem);
 	wrqu->data.length = strlen(priv->nick) + 1;
 	memcpy(extra, priv->nick, wrqu->data.length);
 	wrqu->data.flags = 1;	/* active */
+	up(&priv->sem);
 	return 0;
 }
 
@@ -5680,8 +8607,113 @@
 			   struct iw_request_info *info,
 			   union iwreq_data *wrqu, char *extra)
 {
-	IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
-	return -EOPNOTSUPP;
+	/* TODO: We should use semaphores or locks for access to priv */
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	u32 target_rate = wrqu->bitrate.value;
+	u32 fixed, mask;
+
+	/* value = -1, fixed = 0 means auto only, so we should use all rates offered by AP */
+	/* value = X, fixed = 1 means only rate X */
+	/* value = X, fixed = 0 means all rates lower equal X */
+
+	if (target_rate == -1) {
+		fixed = 0;
+		mask = IEEE80211_DEFAULT_RATES_MASK;
+		/* Now we should reassociate */
+		goto apply;
+	}
+
+	mask = 0;
+	fixed = wrqu->bitrate.fixed;
+
+	if (target_rate == 1000000 || !fixed)
+		mask |= IEEE80211_CCK_RATE_1MB_MASK;
+	if (target_rate == 1000000)
+		goto apply;
+
+	if (target_rate == 2000000 || !fixed)
+		mask |= IEEE80211_CCK_RATE_2MB_MASK;
+	if (target_rate == 2000000)
+		goto apply;
+
+	if (target_rate == 5500000 || !fixed)
+		mask |= IEEE80211_CCK_RATE_5MB_MASK;
+	if (target_rate == 5500000)
+		goto apply;
+
+	if (target_rate == 6000000 || !fixed)
+		mask |= IEEE80211_OFDM_RATE_6MB_MASK;
+	if (target_rate == 6000000)
+		goto apply;
+
+	if (target_rate == 9000000 || !fixed)
+		mask |= IEEE80211_OFDM_RATE_9MB_MASK;
+	if (target_rate == 9000000)
+		goto apply;
+
+	if (target_rate == 11000000 || !fixed)
+		mask |= IEEE80211_CCK_RATE_11MB_MASK;
+	if (target_rate == 11000000)
+		goto apply;
+
+	if (target_rate == 12000000 || !fixed)
+		mask |= IEEE80211_OFDM_RATE_12MB_MASK;
+	if (target_rate == 12000000)
+		goto apply;
+
+	if (target_rate == 18000000 || !fixed)
+		mask |= IEEE80211_OFDM_RATE_18MB_MASK;
+	if (target_rate == 18000000)
+		goto apply;
+
+	if (target_rate == 24000000 || !fixed)
+		mask |= IEEE80211_OFDM_RATE_24MB_MASK;
+	if (target_rate == 24000000)
+		goto apply;
+
+	if (target_rate == 36000000 || !fixed)
+		mask |= IEEE80211_OFDM_RATE_36MB_MASK;
+	if (target_rate == 36000000)
+		goto apply;
+
+	if (target_rate == 48000000 || !fixed)
+		mask |= IEEE80211_OFDM_RATE_48MB_MASK;
+	if (target_rate == 48000000)
+		goto apply;
+
+	if (target_rate == 54000000 || !fixed)
+		mask |= IEEE80211_OFDM_RATE_54MB_MASK;
+	if (target_rate == 54000000)
+		goto apply;
+
+	IPW_DEBUG_WX("invalid rate specified, returning error\n");
+	return -EINVAL;
+
+      apply:
+	IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n",
+		     mask, fixed ? "fixed" : "sub-rates");
+	down(&priv->sem);
+	if (mask == IEEE80211_DEFAULT_RATES_MASK) {
+		priv->config &= ~CFG_FIXED_RATE;
+		ipw_set_fixed_rate(priv, priv->ieee->mode);
+	} else
+		priv->config |= CFG_FIXED_RATE;
+
+	if (priv->rates_mask == mask) {
+		IPW_DEBUG_WX("Mask set to current mask.\n");
+		up(&priv->sem);
+		return 0;
+	}
+
+	priv->rates_mask = mask;
+
+	/* Network configuration changed -- force [re]association */
+	IPW_DEBUG_ASSOC("[re]association triggered due to rates change.\n");
+	if (!ipw_disassociate(priv))
+		ipw_associate(priv);
+
+	up(&priv->sem);
+	return 0;
 }
 
 static int ipw_wx_get_rate(struct net_device *dev,
@@ -5689,8 +8721,9 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
+	down(&priv->sem);
 	wrqu->bitrate.value = priv->last_rate;
-
+	up(&priv->sem);
 	IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
 	return 0;
 }
@@ -5700,18 +8733,20 @@
 			  union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-
+	down(&priv->sem);
 	if (wrqu->rts.disabled)
 		priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
 	else {
 		if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
-		    wrqu->rts.value > MAX_RTS_THRESHOLD)
+		    wrqu->rts.value > MAX_RTS_THRESHOLD) {
+			up(&priv->sem);
 			return -EINVAL;
-
+		}
 		priv->rts_threshold = wrqu->rts.value;
 	}
 
 	ipw_send_rts_threshold(priv, priv->rts_threshold);
+	up(&priv->sem);
 	IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold);
 	return 0;
 }
@@ -5721,10 +8756,11 @@
 			  union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
+	down(&priv->sem);
 	wrqu->rts.value = priv->rts_threshold;
 	wrqu->rts.fixed = 0;	/* no auto select */
 	wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
-
+	up(&priv->sem);
 	IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value);
 	return 0;
 }
@@ -5734,41 +8770,33 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	struct ipw_tx_power tx_power;
-	int i;
+	int err = 0;
 
-	if (ipw_radio_kill_sw(priv, wrqu->power.disabled))
-		return -EINPROGRESS;
+	down(&priv->sem);
+	if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) {
+		err = -EINPROGRESS;
+		goto out;
+	}
 
-	if (wrqu->power.flags != IW_TXPOW_DBM)
-		return -EINVAL;
+	if (!wrqu->power.fixed)
+		wrqu->power.value = IPW_TX_POWER_DEFAULT;
 
-	if ((wrqu->power.value > 20) || (wrqu->power.value < -12))
-		return -EINVAL;
+	if (wrqu->power.flags != IW_TXPOW_DBM) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	if ((wrqu->power.value > IPW_TX_POWER_MAX) ||
+	    (wrqu->power.value < IPW_TX_POWER_MIN)) {
+		err = -EINVAL;
+		goto out;
+	}
 
 	priv->tx_power = wrqu->power.value;
-
-	memset(&tx_power, 0, sizeof(tx_power));
-
-	/* configure device for 'G' band */
-	tx_power.ieee_mode = IPW_G_MODE;
-	tx_power.num_channels = 11;
-	for (i = 0; i < 11; i++) {
-		tx_power.channels_tx_power[i].channel_number = i + 1;
-		tx_power.channels_tx_power[i].tx_power = priv->tx_power;
-	}
-	if (ipw_send_tx_power(priv, &tx_power))
-		goto error;
-
-	/* configure device to also handle 'B' band */
-	tx_power.ieee_mode = IPW_B_MODE;
-	if (ipw_send_tx_power(priv, &tx_power))
-		goto error;
-
-	return 0;
-
-      error:
-	return -EIO;
+	err = ipw_set_tx_power(priv);
+      out:
+	up(&priv->sem);
+	return err;
 }
 
 static int ipw_wx_get_txpow(struct net_device *dev,
@@ -5776,14 +8804,15 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-
+	down(&priv->sem);
 	wrqu->power.value = priv->tx_power;
 	wrqu->power.fixed = 1;
 	wrqu->power.flags = IW_TXPOW_DBM;
 	wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
+	up(&priv->sem);
 
 	IPW_DEBUG_WX("GET TX Power -> %s %d \n",
-		     wrqu->power.disabled ? "ON" : "OFF", wrqu->power.value);
+		     wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
 
 	return 0;
 }
@@ -5793,18 +8822,21 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-
+	down(&priv->sem);
 	if (wrqu->frag.disabled)
 		priv->ieee->fts = DEFAULT_FTS;
 	else {
 		if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
-		    wrqu->frag.value > MAX_FRAG_THRESHOLD)
+		    wrqu->frag.value > MAX_FRAG_THRESHOLD) {
+			up(&priv->sem);
 			return -EINVAL;
+		}
 
 		priv->ieee->fts = wrqu->frag.value & ~0x1;
 	}
 
 	ipw_send_frag_threshold(priv, wrqu->frag.value);
+	up(&priv->sem);
 	IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value);
 	return 0;
 }
@@ -5814,10 +8846,11 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
+	down(&priv->sem);
 	wrqu->frag.value = priv->ieee->fts;
 	wrqu->frag.fixed = 0;	/* no auto select */
 	wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
-
+	up(&priv->sem);
 	IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
 
 	return 0;
@@ -5827,16 +8860,128 @@
 			    struct iw_request_info *info,
 			    union iwreq_data *wrqu, char *extra)
 {
-	IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
-	return -EOPNOTSUPP;
+	struct ipw_priv *priv = ieee80211_priv(dev);
+
+	if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
+		return -EINVAL;
+
+	if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
+		return 0;
+
+	if (wrqu->retry.value < 0 || wrqu->retry.value > 255)
+		return -EINVAL;
+
+	down(&priv->sem);
+	if (wrqu->retry.flags & IW_RETRY_MIN)
+		priv->short_retry_limit = (u8) wrqu->retry.value;
+	else if (wrqu->retry.flags & IW_RETRY_MAX)
+		priv->long_retry_limit = (u8) wrqu->retry.value;
+	else {
+		priv->short_retry_limit = (u8) wrqu->retry.value;
+		priv->long_retry_limit = (u8) wrqu->retry.value;
+	}
+
+	ipw_send_retry_limit(priv, priv->short_retry_limit,
+			     priv->long_retry_limit);
+	up(&priv->sem);
+	IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n",
+		     priv->short_retry_limit, priv->long_retry_limit);
+	return 0;
 }
 
 static int ipw_wx_get_retry(struct net_device *dev,
 			    struct iw_request_info *info,
 			    union iwreq_data *wrqu, char *extra)
 {
-	IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
-	return -EOPNOTSUPP;
+	struct ipw_priv *priv = ieee80211_priv(dev);
+
+	down(&priv->sem);
+	wrqu->retry.disabled = 0;
+
+	if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+		up(&priv->sem);
+		return -EINVAL;
+	}
+
+	if (wrqu->retry.flags & IW_RETRY_MAX) {
+		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+		wrqu->retry.value = priv->long_retry_limit;
+	} else if (wrqu->retry.flags & IW_RETRY_MIN) {
+		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+		wrqu->retry.value = priv->short_retry_limit;
+	} else {
+		wrqu->retry.flags = IW_RETRY_LIMIT;
+		wrqu->retry.value = priv->short_retry_limit;
+	}
+	up(&priv->sem);
+
+	IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value);
+
+	return 0;
+}
+
+static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid,
+				   int essid_len)
+{
+	struct ipw_scan_request_ext scan;
+	int err = 0, scan_type;
+
+	down(&priv->sem);
+
+	if (priv->status & STATUS_RF_KILL_MASK) {
+		IPW_DEBUG_HC("Aborting scan due to RF kill activation\n");
+		priv->status |= STATUS_SCAN_PENDING;
+		goto done;
+	}
+
+	IPW_DEBUG_HC("starting request direct scan!\n");
+
+	if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
+		err = wait_event_interruptible(priv->wait_state,
+					       !(priv->
+						 status & (STATUS_SCANNING |
+							   STATUS_SCAN_ABORTING)));
+		if (err) {
+			IPW_DEBUG_HC("aborting direct scan");
+			goto done;
+		}
+	}
+	memset(&scan, 0, sizeof(scan));
+
+	if (priv->config & CFG_SPEED_SCAN)
+		scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+		    cpu_to_le16(30);
+	else
+		scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+		    cpu_to_le16(20);
+
+	scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
+	    cpu_to_le16(20);
+	scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
+	scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
+
+	scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
+
+	err = ipw_send_ssid(priv, essid, essid_len);
+	if (err) {
+		IPW_DEBUG_HC("Attempt to send SSID command failed\n");
+		goto done;
+	}
+	scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
+
+	ipw_add_scan_channels(priv, &scan, scan_type);
+
+	err = ipw_send_scan_request_ext(priv, &scan);
+	if (err) {
+		IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
+		goto done;
+	}
+
+	priv->status |= STATUS_SCANNING;
+
+      done:
+	up(&priv->sem);
+	return err;
 }
 
 static int ipw_wx_set_scan(struct net_device *dev,
@@ -5844,9 +8989,21 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
+	struct iw_scan_req *req = NULL;
+	if (wrqu->data.length
+	    && wrqu->data.length == sizeof(struct iw_scan_req)) {
+		req = (struct iw_scan_req *)extra;
+		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+			ipw_request_direct_scan(priv, req->essid,
+						req->essid_len);
+			return 0;
+		}
+	}
+
 	IPW_DEBUG_WX("Start scan\n");
-	if (ipw_request_scan(priv))
-		return -EIO;
+
+	queue_work(priv->workqueue, &priv->request_scan);
+
 	return 0;
 }
 
@@ -5863,7 +9020,21 @@
 			     union iwreq_data *wrqu, char *key)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+	int ret;
+	u32 cap = priv->capability;
+
+	down(&priv->sem);
+	ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+
+	/* In IBSS mode, we need to notify the firmware to update
+	 * the beacon info after we changed the capability. */
+	if (cap != priv->capability &&
+	    priv->ieee->iw_mode == IW_MODE_ADHOC &&
+	    priv->status & STATUS_ASSOCIATED)
+		ipw_disassociate(priv);
+
+	up(&priv->sem);
+	return ret;
 }
 
 static int ipw_wx_get_encode(struct net_device *dev,
@@ -5880,17 +9051,17 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int err;
-
+	down(&priv->sem);
 	if (wrqu->power.disabled) {
 		priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
 		err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM);
 		if (err) {
 			IPW_DEBUG_WX("failed setting power mode.\n");
+			up(&priv->sem);
 			return err;
 		}
-
 		IPW_DEBUG_WX("SET Power Management Mode -> off\n");
-
+		up(&priv->sem);
 		return 0;
 	}
 
@@ -5902,6 +9073,7 @@
 	default:		/* Otherwise we don't support it */
 		IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
 			     wrqu->power.flags);
+		up(&priv->sem);
 		return -EOPNOTSUPP;
 	}
 
@@ -5914,11 +9086,12 @@
 	err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
 	if (err) {
 		IPW_DEBUG_WX("failed setting power mode.\n");
+		up(&priv->sem);
 		return err;
 	}
 
 	IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
-
+	up(&priv->sem);
 	return 0;
 }
 
@@ -5927,13 +9100,13 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-
-	if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+	down(&priv->sem);
+	if (!(priv->power_mode & IPW_POWER_ENABLED))
 		wrqu->power.disabled = 1;
-	} else {
+	else
 		wrqu->power.disabled = 0;
-	}
 
+	up(&priv->sem);
 	IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
 
 	return 0;
@@ -5946,7 +9119,7 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int mode = *(int *)extra;
 	int err;
-
+	down(&priv->sem);
 	if ((mode < 1) || (mode > IPW_POWER_LIMIT)) {
 		mode = IPW_POWER_AC;
 		priv->power_mode = mode;
@@ -5959,10 +9132,11 @@
 
 		if (err) {
 			IPW_DEBUG_WX("failed setting power mode.\n");
+			up(&priv->sem);
 			return err;
 		}
 	}
-
+	up(&priv->sem);
 	return 0;
 }
 
@@ -6011,7 +9185,7 @@
 		IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode);
 		return -EINVAL;
 	}
-
+	down(&priv->sem);
 	if (priv->adapter == IPW_2915ABG) {
 		priv->ieee->abg_true = 1;
 		if (mode & IEEE_A) {
@@ -6023,6 +9197,7 @@
 		if (mode & IEEE_A) {
 			IPW_WARNING("Attempt to set 2200BG into "
 				    "802.11a mode\n");
+			up(&priv->sem);
 			return -EINVAL;
 		}
 
@@ -6046,20 +9221,20 @@
 	priv->ieee->modulation = modulation;
 	init_supported_rates(priv, &priv->rates);
 
-	/* If we are currently associated, or trying to associate
-	 * then see if this is a new configuration (causing us to
-	 * disassociate) */
-	if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
-		/* The resulting association will trigger
-		 * the new rates to be sent to the device */
-		IPW_DEBUG_ASSOC("Disassociating due to mode change.\n");
-		ipw_disassociate(priv);
-	} else
+	/* Network configuration changed -- force [re]association */
+	IPW_DEBUG_ASSOC("[re]association triggered due to mode change.\n");
+	if (!ipw_disassociate(priv)) {
 		ipw_send_supported_rates(priv, &priv->rates);
+		ipw_associate(priv);
+	}
+
+	/* Update the band LEDs */
+	ipw_led_band_on(priv);
 
 	IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n",
 		     mode & IEEE_A ? 'a' : '.',
 		     mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.');
+	up(&priv->sem);
 	return 0;
 }
 
@@ -6068,124 +9243,234 @@
 				    union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-
-	switch (priv->ieee->freq_band) {
-	case IEEE80211_24GHZ_BAND:
-		switch (priv->ieee->modulation) {
-		case IEEE80211_CCK_MODULATION:
-			strncpy(extra, "802.11b (2)", MAX_WX_STRING);
-			break;
-		case IEEE80211_OFDM_MODULATION:
-			strncpy(extra, "802.11g (4)", MAX_WX_STRING);
-			break;
-		default:
-			strncpy(extra, "802.11bg (6)", MAX_WX_STRING);
-			break;
-		}
-		break;
-
-	case IEEE80211_52GHZ_BAND:
+	down(&priv->sem);
+	switch (priv->ieee->mode) {
+	case IEEE_A:
 		strncpy(extra, "802.11a (1)", MAX_WX_STRING);
 		break;
-
-	default:		/* Mixed Band */
-		switch (priv->ieee->modulation) {
-		case IEEE80211_CCK_MODULATION:
-			strncpy(extra, "802.11ab (3)", MAX_WX_STRING);
-			break;
-		case IEEE80211_OFDM_MODULATION:
-			strncpy(extra, "802.11ag (5)", MAX_WX_STRING);
-			break;
-		default:
-			strncpy(extra, "802.11abg (7)", MAX_WX_STRING);
-			break;
-		}
+	case IEEE_B:
+		strncpy(extra, "802.11b (2)", MAX_WX_STRING);
+		break;
+	case IEEE_A | IEEE_B:
+		strncpy(extra, "802.11ab (3)", MAX_WX_STRING);
+		break;
+	case IEEE_G:
+		strncpy(extra, "802.11g (4)", MAX_WX_STRING);
+		break;
+	case IEEE_A | IEEE_G:
+		strncpy(extra, "802.11ag (5)", MAX_WX_STRING);
+		break;
+	case IEEE_B | IEEE_G:
+		strncpy(extra, "802.11bg (6)", MAX_WX_STRING);
+		break;
+	case IEEE_A | IEEE_B | IEEE_G:
+		strncpy(extra, "802.11abg (7)", MAX_WX_STRING);
+		break;
+	default:
+		strncpy(extra, "unknown", MAX_WX_STRING);
 		break;
 	}
 
 	IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra);
 
 	wrqu->data.length = strlen(extra) + 1;
+	up(&priv->sem);
 
 	return 0;
 }
 
-#ifdef CONFIG_IPW_PROMISC
-static int ipw_wx_set_promisc(struct net_device *dev,
+static int ipw_wx_set_preamble(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	int mode = *(int *)extra;
+	down(&priv->sem);
+	/* Switching from SHORT -> LONG requires a disassociation */
+	if (mode == 1) {
+		if (!(priv->config & CFG_PREAMBLE_LONG)) {
+			priv->config |= CFG_PREAMBLE_LONG;
+
+			/* Network configuration changed -- force [re]association */
+			IPW_DEBUG_ASSOC
+			    ("[re]association triggered due to preamble change.\n");
+			if (!ipw_disassociate(priv))
+				ipw_associate(priv);
+		}
+		goto done;
+	}
+
+	if (mode == 0) {
+		priv->config &= ~CFG_PREAMBLE_LONG;
+		goto done;
+	}
+	up(&priv->sem);
+	return -EINVAL;
+
+      done:
+	up(&priv->sem);
+	return 0;
+}
+
+static int ipw_wx_get_preamble(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	down(&priv->sem);
+	if (priv->config & CFG_PREAMBLE_LONG)
+		snprintf(wrqu->name, IFNAMSIZ, "long (1)");
+	else
+		snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
+	up(&priv->sem);
+	return 0;
+}
+
+#ifdef CONFIG_IPW2200_MONITOR
+static int ipw_wx_set_monitor(struct net_device *dev,
 			      struct iw_request_info *info,
 			      union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int *parms = (int *)extra;
 	int enable = (parms[0] > 0);
-
-	IPW_DEBUG_WX("SET PROMISC: %d %d\n", enable, parms[1]);
+	down(&priv->sem);
+	IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]);
 	if (enable) {
 		if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
+#ifdef CONFIG_IEEE80211_RADIOTAP
+			priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+#else
 			priv->net_dev->type = ARPHRD_IEEE80211;
-			ipw_adapter_restart(priv);
+#endif
+			queue_work(priv->workqueue, &priv->adapter_restart);
 		}
 
 		ipw_set_channel(priv, parms[1]);
 	} else {
-		if (priv->ieee->iw_mode != IW_MODE_MONITOR)
+		if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
+			up(&priv->sem);
 			return 0;
+		}
 		priv->net_dev->type = ARPHRD_ETHER;
-		ipw_adapter_restart(priv);
+		queue_work(priv->workqueue, &priv->adapter_restart);
 	}
+	up(&priv->sem);
 	return 0;
 }
 
+#endif				// CONFIG_IPW2200_MONITOR
+
 static int ipw_wx_reset(struct net_device *dev,
 			struct iw_request_info *info,
 			union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	IPW_DEBUG_WX("RESET\n");
-	ipw_adapter_restart(priv);
+	queue_work(priv->workqueue, &priv->adapter_restart);
 	return 0;
 }
-#endif				// CONFIG_IPW_PROMISC
+
+static int ipw_wx_sw_reset(struct net_device *dev,
+			   struct iw_request_info *info,
+			   union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	union iwreq_data wrqu_sec = {
+		.encoding = {
+			     .flags = IW_ENCODE_DISABLED,
+			     },
+	};
+	int ret;
+
+	IPW_DEBUG_WX("SW_RESET\n");
+
+	down(&priv->sem);
+
+	ret = ipw_sw_reset(priv, 0);
+	if (!ret) {
+		free_firmware();
+		ipw_adapter_restart(priv);
+	}
+
+	/* The SW reset bit might have been toggled on by the 'disable'
+	 * module parameter, so take appropriate action */
+	ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW);
+
+	up(&priv->sem);
+	ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL);
+	down(&priv->sem);
+
+	if (!(priv->status & STATUS_RF_KILL_MASK)) {
+		/* Configuration likely changed -- force [re]association */
+		IPW_DEBUG_ASSOC("[re]association triggered due to sw "
+				"reset.\n");
+		if (!ipw_disassociate(priv))
+			ipw_associate(priv);
+	}
+
+	up(&priv->sem);
+
+	return 0;
+}
 
 /* Rebase the WE IOCTLs to zero for the handler array */
 #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
 static iw_handler ipw_wx_handlers[] = {
-	IW_IOCTL(SIOCGIWNAME)	= ipw_wx_get_name,
-	IW_IOCTL(SIOCSIWFREQ)	= ipw_wx_set_freq,
-	IW_IOCTL(SIOCGIWFREQ)	= ipw_wx_get_freq,
-	IW_IOCTL(SIOCSIWMODE)	= ipw_wx_set_mode,
-	IW_IOCTL(SIOCGIWMODE)	= ipw_wx_get_mode,
-	IW_IOCTL(SIOCGIWRANGE)	= ipw_wx_get_range,
-	IW_IOCTL(SIOCSIWAP)	= ipw_wx_set_wap,
-	IW_IOCTL(SIOCGIWAP)	= ipw_wx_get_wap,
-	IW_IOCTL(SIOCSIWSCAN)	= ipw_wx_set_scan,
-	IW_IOCTL(SIOCGIWSCAN)	= ipw_wx_get_scan,
-	IW_IOCTL(SIOCSIWESSID)	= ipw_wx_set_essid,
-	IW_IOCTL(SIOCGIWESSID)	= ipw_wx_get_essid,
-	IW_IOCTL(SIOCSIWNICKN)	= ipw_wx_set_nick,
-	IW_IOCTL(SIOCGIWNICKN)	= ipw_wx_get_nick,
-	IW_IOCTL(SIOCSIWRATE)	= ipw_wx_set_rate,
-	IW_IOCTL(SIOCGIWRATE)	= ipw_wx_get_rate,
-	IW_IOCTL(SIOCSIWRTS)	= ipw_wx_set_rts,
-	IW_IOCTL(SIOCGIWRTS)	= ipw_wx_get_rts,
-	IW_IOCTL(SIOCSIWFRAG)	= ipw_wx_set_frag,
-	IW_IOCTL(SIOCGIWFRAG)	= ipw_wx_get_frag,
-	IW_IOCTL(SIOCSIWTXPOW)	= ipw_wx_set_txpow,
-	IW_IOCTL(SIOCGIWTXPOW)	= ipw_wx_get_txpow,
-	IW_IOCTL(SIOCSIWRETRY)	= ipw_wx_set_retry,
-	IW_IOCTL(SIOCGIWRETRY)	= ipw_wx_get_retry,
-	IW_IOCTL(SIOCSIWENCODE)	= ipw_wx_set_encode,
-	IW_IOCTL(SIOCGIWENCODE)	= ipw_wx_get_encode,
-	IW_IOCTL(SIOCSIWPOWER)	= ipw_wx_set_power,
-	IW_IOCTL(SIOCGIWPOWER)	= ipw_wx_get_power,
+	IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name,
+	IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq,
+	IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
+	IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
+	IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode,
+	IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range,
+	IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap,
+	IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap,
+	IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan,
+	IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan,
+	IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid,
+	IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid,
+	IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick,
+	IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick,
+	IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate,
+	IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate,
+	IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts,
+	IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts,
+	IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag,
+	IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag,
+	IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow,
+	IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow,
+	IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry,
+	IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry,
+	IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode,
+	IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode,
+	IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power,
+	IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power,
+	IW_IOCTL(SIOCSIWSPY) = iw_handler_set_spy,
+	IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy,
+	IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy,
+	IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy,
+	IW_IOCTL(SIOCSIWGENIE) = ipw_wx_set_genie,
+	IW_IOCTL(SIOCGIWGENIE) = ipw_wx_get_genie,
+	IW_IOCTL(SIOCSIWMLME) = ipw_wx_set_mlme,
+	IW_IOCTL(SIOCSIWAUTH) = ipw_wx_set_auth,
+	IW_IOCTL(SIOCGIWAUTH) = ipw_wx_get_auth,
+	IW_IOCTL(SIOCSIWENCODEEXT) = ipw_wx_set_encodeext,
+	IW_IOCTL(SIOCGIWENCODEEXT) = ipw_wx_get_encodeext,
 };
 
-#define IPW_PRIV_SET_POWER	SIOCIWFIRSTPRIV
-#define IPW_PRIV_GET_POWER	SIOCIWFIRSTPRIV+1
-#define IPW_PRIV_SET_MODE	SIOCIWFIRSTPRIV+2
-#define IPW_PRIV_GET_MODE	SIOCIWFIRSTPRIV+3
-#define IPW_PRIV_SET_PROMISC	SIOCIWFIRSTPRIV+4
-#define IPW_PRIV_RESET		SIOCIWFIRSTPRIV+5
+enum {
+	IPW_PRIV_SET_POWER = SIOCIWFIRSTPRIV,
+	IPW_PRIV_GET_POWER,
+	IPW_PRIV_SET_MODE,
+	IPW_PRIV_GET_MODE,
+	IPW_PRIV_SET_PREAMBLE,
+	IPW_PRIV_GET_PREAMBLE,
+	IPW_PRIV_RESET,
+	IPW_PRIV_SW_RESET,
+#ifdef CONFIG_IPW2200_MONITOR
+	IPW_PRIV_SET_MONITOR,
+#endif
+};
 
 static struct iw_priv_args ipw_priv_args[] = {
 	{
@@ -6204,14 +9489,25 @@
 	 .cmd = IPW_PRIV_GET_MODE,
 	 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
 	 .name = "get_mode"},
-#ifdef CONFIG_IPW_PROMISC
 	{
-	 IPW_PRIV_SET_PROMISC,
-	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
+	 .cmd = IPW_PRIV_SET_PREAMBLE,
+	 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 .name = "set_preamble"},
+	{
+	 .cmd = IPW_PRIV_GET_PREAMBLE,
+	 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ,
+	 .name = "get_preamble"},
 	{
 	 IPW_PRIV_RESET,
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
-#endif				/* CONFIG_IPW_PROMISC */
+	{
+	 IPW_PRIV_SW_RESET,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "sw_reset"},
+#ifdef CONFIG_IPW2200_MONITOR
+	{
+	 IPW_PRIV_SET_MONITOR,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
+#endif				/* CONFIG_IPW2200_MONITOR */
 };
 
 static iw_handler ipw_priv_handler[] = {
@@ -6219,19 +9515,23 @@
 	ipw_wx_get_powermode,
 	ipw_wx_set_wireless_mode,
 	ipw_wx_get_wireless_mode,
-#ifdef CONFIG_IPW_PROMISC
-	ipw_wx_set_promisc,
+	ipw_wx_set_preamble,
+	ipw_wx_get_preamble,
 	ipw_wx_reset,
+	ipw_wx_sw_reset,
+#ifdef CONFIG_IPW2200_MONITOR
+	ipw_wx_set_monitor,
 #endif
 };
 
 static struct iw_handler_def ipw_wx_handler_def = {
-	.standard		= ipw_wx_handlers,
-	.num_standard		= ARRAY_SIZE(ipw_wx_handlers),
-	.num_private		= ARRAY_SIZE(ipw_priv_handler),
-	.num_private_args	= ARRAY_SIZE(ipw_priv_args),
-	.private		= ipw_priv_handler,
-	.private_args		= ipw_priv_args,
+	.standard = ipw_wx_handlers,
+	.num_standard = ARRAY_SIZE(ipw_wx_handlers),
+	.num_private = ARRAY_SIZE(ipw_priv_handler),
+	.num_private_args = ARRAY_SIZE(ipw_priv_args),
+	.private = ipw_priv_handler,
+	.private_args = ipw_priv_args,
+	.get_wireless_stats = ipw_get_wireless_stats,
 };
 
 /*
@@ -6246,8 +9546,8 @@
 
 	wstats = &priv->wstats;
 
-	/* if hw is disabled, then ipw2100_get_ordinal() can't be called.
-	 * ipw2100_wx_wireless_stats seems to be called before fw is
+	/* if hw is disabled, then ipw_get_ordinal() can't be called.
+	 * netdev->get_wireless_stats seems to be called before fw is
 	 * initialized.  STATUS_ASSOCIATED will only be set if the hw is up
 	 * and associated; if not associcated, the values are all meaningless
 	 * anyway, so set them all to NULL and INVALID */
@@ -6298,7 +9598,7 @@
 	sys_config->dot11g_auto_detection = 0;
 	sys_config->enable_cts_to_self = 0;
 	sys_config->bt_coexist_collision_thr = 0;
-	sys_config->pass_noise_stats_to_host = 1;
+	sys_config->pass_noise_stats_to_host = 1;	//1 -- fix for 256
 }
 
 static int ipw_net_open(struct net_device *dev)
@@ -6306,9 +9606,11 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	IPW_DEBUG_INFO("dev->open\n");
 	/* we should be verifying the device is ready to be opened */
+	down(&priv->sem);
 	if (!(priv->status & STATUS_RF_KILL_MASK) &&
 	    (priv->status & STATUS_ASSOCIATED))
 		netif_start_queue(dev);
+	up(&priv->sem);
 	return 0;
 }
 
@@ -6326,22 +9628,34 @@
 we need to heavily modify the ieee80211_skb_to_txb.
 */
 
-static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
+static inline int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
+			     int pri)
 {
 	struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)
 	    txb->fragments[0]->data;
 	int i = 0;
 	struct tfd_frame *tfd;
+#ifdef CONFIG_IPW_QOS
+	int tx_id = ipw_get_tx_queue_number(priv, pri);
+	struct clx2_tx_queue *txq = &priv->txq[tx_id];
+#else
 	struct clx2_tx_queue *txq = &priv->txq[0];
+#endif
 	struct clx2_queue *q = &txq->q;
 	u8 id, hdr_len, unicast;
 	u16 remaining_bytes;
+	int fc;
+
+	/* If there isn't room in the queue, we return busy and let the
+	 * network stack requeue the packet for us */
+	if (ipw_queue_space(q) < q->high_mark)
+		return NETDEV_TX_BUSY;
 
 	switch (priv->ieee->iw_mode) {
 	case IW_MODE_ADHOC:
 		hdr_len = IEEE80211_3ADDR_LEN;
-		unicast = !is_broadcast_ether_addr(hdr->addr1) &&
-		    !is_multicast_ether_addr(hdr->addr1);
+		unicast = !(is_multicast_ether_addr(hdr->addr1) ||
+			    is_broadcast_ether_addr(hdr->addr1));
 		id = ipw_find_station(priv, hdr->addr1);
 		if (id == IPW_INVALID_STATION) {
 			id = ipw_add_station(priv, hdr->addr1);
@@ -6356,8 +9670,8 @@
 
 	case IW_MODE_INFRA:
 	default:
-		unicast = !is_broadcast_ether_addr(hdr->addr3) &&
-		    !is_multicast_ether_addr(hdr->addr3);
+		unicast = !(is_multicast_ether_addr(hdr->addr3) ||
+			    is_broadcast_ether_addr(hdr->addr3));
 		hdr_len = IEEE80211_3ADDR_LEN;
 		id = 0;
 		break;
@@ -6372,26 +9686,83 @@
 	tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
 
 	tfd->u.data.cmd_id = DINO_CMD_TX;
-	tfd->u.data.len = txb->payload_size;
+	tfd->u.data.len = cpu_to_le16(txb->payload_size);
 	remaining_bytes = txb->payload_size;
-	if (unlikely(!unicast))
-		tfd->u.data.tx_flags = DCT_FLAG_NO_WEP;
-	else
-		tfd->u.data.tx_flags = DCT_FLAG_NO_WEP | DCT_FLAG_ACK_REQD;
 
 	if (priv->assoc_request.ieee_mode == IPW_B_MODE)
-		tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_CCK;
+		tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK;
 	else
-		tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_OFDM;
+		tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_OFDM;
 
-	if (priv->config & CFG_PREAMBLE)
-		tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREMBL;
+	if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE)
+		tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE;
+
+	fc = le16_to_cpu(hdr->frame_ctl);
+	hdr->frame_ctl = cpu_to_le16(fc & ~IEEE80211_FCTL_MOREFRAGS);
 
 	memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len);
 
+	if (likely(unicast))
+		tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
+
+	if (txb->encrypted && !priv->ieee->host_encrypt) {
+		switch (priv->ieee->sec.level) {
+		case SEC_LEVEL_3:
+			tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
+			    IEEE80211_FCTL_PROTECTED;
+			/* XXX: ACK flag must be set for CCMP even if it
+			 * is a multicast/broadcast packet, because CCMP
+			 * group communication encrypted by GTK is
+			 * actually done by the AP. */
+			if (!unicast)
+				tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
+
+			tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
+			tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_CCM;
+			tfd->u.data.key_index = 0;
+			tfd->u.data.key_index |= DCT_WEP_INDEX_USE_IMMEDIATE;
+			break;
+		case SEC_LEVEL_2:
+			tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
+			    IEEE80211_FCTL_PROTECTED;
+			tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
+			tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP;
+			tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE;
+			break;
+		case SEC_LEVEL_1:
+			tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
+			    IEEE80211_FCTL_PROTECTED;
+			tfd->u.data.key_index = priv->ieee->tx_keyidx;
+			if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <=
+			    40)
+				tfd->u.data.key_index |= DCT_WEP_KEY_64Bit;
+			else
+				tfd->u.data.key_index |= DCT_WEP_KEY_128Bit;
+			break;
+		case SEC_LEVEL_0:
+			break;
+		default:
+			printk(KERN_ERR "Unknow security level %d\n",
+			       priv->ieee->sec.level);
+			break;
+		}
+	} else
+		/* No hardware encryption */
+		tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP;
+
+#ifdef CONFIG_IPW_QOS
+	ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data), unicast);
+#endif				/* CONFIG_IPW_QOS */
+
 	/* payload */
-	tfd->u.data.num_chunks = min((u8) (NUM_TFD_CHUNKS - 2), txb->nr_frags);
-	for (i = 0; i < tfd->u.data.num_chunks; i++) {
+	tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2),
+						 txb->nr_frags));
+	IPW_DEBUG_FRAG("%i fragments being sent as %i chunks.\n",
+		       txb->nr_frags, le32_to_cpu(tfd->u.data.num_chunks));
+	for (i = 0; i < le32_to_cpu(tfd->u.data.num_chunks); i++) {
+		IPW_DEBUG_FRAG("Adding fragment %i of %i (%d bytes).\n",
+			       i, le32_to_cpu(tfd->u.data.num_chunks),
+			       txb->fragments[i]->len - hdr_len);
 		IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n",
 			     i, tfd->u.data.num_chunks,
 			     txb->fragments[i]->len - hdr_len);
@@ -6399,11 +9770,13 @@
 			   txb->fragments[i]->len - hdr_len);
 
 		tfd->u.data.chunk_ptr[i] =
-		    pci_map_single(priv->pci_dev,
-				   txb->fragments[i]->data + hdr_len,
-				   txb->fragments[i]->len - hdr_len,
-				   PCI_DMA_TODEVICE);
-		tfd->u.data.chunk_len[i] = txb->fragments[i]->len - hdr_len;
+		    cpu_to_le32(pci_map_single
+				(priv->pci_dev,
+				 txb->fragments[i]->data + hdr_len,
+				 txb->fragments[i]->len - hdr_len,
+				 PCI_DMA_TODEVICE));
+		tfd->u.data.chunk_len[i] =
+		    cpu_to_le16(txb->fragments[i]->len - hdr_len);
 	}
 
 	if (i != txb->nr_frags) {
@@ -6418,9 +9791,10 @@
 		       remaining_bytes);
 		skb = alloc_skb(remaining_bytes, GFP_ATOMIC);
 		if (skb != NULL) {
-			tfd->u.data.chunk_len[i] = remaining_bytes;
+			tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes);
 			for (j = i; j < txb->nr_frags; j++) {
 				int size = txb->fragments[j]->len - hdr_len;
+
 				printk(KERN_INFO "Adding frag %d %d...\n",
 				       j, size);
 				memcpy(skb_put(skb, size),
@@ -6429,10 +9803,14 @@
 			dev_kfree_skb_any(txb->fragments[i]);
 			txb->fragments[i] = skb;
 			tfd->u.data.chunk_ptr[i] =
-			    pci_map_single(priv->pci_dev, skb->data,
-					   tfd->u.data.chunk_len[i],
-					   PCI_DMA_TODEVICE);
-			tfd->u.data.num_chunks++;
+			    cpu_to_le32(pci_map_single
+					(priv->pci_dev, skb->data,
+					 tfd->u.data.chunk_len[i],
+					 PCI_DMA_TODEVICE));
+
+			tfd->u.data.num_chunks =
+			    cpu_to_le32(le32_to_cpu(tfd->u.data.num_chunks) +
+					1);
 		}
 	}
 
@@ -6440,14 +9818,28 @@
 	q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
 	ipw_write32(priv, q->reg_w, q->first_empty);
 
-	if (ipw_queue_space(q) < q->high_mark)
-		netif_stop_queue(priv->net_dev);
-
-	return;
+	return NETDEV_TX_OK;
 
       drop:
 	IPW_DEBUG_DROP("Silently dropping Tx packet.\n");
 	ieee80211_txb_free(txb);
+	return NETDEV_TX_OK;
+}
+
+static int ipw_net_is_queue_full(struct net_device *dev, int pri)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+#ifdef CONFIG_IPW_QOS
+	int tx_id = ipw_get_tx_queue_number(priv, pri);
+	struct clx2_tx_queue *txq = &priv->txq[tx_id];
+#else
+	struct clx2_tx_queue *txq = &priv->txq[0];
+#endif				/* CONFIG_IPW_QOS */
+
+	if (ipw_queue_space(&txq->q) < txq->q.high_mark)
+		return 1;
+
+	return 0;
 }
 
 static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
@@ -6455,9 +9847,9 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	unsigned long flags;
+	int ret;
 
 	IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size);
-
 	spin_lock_irqsave(&priv->lock, flags);
 
 	if (!(priv->status & STATUS_ASSOCIATED)) {
@@ -6467,10 +9859,12 @@
 		goto fail_unlock;
 	}
 
-	ipw_tx_skb(priv, txb);
-
+	ret = ipw_tx_skb(priv, txb, pri);
+	if (ret == NETDEV_TX_OK)
+		__ipw_led_activity_on(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
-	return 0;
+
+	return ret;
 
       fail_unlock:
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -6497,11 +9891,13 @@
 	struct sockaddr *addr = p;
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
+	down(&priv->sem);
 	priv->config |= CFG_CUSTOM_MAC;
 	memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
 	printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n",
 	       priv->net_dev->name, MAC_ARG(priv->mac_addr));
-	ipw_adapter_restart(priv);
+	queue_work(priv->workqueue, &priv->adapter_restart);
+	up(&priv->sem);
 	return 0;
 }
 
@@ -6524,7 +9920,7 @@
 	snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)",
 		 vers, date);
 	strcpy(info->bus_info, pci_name(p->pci_dev));
-	info->eedump_len = CX2_EEPROM_IMAGE_SIZE;
+	info->eedump_len = IPW_EEPROM_IMAGE_SIZE;
 }
 
 static u32 ipw_ethtool_get_link(struct net_device *dev)
@@ -6535,7 +9931,7 @@
 
 static int ipw_ethtool_get_eeprom_len(struct net_device *dev)
 {
-	return CX2_EEPROM_IMAGE_SIZE;
+	return IPW_EEPROM_IMAGE_SIZE;
 }
 
 static int ipw_ethtool_get_eeprom(struct net_device *dev,
@@ -6543,10 +9939,11 @@
 {
 	struct ipw_priv *p = ieee80211_priv(dev);
 
-	if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE)
+	if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
 		return -EINVAL;
-
-	memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len);
+	down(&p->sem);
+	memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len);
+	up(&p->sem);
 	return 0;
 }
 
@@ -6556,23 +9953,23 @@
 	struct ipw_priv *p = ieee80211_priv(dev);
 	int i;
 
-	if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE)
+	if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
 		return -EINVAL;
-
-	memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len);
+	down(&p->sem);
+	memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len);
 	for (i = IPW_EEPROM_DATA;
-	     i < IPW_EEPROM_DATA + CX2_EEPROM_IMAGE_SIZE; i++)
+	     i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++)
 		ipw_write8(p, i, p->eeprom[i]);
-
+	up(&p->sem);
 	return 0;
 }
 
 static struct ethtool_ops ipw_ethtool_ops = {
-	.get_link	= ipw_ethtool_get_link,
-	.get_drvinfo	= ipw_ethtool_get_drvinfo,
-	.get_eeprom_len	= ipw_ethtool_get_eeprom_len,
-	.get_eeprom	= ipw_ethtool_get_eeprom,
-	.set_eeprom	= ipw_ethtool_set_eeprom,
+	.get_link = ipw_ethtool_get_link,
+	.get_drvinfo = ipw_ethtool_get_drvinfo,
+	.get_eeprom_len = ipw_ethtool_get_eeprom_len,
+	.get_eeprom = ipw_ethtool_get_eeprom,
+	.set_eeprom = ipw_ethtool_set_eeprom,
 };
 
 static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
@@ -6590,8 +9987,8 @@
 		goto none;
 	}
 
-	inta = ipw_read32(priv, CX2_INTA_RW);
-	inta_mask = ipw_read32(priv, CX2_INTA_MASK_R);
+	inta = ipw_read32(priv, IPW_INTA_RW);
+	inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
 
 	if (inta == 0xFFFFFFFF) {
 		/* Hardware disappeared */
@@ -6599,7 +9996,7 @@
 		goto none;
 	}
 
-	if (!(inta & (CX2_INTA_MASK_ALL & inta_mask))) {
+	if (!(inta & (IPW_INTA_MASK_ALL & inta_mask))) {
 		/* Shared interrupt */
 		goto none;
 	}
@@ -6608,8 +10005,8 @@
 	ipw_disable_interrupts(priv);
 
 	/* ack current interrupts */
-	inta &= (CX2_INTA_MASK_ALL & inta_mask);
-	ipw_write32(priv, CX2_INTA_RW, inta);
+	inta &= (IPW_INTA_MASK_ALL & inta_mask);
+	ipw_write32(priv, IPW_INTA_RW, inta);
 
 	/* Cache INTA value for our tasklet */
 	priv->isr_inta = inta;
@@ -6655,28 +10052,116 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
+static void ipw_bg_rf_kill(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_rf_kill(data);
+	up(&priv->sem);
+}
+
+void ipw_link_up(struct ipw_priv *priv)
+{
+	priv->last_seq_num = -1;
+	priv->last_frag_num = -1;
+	priv->last_packet_time = 0;
+
+	netif_carrier_on(priv->net_dev);
+	if (netif_queue_stopped(priv->net_dev)) {
+		IPW_DEBUG_NOTIF("waking queue\n");
+		netif_wake_queue(priv->net_dev);
+	} else {
+		IPW_DEBUG_NOTIF("starting queue\n");
+		netif_start_queue(priv->net_dev);
+	}
+
+	cancel_delayed_work(&priv->request_scan);
+	ipw_reset_stats(priv);
+	/* Ensure the rate is updated immediately */
+	priv->last_rate = ipw_get_current_rate(priv);
+	ipw_gather_stats(priv);
+	ipw_led_link_up(priv);
+	notify_wx_assoc_event(priv);
+
+	if (priv->config & CFG_BACKGROUND_SCAN)
+		queue_delayed_work(priv->workqueue, &priv->request_scan, HZ);
+}
+
+static void ipw_bg_link_up(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_link_up(data);
+	up(&priv->sem);
+}
+
+void ipw_link_down(struct ipw_priv *priv)
+{
+	ipw_led_link_down(priv);
+	netif_carrier_off(priv->net_dev);
+	netif_stop_queue(priv->net_dev);
+	notify_wx_assoc_event(priv);
+
+	/* Cancel any queued work ... */
+	cancel_delayed_work(&priv->request_scan);
+	cancel_delayed_work(&priv->adhoc_check);
+	cancel_delayed_work(&priv->gather_stats);
+
+	ipw_reset_stats(priv);
+
+	if (!(priv->status & STATUS_EXIT_PENDING)) {
+		/* Queue up another scan... */
+		queue_work(priv->workqueue, &priv->request_scan);
+	}
+}
+
+static void ipw_bg_link_down(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_link_down(data);
+	up(&priv->sem);
+}
+
 static int ipw_setup_deferred_work(struct ipw_priv *priv)
 {
 	int ret = 0;
 
 	priv->workqueue = create_workqueue(DRV_NAME);
 	init_waitqueue_head(&priv->wait_command_queue);
+	init_waitqueue_head(&priv->wait_state);
 
-	INIT_WORK(&priv->adhoc_check, ipw_adhoc_check, priv);
-	INIT_WORK(&priv->associate, ipw_associate, priv);
-	INIT_WORK(&priv->disassociate, ipw_disassociate, priv);
-	INIT_WORK(&priv->rx_replenish, ipw_rx_queue_replenish, priv);
-	INIT_WORK(&priv->adapter_restart, ipw_adapter_restart, priv);
-	INIT_WORK(&priv->rf_kill, ipw_rf_kill, priv);
-	INIT_WORK(&priv->up, (void (*)(void *))ipw_up, priv);
-	INIT_WORK(&priv->down, (void (*)(void *))ipw_down, priv);
+	INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv);
+	INIT_WORK(&priv->associate, ipw_bg_associate, priv);
+	INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv);
+	INIT_WORK(&priv->system_config, ipw_system_config, priv);
+	INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv);
+	INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv);
+	INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv);
+	INIT_WORK(&priv->up, (void (*)(void *))ipw_bg_up, priv);
+	INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv);
 	INIT_WORK(&priv->request_scan,
 		  (void (*)(void *))ipw_request_scan, priv);
 	INIT_WORK(&priv->gather_stats,
-		  (void (*)(void *))ipw_gather_stats, priv);
-	INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv);
-	INIT_WORK(&priv->roam, ipw_roam, priv);
-	INIT_WORK(&priv->scan_check, ipw_scan_check, priv);
+		  (void (*)(void *))ipw_bg_gather_stats, priv);
+	INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv);
+	INIT_WORK(&priv->roam, ipw_bg_roam, priv);
+	INIT_WORK(&priv->scan_check, ipw_bg_scan_check, priv);
+	INIT_WORK(&priv->link_up, (void (*)(void *))ipw_bg_link_up, priv);
+	INIT_WORK(&priv->link_down, (void (*)(void *))ipw_bg_link_down, priv);
+	INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_bg_led_link_on,
+		  priv);
+	INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_bg_led_link_off,
+		  priv);
+	INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_bg_led_activity_off,
+		  priv);
+	INIT_WORK(&priv->merge_networks,
+		  (void (*)(void *))ipw_merge_adhoc_network, priv);
+
+#ifdef CONFIG_IPW_QOS
+	INIT_WORK(&priv->qos_activate, (void (*)(void *))ipw_bg_qos_activate,
+		  priv);
+#endif				/* CONFIG_IPW_QOS */
 
 	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
 		     ipw_irq_tasklet, (unsigned long)priv);
@@ -6689,34 +10174,36 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int i;
-
 	for (i = 0; i < 4; i++) {
 		if (sec->flags & (1 << i)) {
-			priv->sec.key_sizes[i] = sec->key_sizes[i];
+			priv->ieee->sec.encode_alg[i] = sec->encode_alg[i];
+			priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
 			if (sec->key_sizes[i] == 0)
-				priv->sec.flags &= ~(1 << i);
-			else
-				memcpy(priv->sec.keys[i], sec->keys[i],
+				priv->ieee->sec.flags &= ~(1 << i);
+			else {
+				memcpy(priv->ieee->sec.keys[i], sec->keys[i],
 				       sec->key_sizes[i]);
-			priv->sec.flags |= (1 << i);
+				priv->ieee->sec.flags |= (1 << i);
+			}
 			priv->status |= STATUS_SECURITY_UPDATED;
-		}
+		} else if (sec->level != SEC_LEVEL_1)
+			priv->ieee->sec.flags &= ~(1 << i);
 	}
 
-	if ((sec->flags & SEC_ACTIVE_KEY) &&
-	    priv->sec.active_key != sec->active_key) {
+	if (sec->flags & SEC_ACTIVE_KEY) {
 		if (sec->active_key <= 3) {
-			priv->sec.active_key = sec->active_key;
-			priv->sec.flags |= SEC_ACTIVE_KEY;
+			priv->ieee->sec.active_key = sec->active_key;
+			priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
 		} else
-			priv->sec.flags &= ~SEC_ACTIVE_KEY;
+			priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
 		priv->status |= STATUS_SECURITY_UPDATED;
-	}
+	} else
+		priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
 
 	if ((sec->flags & SEC_AUTH_MODE) &&
-	    (priv->sec.auth_mode != sec->auth_mode)) {
-		priv->sec.auth_mode = sec->auth_mode;
-		priv->sec.flags |= SEC_AUTH_MODE;
+	    (priv->ieee->sec.auth_mode != sec->auth_mode)) {
+		priv->ieee->sec.auth_mode = sec->auth_mode;
+		priv->ieee->sec.flags |= SEC_AUTH_MODE;
 		if (sec->auth_mode == WLAN_AUTH_SHARED_KEY)
 			priv->capability |= CAP_SHARED_KEY;
 		else
@@ -6724,9 +10211,9 @@
 		priv->status |= STATUS_SECURITY_UPDATED;
 	}
 
-	if (sec->flags & SEC_ENABLED && priv->sec.enabled != sec->enabled) {
-		priv->sec.flags |= SEC_ENABLED;
-		priv->sec.enabled = sec->enabled;
+	if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
+		priv->ieee->sec.flags |= SEC_ENABLED;
+		priv->ieee->sec.enabled = sec->enabled;
 		priv->status |= STATUS_SECURITY_UPDATED;
 		if (sec->enabled)
 			priv->capability |= CAP_PRIVACY_ON;
@@ -6734,12 +10221,18 @@
 			priv->capability &= ~CAP_PRIVACY_ON;
 	}
 
-	if (sec->flags & SEC_LEVEL && priv->sec.level != sec->level) {
-		priv->sec.level = sec->level;
-		priv->sec.flags |= SEC_LEVEL;
+	if (sec->flags & SEC_ENCRYPT)
+		priv->ieee->sec.encrypt = sec->encrypt;
+
+	if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
+		priv->ieee->sec.level = sec->level;
+		priv->ieee->sec.flags |= SEC_LEVEL;
 		priv->status |= STATUS_SECURITY_UPDATED;
 	}
 
+	if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT))
+		ipw_set_hwcrypto_keys(priv);
+
 	/* To match current functionality of ipw2100 (which works well w/
 	 * various supplicants, we don't force a disassociate if the
 	 * privacy capability changes ... */
@@ -6788,29 +10281,10 @@
 
 static int ipw_config(struct ipw_priv *priv)
 {
-	int i;
-	struct ipw_tx_power tx_power;
-
-	memset(&priv->sys_config, 0, sizeof(priv->sys_config));
-	memset(&tx_power, 0, sizeof(tx_power));
-
 	/* This is only called from ipw_up, which resets/reloads the firmware
 	   so, we don't need to first disable the card before we configure
 	   it */
-
-	/* configure device for 'G' band */
-	tx_power.ieee_mode = IPW_G_MODE;
-	tx_power.num_channels = 11;
-	for (i = 0; i < 11; i++) {
-		tx_power.channels_tx_power[i].channel_number = i + 1;
-		tx_power.channels_tx_power[i].tx_power = priv->tx_power;
-	}
-	if (ipw_send_tx_power(priv, &tx_power))
-		goto error;
-
-	/* configure device to also handle 'B' band */
-	tx_power.ieee_mode = IPW_B_MODE;
-	if (ipw_send_tx_power(priv, &tx_power))
+	if (ipw_set_tx_power(priv))
 		goto error;
 
 	/* initialize adapter address */
@@ -6819,6 +10293,11 @@
 
 	/* set basic system config settings */
 	init_sys_config(&priv->sys_config);
+	if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+		priv->sys_config.answer_broadcast_ssid_probe = 1;
+	else
+		priv->sys_config.answer_broadcast_ssid_probe = 0;
+
 	if (ipw_send_system_config(priv, &priv->sys_config))
 		goto error;
 
@@ -6831,6 +10310,10 @@
 		if (ipw_send_rts_threshold(priv, priv->rts_threshold))
 			goto error;
 	}
+#ifdef CONFIG_IPW_QOS
+	IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n");
+	ipw_qos_activate(priv, NULL);
+#endif				/* CONFIG_IPW_QOS */
 
 	if (ipw_set_random_seed(priv))
 		goto error;
@@ -6839,9 +10322,17 @@
 	if (ipw_send_host_complete(priv))
 		goto error;
 
-	/* If configured to try and auto-associate, kick off a scan */
-	if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv))
-		goto error;
+	priv->status |= STATUS_INIT;
+
+	ipw_led_init(priv);
+	ipw_led_radio_on(priv);
+	priv->notif_missed_beacons = 0;
+
+	/* Set hardware WEP key if it is configured. */
+	if ((priv->capability & CAP_PRIVACY_ON) &&
+	    (priv->ieee->sec.level == SEC_LEVEL_1) &&
+	    !(priv->ieee->host_encrypt || priv->ieee->host_decrypt))
+		ipw_set_hwcrypto_keys(priv);
 
 	return 0;
 
@@ -6849,20 +10340,379 @@
 	return -EIO;
 }
 
+/*
+ * NOTE:
+ *
+ * These tables have been tested in conjunction with the
+ * Intel PRO/Wireless 2200BG and 2915ABG Network Connection Adapters.
+ *
+ * Altering this values, using it on other hardware, or in geographies
+ * not intended for resale of the above mentioned Intel adapters has
+ * not been tested.
+ *
+ */
+static const struct ieee80211_geo ipw_geos[] = {
+	{			/* Restricted */
+	 "---",
+	 .bg_channels = 11,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}},
+	 },
+
+	{			/* Custom US/Canada */
+	 "ZZF",
+	 .bg_channels = 11,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}},
+	 .a_channels = 8,
+	 .a = {{5180, 36},
+	       {5200, 40},
+	       {5220, 44},
+	       {5240, 48},
+	       {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+	       {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+	       {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+	       {5320, 64, IEEE80211_CH_PASSIVE_ONLY}},
+	 },
+
+	{			/* Rest of World */
+	 "ZZD",
+	 .bg_channels = 13,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}, {2467, 12},
+		{2472, 13}},
+	 },
+
+	{			/* Custom USA & Europe & High */
+	 "ZZA",
+	 .bg_channels = 11,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}},
+	 .a_channels = 13,
+	 .a = {{5180, 36},
+	       {5200, 40},
+	       {5220, 44},
+	       {5240, 48},
+	       {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+	       {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+	       {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+	       {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+	       {5745, 149},
+	       {5765, 153},
+	       {5785, 157},
+	       {5805, 161},
+	       {5825, 165}},
+	 },
+
+	{			/* Custom NA & Europe */
+	 "ZZB",
+	 .bg_channels = 11,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}},
+	 .a_channels = 13,
+	 .a = {{5180, 36},
+	       {5200, 40},
+	       {5220, 44},
+	       {5240, 48},
+	       {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+	       {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+	       {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+	       {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+	       {5745, 149, IEEE80211_CH_PASSIVE_ONLY},
+	       {5765, 153, IEEE80211_CH_PASSIVE_ONLY},
+	       {5785, 157, IEEE80211_CH_PASSIVE_ONLY},
+	       {5805, 161, IEEE80211_CH_PASSIVE_ONLY},
+	       {5825, 165, IEEE80211_CH_PASSIVE_ONLY}},
+	 },
+
+	{			/* Custom Japan */
+	 "ZZC",
+	 .bg_channels = 11,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}},
+	 .a_channels = 4,
+	 .a = {{5170, 34}, {5190, 38},
+	       {5210, 42}, {5230, 46}},
+	 },
+
+	{			/* Custom */
+	 "ZZM",
+	 .bg_channels = 11,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}},
+	 },
+
+	{			/* Europe */
+	 "ZZE",
+	 .bg_channels = 13,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}, {2467, 12},
+		{2472, 13}},
+	 .a_channels = 19,
+	 .a = {{5180, 36},
+	       {5200, 40},
+	       {5220, 44},
+	       {5240, 48},
+	       {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+	       {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+	       {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+	       {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+	       {5500, 100, IEEE80211_CH_PASSIVE_ONLY},
+	       {5520, 104, IEEE80211_CH_PASSIVE_ONLY},
+	       {5540, 108, IEEE80211_CH_PASSIVE_ONLY},
+	       {5560, 112, IEEE80211_CH_PASSIVE_ONLY},
+	       {5580, 116, IEEE80211_CH_PASSIVE_ONLY},
+	       {5600, 120, IEEE80211_CH_PASSIVE_ONLY},
+	       {5620, 124, IEEE80211_CH_PASSIVE_ONLY},
+	       {5640, 128, IEEE80211_CH_PASSIVE_ONLY},
+	       {5660, 132, IEEE80211_CH_PASSIVE_ONLY},
+	       {5680, 136, IEEE80211_CH_PASSIVE_ONLY},
+	       {5700, 140, IEEE80211_CH_PASSIVE_ONLY}},
+	 },
+
+	{			/* Custom Japan */
+	 "ZZJ",
+	 .bg_channels = 14,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}, {2467, 12},
+		{2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY}},
+	 .a_channels = 4,
+	 .a = {{5170, 34}, {5190, 38},
+	       {5210, 42}, {5230, 46}},
+	 },
+
+	{			/* Rest of World */
+	 "ZZR",
+	 .bg_channels = 14,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}, {2467, 12},
+		{2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY |
+			     IEEE80211_CH_PASSIVE_ONLY}},
+	 },
+
+	{			/* High Band */
+	 "ZZH",
+	 .bg_channels = 13,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11},
+		{2467, 12, IEEE80211_CH_PASSIVE_ONLY},
+		{2472, 13, IEEE80211_CH_PASSIVE_ONLY}},
+	 .a_channels = 4,
+	 .a = {{5745, 149}, {5765, 153},
+	       {5785, 157}, {5805, 161}},
+	 },
+
+	{			/* Custom Europe */
+	 "ZZG",
+	 .bg_channels = 13,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11},
+		{2467, 12}, {2472, 13}},
+	 .a_channels = 4,
+	 .a = {{5180, 36}, {5200, 40},
+	       {5220, 44}, {5240, 48}},
+	 },
+
+	{			/* Europe */
+	 "ZZK",
+	 .bg_channels = 13,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11},
+		{2467, 12, IEEE80211_CH_PASSIVE_ONLY},
+		{2472, 13, IEEE80211_CH_PASSIVE_ONLY}},
+	 .a_channels = 24,
+	 .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY},
+	       {5200, 40, IEEE80211_CH_PASSIVE_ONLY},
+	       {5220, 44, IEEE80211_CH_PASSIVE_ONLY},
+	       {5240, 48, IEEE80211_CH_PASSIVE_ONLY},
+	       {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+	       {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+	       {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+	       {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+	       {5500, 100, IEEE80211_CH_PASSIVE_ONLY},
+	       {5520, 104, IEEE80211_CH_PASSIVE_ONLY},
+	       {5540, 108, IEEE80211_CH_PASSIVE_ONLY},
+	       {5560, 112, IEEE80211_CH_PASSIVE_ONLY},
+	       {5580, 116, IEEE80211_CH_PASSIVE_ONLY},
+	       {5600, 120, IEEE80211_CH_PASSIVE_ONLY},
+	       {5620, 124, IEEE80211_CH_PASSIVE_ONLY},
+	       {5640, 128, IEEE80211_CH_PASSIVE_ONLY},
+	       {5660, 132, IEEE80211_CH_PASSIVE_ONLY},
+	       {5680, 136, IEEE80211_CH_PASSIVE_ONLY},
+	       {5700, 140, IEEE80211_CH_PASSIVE_ONLY},
+	       {5745, 149, IEEE80211_CH_PASSIVE_ONLY},
+	       {5765, 153, IEEE80211_CH_PASSIVE_ONLY},
+	       {5785, 157, IEEE80211_CH_PASSIVE_ONLY},
+	       {5805, 161, IEEE80211_CH_PASSIVE_ONLY},
+	       {5825, 165, IEEE80211_CH_PASSIVE_ONLY}},
+	 },
+
+	{			/* Europe */
+	 "ZZL",
+	 .bg_channels = 11,
+	 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+		{2427, 4}, {2432, 5}, {2437, 6},
+		{2442, 7}, {2447, 8}, {2452, 9},
+		{2457, 10}, {2462, 11}},
+	 .a_channels = 13,
+	 .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY},
+	       {5200, 40, IEEE80211_CH_PASSIVE_ONLY},
+	       {5220, 44, IEEE80211_CH_PASSIVE_ONLY},
+	       {5240, 48, IEEE80211_CH_PASSIVE_ONLY},
+	       {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+	       {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+	       {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+	       {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+	       {5745, 149, IEEE80211_CH_PASSIVE_ONLY},
+	       {5765, 153, IEEE80211_CH_PASSIVE_ONLY},
+	       {5785, 157, IEEE80211_CH_PASSIVE_ONLY},
+	       {5805, 161, IEEE80211_CH_PASSIVE_ONLY},
+	       {5825, 165, IEEE80211_CH_PASSIVE_ONLY}},
+	 }
+};
+
+/* GEO code borrowed from ieee80211_geo.c */
+static int ipw_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
+{
+	int i;
+
+	/* Driver needs to initialize the geography map before using
+	 * these helper functions */
+	BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0);
+
+	if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+		for (i = 0; i < ieee->geo.bg_channels; i++)
+			/* NOTE: If G mode is currently supported but
+			 * this is a B only channel, we don't see it
+			 * as valid. */
+			if ((ieee->geo.bg[i].channel == channel) &&
+			    (!(ieee->mode & IEEE_G) ||
+			     !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY)))
+				return IEEE80211_24GHZ_BAND;
+
+	if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+		for (i = 0; i < ieee->geo.a_channels; i++)
+			if (ieee->geo.a[i].channel == channel)
+				return IEEE80211_52GHZ_BAND;
+
+	return 0;
+}
+
+static int ipw_channel_to_index(struct ieee80211_device *ieee, u8 channel)
+{
+	int i;
+
+	/* Driver needs to initialize the geography map before using
+	 * these helper functions */
+	BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0);
+
+	if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+		for (i = 0; i < ieee->geo.bg_channels; i++)
+			if (ieee->geo.bg[i].channel == channel)
+				return i;
+
+	if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+		for (i = 0; i < ieee->geo.a_channels; i++)
+			if (ieee->geo.a[i].channel == channel)
+				return i;
+
+	return -1;
+}
+
+static u8 ipw_freq_to_channel(struct ieee80211_device *ieee, u32 freq)
+{
+	int i;
+
+	/* Driver needs to initialize the geography map before using
+	 * these helper functions */
+	BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0);
+
+	freq /= 100000;
+
+	if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+		for (i = 0; i < ieee->geo.bg_channels; i++)
+			if (ieee->geo.bg[i].freq == freq)
+				return ieee->geo.bg[i].channel;
+
+	if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+		for (i = 0; i < ieee->geo.a_channels; i++)
+			if (ieee->geo.a[i].freq == freq)
+				return ieee->geo.a[i].channel;
+
+	return 0;
+}
+
+static int ipw_set_geo(struct ieee80211_device *ieee,
+		       const struct ieee80211_geo *geo)
+{
+	memcpy(ieee->geo.name, geo->name, 3);
+	ieee->geo.name[3] = '\0';
+	ieee->geo.bg_channels = geo->bg_channels;
+	ieee->geo.a_channels = geo->a_channels;
+	memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
+	       sizeof(struct ieee80211_channel));
+	memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
+	       sizeof(struct ieee80211_channel));
+	return 0;
+}
+
+static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *ieee)
+{
+	return &ieee->geo;
+}
+
 #define MAX_HW_RESTARTS 5
 static int ipw_up(struct ipw_priv *priv)
 {
-	int rc, i;
+	int rc, i, j;
 
 	if (priv->status & STATUS_EXIT_PENDING)
 		return -EIO;
 
+	if (cmdlog && !priv->cmdlog) {
+		priv->cmdlog = kmalloc(sizeof(*priv->cmdlog) * cmdlog,
+				       GFP_KERNEL);
+		if (priv->cmdlog == NULL) {
+			IPW_ERROR("Error allocating %d command log entries.\n",
+				  cmdlog);
+		} else {
+			memset(priv->cmdlog, 0, sizeof(*priv->cmdlog) * cmdlog);
+			priv->cmdlog_len = cmdlog;
+		}
+	}
+
 	for (i = 0; i < MAX_HW_RESTARTS; i++) {
 		/* Load the microcode, firmware, and eeprom.
 		 * Also start the clocks. */
 		rc = ipw_load(priv);
 		if (rc) {
-			IPW_ERROR("Unable to load firmware: 0x%08X\n", rc);
+			IPW_ERROR("Unable to load firmware: %d\n", rc);
 			return rc;
 		}
 
@@ -6871,20 +10721,50 @@
 			eeprom_parse_mac(priv, priv->mac_addr);
 		memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
 
-		if (priv->status & STATUS_RF_KILL_MASK)
+		for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) {
+			if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE],
+				    ipw_geos[j].name, 3))
+				break;
+		}
+		if (j == ARRAY_SIZE(ipw_geos)) {
+			IPW_WARNING("SKU [%c%c%c] not recognized.\n",
+				    priv->eeprom[EEPROM_COUNTRY_CODE + 0],
+				    priv->eeprom[EEPROM_COUNTRY_CODE + 1],
+				    priv->eeprom[EEPROM_COUNTRY_CODE + 2]);
+			j = 0;
+		}
+		if (ipw_set_geo(priv->ieee, &ipw_geos[j])) {
+			IPW_WARNING("Could not set geography.");
 			return 0;
+		}
+
+		IPW_DEBUG_INFO("Geography %03d [%s] detected.\n",
+			       j, priv->ieee->geo.name);
+
+		if (priv->status & STATUS_RF_KILL_SW) {
+			IPW_WARNING("Radio disabled by module parameter.\n");
+			return 0;
+		} else if (rf_kill_active(priv)) {
+			IPW_WARNING("Radio Frequency Kill Switch is On:\n"
+				    "Kill switch must be turned off for "
+				    "wireless networking to work.\n");
+			queue_delayed_work(priv->workqueue, &priv->rf_kill,
+					   2 * HZ);
+			return 0;
+		}
 
 		rc = ipw_config(priv);
 		if (!rc) {
 			IPW_DEBUG_INFO("Configured device on count %i\n", i);
-			priv->notif_missed_beacons = 0;
-			netif_start_queue(priv->net_dev);
+
+			/* If configure to try and auto-associate, kick
+			 * off a scan. */
+			queue_work(priv->workqueue, &priv->request_scan);
+
 			return 0;
-		} else {
-			IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n",
-				       rc);
 		}
 
+		IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", rc);
 		IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n",
 			       i, MAX_HW_RESTARTS);
 
@@ -6896,47 +10776,101 @@
 	/* tried to restart and config the device for as long as our
 	 * patience could withstand */
 	IPW_ERROR("Unable to initialize device after %d attempts.\n", i);
+
 	return -EIO;
 }
 
+static void ipw_bg_up(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_up(data);
+	up(&priv->sem);
+}
+
+static void ipw_deinit(struct ipw_priv *priv)
+{
+	int i;
+
+	if (priv->status & STATUS_SCANNING) {
+		IPW_DEBUG_INFO("Aborting scan during shutdown.\n");
+		ipw_abort_scan(priv);
+	}
+
+	if (priv->status & STATUS_ASSOCIATED) {
+		IPW_DEBUG_INFO("Disassociating during shutdown.\n");
+		ipw_disassociate(priv);
+	}
+
+	ipw_led_shutdown(priv);
+
+	/* Wait up to 1s for status to change to not scanning and not
+	 * associated (disassociation can take a while for a ful 802.11
+	 * exchange */
+	for (i = 1000; i && (priv->status &
+			     (STATUS_DISASSOCIATING |
+			      STATUS_ASSOCIATED | STATUS_SCANNING)); i--)
+		udelay(10);
+
+	if (priv->status & (STATUS_DISASSOCIATING |
+			    STATUS_ASSOCIATED | STATUS_SCANNING))
+		IPW_DEBUG_INFO("Still associated or scanning...\n");
+	else
+		IPW_DEBUG_INFO("Took %dms to de-init\n", 1000 - i);
+
+	/* Attempt to disable the card */
+	ipw_send_card_disable(priv, 0);
+
+	priv->status &= ~STATUS_INIT;
+}
+
 static void ipw_down(struct ipw_priv *priv)
 {
-	/* Attempt to disable the card */
-#if 0
-	ipw_send_card_disable(priv, 0);
-#endif
+	int exit_pending = priv->status & STATUS_EXIT_PENDING;
+
+	priv->status |= STATUS_EXIT_PENDING;
+
+	if (ipw_is_init(priv))
+		ipw_deinit(priv);
+
+	/* Wipe out the EXIT_PENDING status bit if we are not actually
+	 * exiting the module */
+	if (!exit_pending)
+		priv->status &= ~STATUS_EXIT_PENDING;
 
 	/* tell the device to stop sending interrupts */
 	ipw_disable_interrupts(priv);
 
 	/* Clear all bits but the RF Kill */
-	priv->status &= STATUS_RF_KILL_MASK;
-
+	priv->status &= STATUS_RF_KILL_MASK | STATUS_EXIT_PENDING;
 	netif_carrier_off(priv->net_dev);
 	netif_stop_queue(priv->net_dev);
 
 	ipw_stop_nic(priv);
+
+	ipw_led_radio_off(priv);
+}
+
+static void ipw_bg_down(void *data)
+{
+	struct ipw_priv *priv = data;
+	down(&priv->sem);
+	ipw_down(data);
+	up(&priv->sem);
 }
 
 /* Called by register_netdev() */
 static int ipw_net_init(struct net_device *dev)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
+	down(&priv->sem);
 
-	if (priv->status & STATUS_RF_KILL_SW) {
-		IPW_WARNING("Radio disabled by module parameter.\n");
-		return 0;
-	} else if (rf_kill_active(priv)) {
-		IPW_WARNING("Radio Frequency Kill Switch is On:\n"
-			    "Kill switch must be turned off for "
-			    "wireless networking to work.\n");
-		queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
-		return 0;
+	if (ipw_up(priv)) {
+		up(&priv->sem);
+		return -EIO;
 	}
 
-	if (ipw_up(priv))
-		return -EIO;
-
+	up(&priv->sem);
 	return 0;
 }
 
@@ -6961,7 +10895,7 @@
 	{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
 	{PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	/* BG */
-	{PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	/* 2225BG */
+	{PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	/* BG */
 	{PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	/* ABG */
 	{PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	/* ABG */
 
@@ -6981,11 +10915,16 @@
 	&dev_attr_nic_type.attr,
 	&dev_attr_status.attr,
 	&dev_attr_cfg.attr,
-	&dev_attr_dump_errors.attr,
-	&dev_attr_dump_events.attr,
+	&dev_attr_error.attr,
+	&dev_attr_event_log.attr,
+	&dev_attr_cmd_log.attr,
 	&dev_attr_eeprom_delay.attr,
 	&dev_attr_ucode_version.attr,
 	&dev_attr_rtc.attr,
+	&dev_attr_scan_age.attr,
+	&dev_attr_led.attr,
+	&dev_attr_speed_scan.attr,
+	&dev_attr_net_stats.attr,
 	NULL
 };
 
@@ -7001,7 +10940,7 @@
 	void __iomem *base;
 	u32 length, val;
 	struct ipw_priv *priv;
-	int band, modulation;
+	int i;
 
 	net_dev = alloc_ieee80211(sizeof(struct ipw_priv));
 	if (net_dev == NULL) {
@@ -7011,13 +10950,17 @@
 
 	priv = ieee80211_priv(net_dev);
 	priv->ieee = netdev_priv(net_dev);
+
 	priv->net_dev = net_dev;
 	priv->pci_dev = pdev;
 #ifdef CONFIG_IPW_DEBUG
 	ipw_debug_level = debug;
 #endif
 	spin_lock_init(&priv->lock);
+	for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
 
+	init_MUTEX(&priv->sem);
 	if (pci_enable_device(pdev)) {
 		err = -ENODEV;
 		goto out_free_ieee80211;
@@ -7064,90 +11007,7 @@
 		goto out_iounmap;
 	}
 
-	/* Initialize module parameter values here */
-	if (ifname)
-		strncpy(net_dev->name, ifname, IFNAMSIZ);
-
-	if (associate)
-		priv->config |= CFG_ASSOCIATE;
-	else
-		IPW_DEBUG_INFO("Auto associate disabled.\n");
-
-	if (auto_create)
-		priv->config |= CFG_ADHOC_CREATE;
-	else
-		IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
-
-	if (disable) {
-		priv->status |= STATUS_RF_KILL_SW;
-		IPW_DEBUG_INFO("Radio disabled.\n");
-	}
-
-	if (channel != 0) {
-		priv->config |= CFG_STATIC_CHANNEL;
-		priv->channel = channel;
-		IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
-		IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
-		/* TODO: Validate that provided channel is in range */
-	}
-
-	switch (mode) {
-	case 1:
-		priv->ieee->iw_mode = IW_MODE_ADHOC;
-		break;
-#ifdef CONFIG_IPW_PROMISC
-	case 2:
-		priv->ieee->iw_mode = IW_MODE_MONITOR;
-		break;
-#endif
-	default:
-	case 0:
-		priv->ieee->iw_mode = IW_MODE_INFRA;
-		break;
-	}
-
-	if ((priv->pci_dev->device == 0x4223) ||
-	    (priv->pci_dev->device == 0x4224)) {
-		printk(KERN_INFO DRV_NAME
-		       ": Detected Intel PRO/Wireless 2915ABG Network "
-		       "Connection\n");
-		priv->ieee->abg_true = 1;
-		band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND;
-		modulation = IEEE80211_OFDM_MODULATION |
-		    IEEE80211_CCK_MODULATION;
-		priv->adapter = IPW_2915ABG;
-		priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
-	} else {
-		if (priv->pci_dev->device == 0x4221)
-			printk(KERN_INFO DRV_NAME
-			       ": Detected Intel PRO/Wireless 2225BG Network "
-			       "Connection\n");
-		else
-			printk(KERN_INFO DRV_NAME
-			       ": Detected Intel PRO/Wireless 2200BG Network "
-			       "Connection\n");
-
-		priv->ieee->abg_true = 0;
-		band = IEEE80211_24GHZ_BAND;
-		modulation = IEEE80211_OFDM_MODULATION |
-		    IEEE80211_CCK_MODULATION;
-		priv->adapter = IPW_2200BG;
-		priv->ieee->mode = IEEE_G | IEEE_B;
-	}
-
-	priv->ieee->freq_band = band;
-	priv->ieee->modulation = modulation;
-
-	priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK;
-
-	priv->missed_beacon_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
-	priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
-
-	priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
-
-	/* If power management is turned on, default to AC mode */
-	priv->power_mode = IPW_POWER_AC;
-	priv->tx_power = IPW_DEFAULT_TX_POWER;
+	ipw_sw_reset(priv, 1);
 
 	err = request_irq(pdev->irq, ipw_isr, SA_SHIRQ, DRV_NAME, priv);
 	if (err) {
@@ -7158,8 +11018,20 @@
 	SET_MODULE_OWNER(net_dev);
 	SET_NETDEV_DEV(net_dev, &pdev->dev);
 
+	down(&priv->sem);
+
 	priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit;
 	priv->ieee->set_security = shim__set_security;
+	priv->ieee->is_queue_full = ipw_net_is_queue_full;
+
+#ifdef CONFIG_IPW_QOS
+	priv->ieee->handle_probe_response = ipw_handle_beacon;
+	priv->ieee->handle_beacon = ipw_handle_probe_response;
+	priv->ieee->handle_assoc_response = ipw_handle_assoc_response;
+#endif				/* CONFIG_IPW_QOS */
+
+	priv->ieee->perfect_rssi = -20;
+	priv->ieee->worst_rssi = -85;
 
 	net_dev->open = ipw_net_open;
 	net_dev->stop = ipw_net_stop;
@@ -7167,7 +11039,9 @@
 	net_dev->get_stats = ipw_net_get_stats;
 	net_dev->set_multicast_list = ipw_net_set_multicast_list;
 	net_dev->set_mac_address = ipw_net_set_mac_address;
-	net_dev->get_wireless_stats = ipw_get_wireless_stats;
+	priv->wireless_data.spy_data = &priv->ieee->spy_data;
+	priv->wireless_data.ieee80211 = priv->ieee;
+	net_dev->wireless_data = &priv->wireless_data;
 	net_dev->wireless_handlers = &ipw_wx_handler_def;
 	net_dev->ethtool_ops = &ipw_ethtool_ops;
 	net_dev->irq = pdev->irq;
@@ -7178,18 +11052,19 @@
 	err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);
 	if (err) {
 		IPW_ERROR("failed to create sysfs device attributes\n");
+		up(&priv->sem);
 		goto out_release_irq;
 	}
 
+	up(&priv->sem);
 	err = register_netdev(net_dev);
 	if (err) {
 		IPW_ERROR("failed to register network device\n");
-		goto out_remove_group;
+		goto out_remove_sysfs;
 	}
-
 	return 0;
 
-      out_remove_group:
+      out_remove_sysfs:
 	sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
       out_release_irq:
 	free_irq(pdev->irq, priv);
@@ -7212,14 +11087,19 @@
 static void ipw_pci_remove(struct pci_dev *pdev)
 {
 	struct ipw_priv *priv = pci_get_drvdata(pdev);
+	struct list_head *p, *q;
+	int i;
+
 	if (!priv)
 		return;
 
-	priv->status |= STATUS_EXIT_PENDING;
+	down(&priv->sem);
 
+	priv->status |= STATUS_EXIT_PENDING;
+	ipw_down(priv);
 	sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
 
-	ipw_down(priv);
+	up(&priv->sem);
 
 	unregister_netdev(priv->net_dev);
 
@@ -7229,16 +11109,31 @@
 	}
 	ipw_tx_queue_free(priv);
 
+	if (priv->cmdlog) {
+		kfree(priv->cmdlog);
+		priv->cmdlog = NULL;
+	}
 	/* ipw_down will ensure that there is no more pending work
 	 * in the workqueue's, so we can safely remove them now. */
-	if (priv->workqueue) {
-		cancel_delayed_work(&priv->adhoc_check);
-		cancel_delayed_work(&priv->gather_stats);
-		cancel_delayed_work(&priv->request_scan);
-		cancel_delayed_work(&priv->rf_kill);
-		cancel_delayed_work(&priv->scan_check);
-		destroy_workqueue(priv->workqueue);
-		priv->workqueue = NULL;
+	cancel_delayed_work(&priv->adhoc_check);
+	cancel_delayed_work(&priv->gather_stats);
+	cancel_delayed_work(&priv->request_scan);
+	cancel_delayed_work(&priv->rf_kill);
+	cancel_delayed_work(&priv->scan_check);
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+
+	/* Free MAC hash list for ADHOC */
+	for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) {
+		list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
+			kfree(list_entry(p, struct ipw_ibss_seq, list));
+			list_del(p);
+		}
+	}
+
+	if (priv->error) {
+		ipw_free_error_log(priv->error);
+		priv->error = NULL;
 	}
 
 	free_irq(pdev->irq, priv);
@@ -7247,15 +11142,7 @@
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 	free_ieee80211(priv->net_dev);
-
-#ifdef CONFIG_PM
-	if (fw_loaded) {
-		release_firmware(bootfw);
-		release_firmware(ucode);
-		release_firmware(firmware);
-		fw_loaded = 0;
-	}
-#endif
+	free_firmware();
 }
 
 #ifdef CONFIG_PM
@@ -7287,13 +11174,10 @@
 
 	printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
 
-	pci_set_power_state(pdev, 0);
+	pci_set_power_state(pdev, PCI_D0);
 	pci_enable_device(pdev);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
-	pci_restore_state(pdev, priv->pm_state);
-#else
 	pci_restore_state(pdev);
-#endif
+
 	/*
 	 * Suspend/Resume resets the PCI configuration space, so we have to
 	 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
@@ -7365,16 +11249,33 @@
 module_param(auto_create, int, 0444);
 MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
 
+module_param(led, int, 0444);
+MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n");
+
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
 
 module_param(channel, int, 0444);
 MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
 
-module_param(ifname, charp, 0444);
-MODULE_PARM_DESC(ifname, "network device name (default eth%d)");
+#ifdef CONFIG_IPW_QOS
+module_param(qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis");
 
-#ifdef CONFIG_IPW_PROMISC
+module_param(qos_burst_enable, int, 0444);
+MODULE_PARM_DESC(qos_burst_enable, "enable QoS burst mode");
+
+module_param(qos_no_ack_mask, int, 0444);
+MODULE_PARM_DESC(qos_no_ack_mask, "mask Tx_Queue to no ack");
+
+module_param(burst_duration_CCK, int, 0444);
+MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value");
+
+module_param(burst_duration_OFDM, int, 0444);
+MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value");
+#endif				/* CONFIG_IPW_QOS */
+
+#ifdef CONFIG_IPW2200_MONITOR
 module_param(mode, int, 0444);
 MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
 #else
@@ -7382,5 +11283,12 @@
 MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
 #endif
 
+module_param(hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)");
+
+module_param(cmdlog, int, 0444);
+MODULE_PARM_DESC(cmdlog,
+		 "allocate a ring buffer for logging firmware commands");
+
 module_exit(ipw_exit);
 module_init(ipw_init);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index e9cf32b..1c98db0 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1,6 +1,6 @@
 /******************************************************************************
 
-  Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,6 @@
 #include <linux/config.h>
 #include <linux/init.h>
 
-#include <linux/version.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
@@ -50,6 +49,7 @@
 #include <asm/io.h>
 
 #include <net/ieee80211.h>
+#include <net/ieee80211_radiotap.h>
 
 #define DRV_NAME	"ipw2200"
 
@@ -161,6 +161,16 @@
  * TX Queue Flag Definitions
  */
 
+/* tx wep key definition */
+#define DCT_WEP_KEY_NOT_IMMIDIATE	0x00
+#define DCT_WEP_KEY_64Bit		0x40
+#define DCT_WEP_KEY_128Bit		0x80
+#define DCT_WEP_KEY_128bitIV		0xC0
+#define DCT_WEP_KEY_SIZE_MASK		0xC0
+
+#define DCT_WEP_KEY_INDEX_MASK		0x0F
+#define DCT_WEP_INDEX_USE_IMMEDIATE	0x20
+
 /* abort attempt if mgmt frame is rx'd */
 #define DCT_FLAG_ABORT_MGMT                0x01
 
@@ -168,7 +178,8 @@
 #define DCT_FLAG_CTS_REQUIRED              0x02
 
 /* use short preamble */
-#define DCT_FLAG_SHORT_PREMBL              0x04
+#define DCT_FLAG_LONG_PREAMBLE             0x00
+#define DCT_FLAG_SHORT_PREAMBLE            0x04
 
 /* RTS/CTS first */
 #define DCT_FLAG_RTS_REQD                  0x08
@@ -185,9 +196,23 @@
 /* ACK rx is expected to follow */
 #define DCT_FLAG_ACK_REQD                  0x80
 
+/* TX flags extension */
 #define DCT_FLAG_EXT_MODE_CCK  0x01
 #define DCT_FLAG_EXT_MODE_OFDM 0x00
 
+#define DCT_FLAG_EXT_SECURITY_WEP     0x00
+#define DCT_FLAG_EXT_SECURITY_NO      DCT_FLAG_EXT_SECURITY_WEP
+#define DCT_FLAG_EXT_SECURITY_CKIP    0x04
+#define DCT_FLAG_EXT_SECURITY_CCM     0x08
+#define DCT_FLAG_EXT_SECURITY_TKIP    0x0C
+#define DCT_FLAG_EXT_SECURITY_MASK    0x0C
+
+#define DCT_FLAG_EXT_QOS_ENABLED      0x10
+
+#define DCT_FLAG_EXT_HC_NO_SIFS_PIFS  0x00
+#define DCT_FLAG_EXT_HC_SIFS          0x20
+#define DCT_FLAG_EXT_HC_PIFS          0x40
+
 #define TX_RX_TYPE_MASK                    0xFF
 #define TX_FRAME_TYPE                      0x00
 #define TX_HOST_COMMAND_TYPE               0x01
@@ -233,6 +258,117 @@
 #define DCR_TYPE_SNIFFER                  0x06
 #define DCR_TYPE_MU_BSS        DCR_TYPE_MU_ESS
 
+/* QoS  definitions */
+
+#define CW_MIN_OFDM          15
+#define CW_MAX_OFDM          1023
+#define CW_MIN_CCK           31
+#define CW_MAX_CCK           1023
+
+#define QOS_TX0_CW_MIN_OFDM      CW_MIN_OFDM
+#define QOS_TX1_CW_MIN_OFDM      CW_MIN_OFDM
+#define QOS_TX2_CW_MIN_OFDM      ( (CW_MIN_OFDM + 1) / 2 - 1 )
+#define QOS_TX3_CW_MIN_OFDM      ( (CW_MIN_OFDM + 1) / 4 - 1 )
+
+#define QOS_TX0_CW_MIN_CCK       CW_MIN_CCK
+#define QOS_TX1_CW_MIN_CCK       CW_MIN_CCK
+#define QOS_TX2_CW_MIN_CCK       ( (CW_MIN_CCK + 1) / 2 - 1 )
+#define QOS_TX3_CW_MIN_CCK       ( (CW_MIN_CCK + 1) / 4 - 1 )
+
+#define QOS_TX0_CW_MAX_OFDM      CW_MAX_OFDM
+#define QOS_TX1_CW_MAX_OFDM      CW_MAX_OFDM
+#define QOS_TX2_CW_MAX_OFDM      CW_MIN_OFDM
+#define QOS_TX3_CW_MAX_OFDM      ( (CW_MIN_OFDM + 1) / 2 - 1 )
+
+#define QOS_TX0_CW_MAX_CCK       CW_MAX_CCK
+#define QOS_TX1_CW_MAX_CCK       CW_MAX_CCK
+#define QOS_TX2_CW_MAX_CCK       CW_MIN_CCK
+#define QOS_TX3_CW_MAX_CCK       ( (CW_MIN_CCK + 1) / 2 - 1 )
+
+#define QOS_TX0_AIFS            (3 - QOS_AIFSN_MIN_VALUE)
+#define QOS_TX1_AIFS            (7 - QOS_AIFSN_MIN_VALUE)
+#define QOS_TX2_AIFS            (2 - QOS_AIFSN_MIN_VALUE)
+#define QOS_TX3_AIFS            (2 - QOS_AIFSN_MIN_VALUE)
+
+#define QOS_TX0_ACM             0
+#define QOS_TX1_ACM             0
+#define QOS_TX2_ACM             0
+#define QOS_TX3_ACM             0
+
+#define QOS_TX0_TXOP_LIMIT_CCK          0
+#define QOS_TX1_TXOP_LIMIT_CCK          0
+#define QOS_TX2_TXOP_LIMIT_CCK          6016
+#define QOS_TX3_TXOP_LIMIT_CCK          3264
+
+#define QOS_TX0_TXOP_LIMIT_OFDM      0
+#define QOS_TX1_TXOP_LIMIT_OFDM      0
+#define QOS_TX2_TXOP_LIMIT_OFDM      3008
+#define QOS_TX3_TXOP_LIMIT_OFDM      1504
+
+#define DEF_TX0_CW_MIN_OFDM      CW_MIN_OFDM
+#define DEF_TX1_CW_MIN_OFDM      CW_MIN_OFDM
+#define DEF_TX2_CW_MIN_OFDM      CW_MIN_OFDM
+#define DEF_TX3_CW_MIN_OFDM      CW_MIN_OFDM
+
+#define DEF_TX0_CW_MIN_CCK       CW_MIN_CCK
+#define DEF_TX1_CW_MIN_CCK       CW_MIN_CCK
+#define DEF_TX2_CW_MIN_CCK       CW_MIN_CCK
+#define DEF_TX3_CW_MIN_CCK       CW_MIN_CCK
+
+#define DEF_TX0_CW_MAX_OFDM      CW_MAX_OFDM
+#define DEF_TX1_CW_MAX_OFDM      CW_MAX_OFDM
+#define DEF_TX2_CW_MAX_OFDM      CW_MAX_OFDM
+#define DEF_TX3_CW_MAX_OFDM      CW_MAX_OFDM
+
+#define DEF_TX0_CW_MAX_CCK       CW_MAX_CCK
+#define DEF_TX1_CW_MAX_CCK       CW_MAX_CCK
+#define DEF_TX2_CW_MAX_CCK       CW_MAX_CCK
+#define DEF_TX3_CW_MAX_CCK       CW_MAX_CCK
+
+#define DEF_TX0_AIFS            0
+#define DEF_TX1_AIFS            0
+#define DEF_TX2_AIFS            0
+#define DEF_TX3_AIFS            0
+
+#define DEF_TX0_ACM             0
+#define DEF_TX1_ACM             0
+#define DEF_TX2_ACM             0
+#define DEF_TX3_ACM             0
+
+#define DEF_TX0_TXOP_LIMIT_CCK        0
+#define DEF_TX1_TXOP_LIMIT_CCK        0
+#define DEF_TX2_TXOP_LIMIT_CCK        0
+#define DEF_TX3_TXOP_LIMIT_CCK        0
+
+#define DEF_TX0_TXOP_LIMIT_OFDM       0
+#define DEF_TX1_TXOP_LIMIT_OFDM       0
+#define DEF_TX2_TXOP_LIMIT_OFDM       0
+#define DEF_TX3_TXOP_LIMIT_OFDM       0
+
+#define QOS_QOS_SETS                  3
+#define QOS_PARAM_SET_ACTIVE          0
+#define QOS_PARAM_SET_DEF_CCK         1
+#define QOS_PARAM_SET_DEF_OFDM        2
+
+#define CTRL_QOS_NO_ACK               (0x0020)
+
+#define IPW_TX_QUEUE_1        1
+#define IPW_TX_QUEUE_2        2
+#define IPW_TX_QUEUE_3        3
+#define IPW_TX_QUEUE_4        4
+
+/* QoS sturctures */
+struct ipw_qos_info {
+	int qos_enable;
+	struct ieee80211_qos_parameters *def_qos_parm_OFDM;
+	struct ieee80211_qos_parameters *def_qos_parm_CCK;
+	u32 burst_duration_CCK;
+	u32 burst_duration_OFDM;
+	u16 qos_no_ack_mask;
+	int burst_enable;
+};
+
+/**************************************************************/
 /**
  * Generic queue structure
  *
@@ -402,9 +538,9 @@
 #define RX_FREE_BUFFERS 32
 #define RX_LOW_WATERMARK 8
 
-#define SUP_RATE_11A_MAX_NUM_CHANNELS  (8)
-#define SUP_RATE_11B_MAX_NUM_CHANNELS  (4)
-#define SUP_RATE_11G_MAX_NUM_CHANNELS  (12)
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
 
 // Used for passing to driver number of successes and failures per rate
 struct rate_histogram {
@@ -453,6 +589,9 @@
 	u8 uReserved;
 } __attribute__ ((packed));
 
+#define SCAN_COMPLETED_STATUS_COMPLETE  1
+#define SCAN_COMPLETED_STATUS_ABORTED   2
+
 struct notif_scan_complete {
 	u8 scan_type;
 	u8 num_channels;
@@ -563,8 +702,8 @@
 } __attribute__ ((packed));
 
 #define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
-#define IPW_RX_FRAME_SIZE        sizeof(struct ipw_rx_header) + \
-                                 sizeof(struct ipw_rx_frame)
+#define IPW_RX_FRAME_SIZE        (unsigned int)(sizeof(struct ipw_rx_header) + \
+                                 sizeof(struct ipw_rx_frame))
 
 struct ipw_rx_mem_buffer {
 	dma_addr_t dma_addr;
@@ -657,6 +796,19 @@
 	u8 mac4[6];
 } __attribute__ ((packed));
 
+#define DCW_WEP_KEY_INDEX_MASK		0x03	/* bits [0:1] */
+#define DCW_WEP_KEY_SEC_TYPE_MASK	0x30	/* bits [4:5] */
+
+#define DCW_WEP_KEY_SEC_TYPE_WEP	0x00
+#define DCW_WEP_KEY_SEC_TYPE_CCM	0x20
+#define DCW_WEP_KEY_SEC_TYPE_TKIP	0x30
+
+#define DCW_WEP_KEY_INVALID_SIZE	0x00	/* 0 = Invalid key */
+#define DCW_WEP_KEY64Bit_SIZE		0x05	/* 64-bit encryption */
+#define DCW_WEP_KEY128Bit_SIZE		0x0D	/* 128-bit encryption */
+#define DCW_CCM_KEY128Bit_SIZE		0x10	/* 128-bit key */
+//#define DCW_WEP_KEY128BitIV_SIZE      0x10    /* 128-bit key and 128-bit IV */
+
 struct ipw_wep_key {
 	u8 cmd_id;
 	u8 seq_num;
@@ -818,14 +970,6 @@
 	struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
 } __attribute__ ((packed));
 
-struct ipw_qos_parameters {
-	u16 cw_min[4];
-	u16 cw_max[4];
-	u8 aifs[4];
-	u8 flag[4];
-	u16 tx_op_limit[4];
-} __attribute__ ((packed));
-
 struct ipw_rsn_capabilities {
 	u8 id;
 	u8 length;
@@ -888,6 +1032,10 @@
 #define STATUS_SCAN_PENDING     (1<<20)
 #define STATUS_SCANNING         (1<<21)
 #define STATUS_SCAN_ABORTING    (1<<22)
+#define STATUS_SCAN_FORCED      (1<<23)
+
+#define STATUS_LED_LINK_ON      (1<<24)
+#define STATUS_LED_ACT_ON       (1<<25)
 
 #define STATUS_INDIRECT_BYTE    (1<<28)	/* sysfs entry configured for access */
 #define STATUS_INDIRECT_DWORD   (1<<29)	/* sysfs entry configured for access */
@@ -899,11 +1047,15 @@
 #define CFG_STATIC_ESSID        (1<<1)	/* Restrict assoc. to single SSID */
 #define CFG_STATIC_BSSID        (1<<2)	/* Restrict assoc. to single BSSID */
 #define CFG_CUSTOM_MAC          (1<<3)
-#define CFG_PREAMBLE            (1<<4)
+#define CFG_PREAMBLE_LONG       (1<<4)
 #define CFG_ADHOC_PERSIST       (1<<5)
 #define CFG_ASSOCIATE           (1<<6)
 #define CFG_FIXED_RATE          (1<<7)
 #define CFG_ADHOC_CREATE        (1<<8)
+#define CFG_NO_LED              (1<<9)
+#define CFG_BACKGROUND_SCAN     (1<<10)
+#define CFG_SPEED_SCAN          (1<<11)
+#define CFG_NET_STATS           (1<<12)
 
 #define CAP_SHARED_KEY          (1<<0)	/* Off = OPEN */
 #define CAP_PRIVACY_ON          (1<<1)	/* Off = No privacy */
@@ -925,13 +1077,50 @@
 	s32 sum;
 };
 
+#define MAX_SPEED_SCAN 100
+#define IPW_IBSS_MAC_HASH_SIZE 31
+
+struct ipw_ibss_seq {
+	u8 mac[ETH_ALEN];
+	u16 seq_num;
+	u16 frag_num;
+	unsigned long packet_time;
+	struct list_head list;
+};
+
+struct ipw_error_elem {
+	u32 desc;
+	u32 time;
+	u32 blink1;
+	u32 blink2;
+	u32 link1;
+	u32 link2;
+	u32 data;
+};
+
+struct ipw_event {
+	u32 event;
+	u32 time;
+	u32 data;
+} __attribute__ ((packed));
+
+struct ipw_fw_error {
+	unsigned long jiffies;
+	u32 status;
+	u32 config;
+	u32 elem_len;
+	u32 log_len;
+	struct ipw_error_elem *elem;
+	struct ipw_event *log;
+	u8 payload[0];
+} __attribute__ ((packed));
+
 struct ipw_priv {
 	/* ieee device used by generic ieee processing code */
 	struct ieee80211_device *ieee;
-	struct ieee80211_security sec;
 
-	/* spinlock */
 	spinlock_t lock;
+	struct semaphore sem;
 
 	/* basic pci-network driver stuff */
 	struct pci_dev *pci_dev;
@@ -966,7 +1155,7 @@
 	int rx_bufs_min;	  /**< minimum number of bufs in Rx queue */
 	int rx_pend_max;	  /**< maximum pending buffers for one IRQ */
 	u32 hcmd_seq;		  /**< sequence number for hcmd */
-	u32 missed_beacon_threshold;
+	u32 disassociate_threshold;
 	u32 roaming_threshold;
 
 	struct ipw_associate assoc_request;
@@ -1007,6 +1196,8 @@
 	u8 mac_addr[ETH_ALEN];
 	u8 num_stations;
 	u8 stations[MAX_STATIONS][ETH_ALEN];
+	u8 short_retry_limit;
+	u8 long_retry_limit;
 
 	u32 notif_missed_beacons;
 
@@ -1024,17 +1215,29 @@
 	u32 tx_packets;
 	u32 quality;
 
+	u8 speed_scan[MAX_SPEED_SCAN];
+	u8 speed_scan_pos;
+
+	u16 last_seq_num;
+	u16 last_frag_num;
+	unsigned long last_packet_time;
+	struct list_head ibss_mac_hash[IPW_IBSS_MAC_HASH_SIZE];
+
 	/* eeprom */
 	u8 eeprom[0x100];	/* 256 bytes of eeprom */
+	u8 country[4];
 	int eeprom_delay;
 
 	struct iw_statistics wstats;
 
+	struct iw_public_data wireless_data;
+
 	struct workqueue_struct *workqueue;
 
 	struct work_struct adhoc_check;
 	struct work_struct associate;
 	struct work_struct disassociate;
+	struct work_struct system_config;
 	struct work_struct rx_replenish;
 	struct work_struct request_scan;
 	struct work_struct adapter_restart;
@@ -1045,25 +1248,51 @@
 	struct work_struct abort_scan;
 	struct work_struct roam;
 	struct work_struct scan_check;
+	struct work_struct link_up;
+	struct work_struct link_down;
 
 	struct tasklet_struct irq_tasklet;
 
+	/* LED related variables and work_struct */
+	u8 nic_type;
+	u32 led_activity_on;
+	u32 led_activity_off;
+	u32 led_association_on;
+	u32 led_association_off;
+	u32 led_ofdm_on;
+	u32 led_ofdm_off;
+
+	struct work_struct led_link_on;
+	struct work_struct led_link_off;
+	struct work_struct led_act_off;
+	struct work_struct merge_networks;
+
+	struct ipw_cmd_log *cmdlog;
+	int cmdlog_len;
+	int cmdlog_pos;
+
 #define IPW_2200BG  1
 #define IPW_2915ABG 2
 	u8 adapter;
 
-#define IPW_DEFAULT_TX_POWER 0x14
-	u8 tx_power;
+	s8 tx_power;
 
 #ifdef CONFIG_PM
 	u32 pm_state[16];
 #endif
 
+	struct ipw_fw_error *error;
+
 	/* network state */
 
 	/* Used to pass the current INTA value from ISR to Tasklet */
 	u32 isr_inta;
 
+	/* QoS */
+	struct ipw_qos_info qos_data;
+	struct work_struct qos_activate;
+	/*********************************/
+
 	/* debugging info */
 	u32 indirect_dword;
 	u32 direct_dword;
@@ -1125,6 +1354,8 @@
 #define IPW_DL_RF_KILL       (1<<17)
 #define IPW_DL_FW_ERRORS     (1<<18)
 
+#define IPW_DL_LED           (1<<19)
+
 #define IPW_DL_ORD           (1<<20)
 
 #define IPW_DL_FRAG          (1<<21)
@@ -1137,6 +1368,8 @@
 #define IPW_DL_TRACE         (1<<28)
 
 #define IPW_DL_STATS         (1<<29)
+#define IPW_DL_MERGE         (1<<30)
+#define IPW_DL_QOS           (1<<31)
 
 #define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
 #define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
@@ -1150,6 +1383,7 @@
 #define IPW_DEBUG_TX(f, a...)     IPW_DEBUG(IPW_DL_TX, f, ## a)
 #define IPW_DEBUG_ISR(f, a...)    IPW_DEBUG(IPW_DL_ISR, f, ## a)
 #define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a)
+#define IPW_DEBUG_LED(f, a...) IPW_DEBUG(IPW_DL_LED, f, ## a)
 #define IPW_DEBUG_WEP(f, a...)    IPW_DEBUG(IPW_DL_WEP, f, ## a)
 #define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
 #define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a)
@@ -1163,6 +1397,8 @@
 #define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
 #define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
 #define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a)
+#define IPW_DEBUG_MERGE(f, a...) IPW_DEBUG(IPW_DL_MERGE, f, ## a)
+#define IPW_DEBUG_QOS(f, a...)   IPW_DEBUG(IPW_DL_QOS, f, ## a)
 
 #include <linux/ctype.h>
 
@@ -1177,59 +1413,65 @@
 #define DINO_RXFIFO_DATA   0x01
 #define DINO_CONTROL_REG   0x00200000
 
-#define CX2_INTA_RW       0x00000008
-#define CX2_INTA_MASK_R   0x0000000C
-#define CX2_INDIRECT_ADDR 0x00000010
-#define CX2_INDIRECT_DATA 0x00000014
-#define CX2_AUTOINC_ADDR  0x00000018
-#define CX2_AUTOINC_DATA  0x0000001C
-#define CX2_RESET_REG     0x00000020
-#define CX2_GP_CNTRL_RW   0x00000024
+#define IPW_INTA_RW       0x00000008
+#define IPW_INTA_MASK_R   0x0000000C
+#define IPW_INDIRECT_ADDR 0x00000010
+#define IPW_INDIRECT_DATA 0x00000014
+#define IPW_AUTOINC_ADDR  0x00000018
+#define IPW_AUTOINC_DATA  0x0000001C
+#define IPW_RESET_REG     0x00000020
+#define IPW_GP_CNTRL_RW   0x00000024
 
-#define CX2_READ_INT_REGISTER 0xFF4
+#define IPW_READ_INT_REGISTER 0xFF4
 
-#define CX2_GP_CNTRL_BIT_INIT_DONE	0x00000004
+#define IPW_GP_CNTRL_BIT_INIT_DONE	0x00000004
 
-#define CX2_REGISTER_DOMAIN1_END        0x00001000
-#define CX2_SRAM_READ_INT_REGISTER 	0x00000ff4
+#define IPW_REGISTER_DOMAIN1_END        0x00001000
+#define IPW_SRAM_READ_INT_REGISTER 	0x00000ff4
 
-#define CX2_SHARED_LOWER_BOUND          0x00000200
-#define CX2_INTERRUPT_AREA_LOWER_BOUND  0x00000f80
+#define IPW_SHARED_LOWER_BOUND          0x00000200
+#define IPW_INTERRUPT_AREA_LOWER_BOUND  0x00000f80
 
-#define CX2_NIC_SRAM_LOWER_BOUND        0x00000000
-#define CX2_NIC_SRAM_UPPER_BOUND        0x00030000
+#define IPW_NIC_SRAM_LOWER_BOUND        0x00000000
+#define IPW_NIC_SRAM_UPPER_BOUND        0x00030000
 
-#define CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29)
-#define CX2_GP_CNTRL_BIT_CLOCK_READY    0x00000001
-#define CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002
+#define IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29)
+#define IPW_GP_CNTRL_BIT_CLOCK_READY    0x00000001
+#define IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002
 
 /*
  * RESET Register Bit Indexes
  */
-#define CBD_RESET_REG_PRINCETON_RESET 0x00000001	/* Bit 0 (LSB) */
-#define CX2_RESET_REG_SW_RESET        0x00000080	/* Bit 7       */
-#define CX2_RESET_REG_MASTER_DISABLED 0x00000100	/* Bit 8       */
-#define CX2_RESET_REG_STOP_MASTER     0x00000200	/* Bit 9       */
-#define CX2_ARC_KESHET_CONFIG         0x08000000	/* Bit 27      */
-#define CX2_START_STANDBY             0x00000004	/* Bit 2       */
+#define CBD_RESET_REG_PRINCETON_RESET (1<<0)
+#define IPW_START_STANDBY             (1<<2)
+#define IPW_ACTIVITY_LED              (1<<4)
+#define IPW_ASSOCIATED_LED            (1<<5)
+#define IPW_OFDM_LED                  (1<<6)
+#define IPW_RESET_REG_SW_RESET        (1<<7)
+#define IPW_RESET_REG_MASTER_DISABLED (1<<8)
+#define IPW_RESET_REG_STOP_MASTER     (1<<9)
+#define IPW_GATE_ODMA                 (1<<25)
+#define IPW_GATE_IDMA                 (1<<26)
+#define IPW_ARC_KESHET_CONFIG         (1<<27)
+#define IPW_GATE_ADMA                 (1<<29)
 
-#define CX2_CSR_CIS_UPPER_BOUND	0x00000200
-#define CX2_DOMAIN_0_END 0x1000
+#define IPW_CSR_CIS_UPPER_BOUND	0x00000200
+#define IPW_DOMAIN_0_END 0x1000
 #define CLX_MEM_BAR_SIZE 0x1000
 
-#define CX2_BASEBAND_CONTROL_STATUS	0X00200000
-#define CX2_BASEBAND_TX_FIFO_WRITE	0X00200004
-#define CX2_BASEBAND_RX_FIFO_READ	0X00200004
-#define CX2_BASEBAND_CONTROL_STORE	0X00200010
+#define IPW_BASEBAND_CONTROL_STATUS	0X00200000
+#define IPW_BASEBAND_TX_FIFO_WRITE	0X00200004
+#define IPW_BASEBAND_RX_FIFO_READ	0X00200004
+#define IPW_BASEBAND_CONTROL_STORE	0X00200010
 
-#define CX2_INTERNAL_CMD_EVENT 	0X00300004
-#define CX2_BASEBAND_POWER_DOWN 0x00000001
+#define IPW_INTERNAL_CMD_EVENT 	0X00300004
+#define IPW_BASEBAND_POWER_DOWN 0x00000001
 
-#define CX2_MEM_HALT_AND_RESET  0x003000e0
+#define IPW_MEM_HALT_AND_RESET  0x003000e0
 
 /* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */
-#define CX2_BIT_HALT_RESET_ON	0x80000000
-#define CX2_BIT_HALT_RESET_OFF 	0x00000000
+#define IPW_BIT_HALT_RESET_ON	0x80000000
+#define IPW_BIT_HALT_RESET_OFF 	0x00000000
 
 #define CB_LAST_VALID     0x20000000
 #define CB_INT_ENABLED    0x40000000
@@ -1248,63 +1490,63 @@
 #define DMA_CB_STOP_AND_ABORT            0x00000C00
 #define DMA_CB_START                     0x00000100
 
-#define CX2_SHARED_SRAM_SIZE               0x00030000
-#define CX2_SHARED_SRAM_DMA_CONTROL        0x00027000
+#define IPW_SHARED_SRAM_SIZE               0x00030000
+#define IPW_SHARED_SRAM_DMA_CONTROL        0x00027000
 #define CB_MAX_LENGTH                      0x1FFF
 
-#define CX2_HOST_EEPROM_DATA_SRAM_SIZE 0xA18
-#define CX2_EEPROM_IMAGE_SIZE          0x100
+#define IPW_HOST_EEPROM_DATA_SRAM_SIZE 0xA18
+#define IPW_EEPROM_IMAGE_SIZE          0x100
 
 /* DMA defs */
-#define CX2_DMA_I_CURRENT_CB  0x003000D0
-#define CX2_DMA_O_CURRENT_CB  0x003000D4
-#define CX2_DMA_I_DMA_CONTROL 0x003000A4
-#define CX2_DMA_I_CB_BASE     0x003000A0
+#define IPW_DMA_I_CURRENT_CB  0x003000D0
+#define IPW_DMA_O_CURRENT_CB  0x003000D4
+#define IPW_DMA_I_DMA_CONTROL 0x003000A4
+#define IPW_DMA_I_CB_BASE     0x003000A0
 
-#define CX2_TX_CMD_QUEUE_BD_BASE        (0x00000200)
-#define CX2_TX_CMD_QUEUE_BD_SIZE        (0x00000204)
-#define CX2_TX_QUEUE_0_BD_BASE          (0x00000208)
-#define CX2_TX_QUEUE_0_BD_SIZE          (0x0000020C)
-#define CX2_TX_QUEUE_1_BD_BASE          (0x00000210)
-#define CX2_TX_QUEUE_1_BD_SIZE          (0x00000214)
-#define CX2_TX_QUEUE_2_BD_BASE          (0x00000218)
-#define CX2_TX_QUEUE_2_BD_SIZE          (0x0000021C)
-#define CX2_TX_QUEUE_3_BD_BASE          (0x00000220)
-#define CX2_TX_QUEUE_3_BD_SIZE          (0x00000224)
-#define CX2_RX_BD_BASE                  (0x00000240)
-#define CX2_RX_BD_SIZE                  (0x00000244)
-#define CX2_RFDS_TABLE_LOWER            (0x00000500)
+#define IPW_TX_CMD_QUEUE_BD_BASE        0x00000200
+#define IPW_TX_CMD_QUEUE_BD_SIZE        0x00000204
+#define IPW_TX_QUEUE_0_BD_BASE          0x00000208
+#define IPW_TX_QUEUE_0_BD_SIZE          (0x0000020C)
+#define IPW_TX_QUEUE_1_BD_BASE          0x00000210
+#define IPW_TX_QUEUE_1_BD_SIZE          0x00000214
+#define IPW_TX_QUEUE_2_BD_BASE          0x00000218
+#define IPW_TX_QUEUE_2_BD_SIZE          (0x0000021C)
+#define IPW_TX_QUEUE_3_BD_BASE          0x00000220
+#define IPW_TX_QUEUE_3_BD_SIZE          0x00000224
+#define IPW_RX_BD_BASE                  0x00000240
+#define IPW_RX_BD_SIZE                  0x00000244
+#define IPW_RFDS_TABLE_LOWER            0x00000500
 
-#define CX2_TX_CMD_QUEUE_READ_INDEX     (0x00000280)
-#define CX2_TX_QUEUE_0_READ_INDEX       (0x00000284)
-#define CX2_TX_QUEUE_1_READ_INDEX       (0x00000288)
-#define CX2_TX_QUEUE_2_READ_INDEX       (0x0000028C)
-#define CX2_TX_QUEUE_3_READ_INDEX       (0x00000290)
-#define CX2_RX_READ_INDEX               (0x000002A0)
+#define IPW_TX_CMD_QUEUE_READ_INDEX     0x00000280
+#define IPW_TX_QUEUE_0_READ_INDEX       0x00000284
+#define IPW_TX_QUEUE_1_READ_INDEX       0x00000288
+#define IPW_TX_QUEUE_2_READ_INDEX       (0x0000028C)
+#define IPW_TX_QUEUE_3_READ_INDEX       0x00000290
+#define IPW_RX_READ_INDEX               (0x000002A0)
 
-#define CX2_TX_CMD_QUEUE_WRITE_INDEX    (0x00000F80)
-#define CX2_TX_QUEUE_0_WRITE_INDEX      (0x00000F84)
-#define CX2_TX_QUEUE_1_WRITE_INDEX      (0x00000F88)
-#define CX2_TX_QUEUE_2_WRITE_INDEX      (0x00000F8C)
-#define CX2_TX_QUEUE_3_WRITE_INDEX      (0x00000F90)
-#define CX2_RX_WRITE_INDEX              (0x00000FA0)
+#define IPW_TX_CMD_QUEUE_WRITE_INDEX    (0x00000F80)
+#define IPW_TX_QUEUE_0_WRITE_INDEX      (0x00000F84)
+#define IPW_TX_QUEUE_1_WRITE_INDEX      (0x00000F88)
+#define IPW_TX_QUEUE_2_WRITE_INDEX      (0x00000F8C)
+#define IPW_TX_QUEUE_3_WRITE_INDEX      (0x00000F90)
+#define IPW_RX_WRITE_INDEX              (0x00000FA0)
 
 /*
  * EEPROM Related Definitions
  */
 
-#define IPW_EEPROM_DATA_SRAM_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x814)
-#define IPW_EEPROM_DATA_SRAM_SIZE    (CX2_SHARED_LOWER_BOUND + 0x818)
-#define IPW_EEPROM_LOAD_DISABLE      (CX2_SHARED_LOWER_BOUND + 0x81C)
-#define IPW_EEPROM_DATA              (CX2_SHARED_LOWER_BOUND + 0x820)
-#define IPW_EEPROM_UPPER_ADDRESS     (CX2_SHARED_LOWER_BOUND + 0x9E0)
+#define IPW_EEPROM_DATA_SRAM_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x814)
+#define IPW_EEPROM_DATA_SRAM_SIZE    (IPW_SHARED_LOWER_BOUND + 0x818)
+#define IPW_EEPROM_LOAD_DISABLE      (IPW_SHARED_LOWER_BOUND + 0x81C)
+#define IPW_EEPROM_DATA              (IPW_SHARED_LOWER_BOUND + 0x820)
+#define IPW_EEPROM_UPPER_ADDRESS     (IPW_SHARED_LOWER_BOUND + 0x9E0)
 
-#define IPW_STATION_TABLE_LOWER      (CX2_SHARED_LOWER_BOUND + 0xA0C)
-#define IPW_STATION_TABLE_UPPER      (CX2_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_REQUEST_ATIM             (CX2_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_ATIM_SENT                (CX2_SHARED_LOWER_BOUND + 0xB10)
-#define IPW_WHO_IS_AWAKE             (CX2_SHARED_LOWER_BOUND + 0xB14)
-#define IPW_DURING_ATIM_WINDOW       (CX2_SHARED_LOWER_BOUND + 0xB18)
+#define IPW_STATION_TABLE_LOWER      (IPW_SHARED_LOWER_BOUND + 0xA0C)
+#define IPW_STATION_TABLE_UPPER      (IPW_SHARED_LOWER_BOUND + 0xB0C)
+#define IPW_REQUEST_ATIM             (IPW_SHARED_LOWER_BOUND + 0xB0C)
+#define IPW_ATIM_SENT                (IPW_SHARED_LOWER_BOUND + 0xB10)
+#define IPW_WHO_IS_AWAKE             (IPW_SHARED_LOWER_BOUND + 0xB14)
+#define IPW_DURING_ATIM_WINDOW       (IPW_SHARED_LOWER_BOUND + 0xB18)
 
 #define MSB                             1
 #define LSB                             0
@@ -1326,15 +1568,15 @@
 #define EEPROM_HW_VERSION       (GET_EEPROM_ADDR(0x72,LSB))	/* 2 bytes  */
 
 /* NIC type as found in the one byte EEPROM_NIC_TYPE  offset*/
-#define EEPROM_NIC_TYPE_STANDARD        0
-#define EEPROM_NIC_TYPE_DELL            1
-#define EEPROM_NIC_TYPE_FUJITSU         2
-#define EEPROM_NIC_TYPE_IBM             3
-#define EEPROM_NIC_TYPE_HP              4
+#define EEPROM_NIC_TYPE_0 0
+#define EEPROM_NIC_TYPE_1 1
+#define EEPROM_NIC_TYPE_2 2
+#define EEPROM_NIC_TYPE_3 3
+#define EEPROM_NIC_TYPE_4 4
 
 #define FW_MEM_REG_LOWER_BOUND          0x00300000
 #define FW_MEM_REG_EEPROM_ACCESS        (FW_MEM_REG_LOWER_BOUND + 0x40)
-
+#define IPW_EVENT_REG                   (FW_MEM_REG_LOWER_BOUND + 0x04)
 #define EEPROM_BIT_SK                   (1<<0)
 #define EEPROM_BIT_CS                   (1<<1)
 #define EEPROM_BIT_DI                   (1<<2)
@@ -1343,50 +1585,47 @@
 #define EEPROM_CMD_READ                 0x2
 
 /* Interrupts masks */
-#define CX2_INTA_NONE   0x00000000
+#define IPW_INTA_NONE   0x00000000
 
-#define CX2_INTA_BIT_RX_TRANSFER                   0x00000002
-#define CX2_INTA_BIT_STATUS_CHANGE                 0x00000010
-#define CX2_INTA_BIT_BEACON_PERIOD_EXPIRED         0x00000020
+#define IPW_INTA_BIT_RX_TRANSFER                   0x00000002
+#define IPW_INTA_BIT_STATUS_CHANGE                 0x00000010
+#define IPW_INTA_BIT_BEACON_PERIOD_EXPIRED         0x00000020
 
 //Inta Bits for CF
-#define CX2_INTA_BIT_TX_CMD_QUEUE                  0x00000800
-#define CX2_INTA_BIT_TX_QUEUE_1                    0x00001000
-#define CX2_INTA_BIT_TX_QUEUE_2                    0x00002000
-#define CX2_INTA_BIT_TX_QUEUE_3                    0x00004000
-#define CX2_INTA_BIT_TX_QUEUE_4                    0x00008000
+#define IPW_INTA_BIT_TX_CMD_QUEUE                  0x00000800
+#define IPW_INTA_BIT_TX_QUEUE_1                    0x00001000
+#define IPW_INTA_BIT_TX_QUEUE_2                    0x00002000
+#define IPW_INTA_BIT_TX_QUEUE_3                    0x00004000
+#define IPW_INTA_BIT_TX_QUEUE_4                    0x00008000
 
-#define CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE      0x00010000
+#define IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE      0x00010000
 
-#define CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN        0x00100000
-#define CX2_INTA_BIT_POWER_DOWN                    0x00200000
+#define IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN        0x00100000
+#define IPW_INTA_BIT_POWER_DOWN                    0x00200000
 
-#define CX2_INTA_BIT_FW_INITIALIZATION_DONE        0x01000000
-#define CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE  0x02000000
-#define CX2_INTA_BIT_RF_KILL_DONE                  0x04000000
-#define CX2_INTA_BIT_FATAL_ERROR             0x40000000
-#define CX2_INTA_BIT_PARITY_ERROR            0x80000000
+#define IPW_INTA_BIT_FW_INITIALIZATION_DONE        0x01000000
+#define IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE  0x02000000
+#define IPW_INTA_BIT_RF_KILL_DONE                  0x04000000
+#define IPW_INTA_BIT_FATAL_ERROR             0x40000000
+#define IPW_INTA_BIT_PARITY_ERROR            0x80000000
 
 /* Interrupts enabled at init time. */
-#define CX2_INTA_MASK_ALL                        \
-        (CX2_INTA_BIT_TX_QUEUE_1               | \
-	 CX2_INTA_BIT_TX_QUEUE_2               | \
-	 CX2_INTA_BIT_TX_QUEUE_3               | \
-	 CX2_INTA_BIT_TX_QUEUE_4               | \
-	 CX2_INTA_BIT_TX_CMD_QUEUE             | \
-	 CX2_INTA_BIT_RX_TRANSFER              | \
-	 CX2_INTA_BIT_FATAL_ERROR              | \
-	 CX2_INTA_BIT_PARITY_ERROR             | \
-	 CX2_INTA_BIT_STATUS_CHANGE            | \
-	 CX2_INTA_BIT_FW_INITIALIZATION_DONE   | \
-	 CX2_INTA_BIT_BEACON_PERIOD_EXPIRED    | \
-	 CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \
-	 CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN   | \
-	 CX2_INTA_BIT_POWER_DOWN               | \
-         CX2_INTA_BIT_RF_KILL_DONE )
-
-#define IPWSTATUS_ERROR_LOG     (CX2_SHARED_LOWER_BOUND + 0x410)
-#define IPW_EVENT_LOG     (CX2_SHARED_LOWER_BOUND + 0x414)
+#define IPW_INTA_MASK_ALL                        \
+        (IPW_INTA_BIT_TX_QUEUE_1               | \
+	 IPW_INTA_BIT_TX_QUEUE_2               | \
+	 IPW_INTA_BIT_TX_QUEUE_3               | \
+	 IPW_INTA_BIT_TX_QUEUE_4               | \
+	 IPW_INTA_BIT_TX_CMD_QUEUE             | \
+	 IPW_INTA_BIT_RX_TRANSFER              | \
+	 IPW_INTA_BIT_FATAL_ERROR              | \
+	 IPW_INTA_BIT_PARITY_ERROR             | \
+	 IPW_INTA_BIT_STATUS_CHANGE            | \
+	 IPW_INTA_BIT_FW_INITIALIZATION_DONE   | \
+	 IPW_INTA_BIT_BEACON_PERIOD_EXPIRED    | \
+	 IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \
+	 IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN   | \
+	 IPW_INTA_BIT_POWER_DOWN               | \
+         IPW_INTA_BIT_RF_KILL_DONE )
 
 /* FW event log definitions */
 #define EVENT_ELEM_SIZE     (3 * sizeof(u32))
@@ -1396,6 +1635,11 @@
 #define ERROR_ELEM_SIZE     (7 * sizeof(u32))
 #define ERROR_START_OFFSET  (1 * sizeof(u32))
 
+/* TX power level (dbm) */
+#define IPW_TX_POWER_MIN	-12
+#define IPW_TX_POWER_MAX	20
+#define IPW_TX_POWER_DEFAULT	IPW_TX_POWER_MAX
+
 enum {
 	IPW_FW_ERROR_OK = 0,
 	IPW_FW_ERROR_FAIL,
@@ -1408,8 +1652,8 @@
 	IPW_FW_ERROR_ALLOC_FAIL,
 	IPW_FW_ERROR_DMA_UNDERRUN,
 	IPW_FW_ERROR_DMA_STATUS,
-	IPW_FW_ERROR_DINOSTATUS_ERROR,
-	IPW_FW_ERROR_EEPROMSTATUS_ERROR,
+	IPW_FW_ERROR_DINO_ERROR,
+	IPW_FW_ERROR_EEPROM_ERROR,
 	IPW_FW_ERROR_SYSASSERT,
 	IPW_FW_ERROR_FATAL_ERROR
 };
@@ -1425,6 +1669,8 @@
 #define HC_IBSS_RECONF    4
 #define HC_DISASSOC_QUIET 5
 
+#define HC_QOS_SUPPORT_ASSOC  0x01
+
 #define IPW_RATE_CAPABILITIES 1
 #define IPW_RATE_CONNECT      0
 
@@ -1595,18 +1841,20 @@
 	IPW_ORD_TABLE_7_LAST
 };
 
-#define IPW_ORDINALS_TABLE_LOWER        (CX2_SHARED_LOWER_BOUND + 0x500)
-#define IPW_ORDINALS_TABLE_0            (CX2_SHARED_LOWER_BOUND + 0x180)
-#define IPW_ORDINALS_TABLE_1            (CX2_SHARED_LOWER_BOUND + 0x184)
-#define IPW_ORDINALS_TABLE_2            (CX2_SHARED_LOWER_BOUND + 0x188)
-#define IPW_MEM_FIXED_OVERRIDE          (CX2_SHARED_LOWER_BOUND + 0x41C)
+#define IPW_ERROR_LOG     (IPW_SHARED_LOWER_BOUND + 0x410)
+#define IPW_EVENT_LOG     (IPW_SHARED_LOWER_BOUND + 0x414)
+#define IPW_ORDINALS_TABLE_LOWER        (IPW_SHARED_LOWER_BOUND + 0x500)
+#define IPW_ORDINALS_TABLE_0            (IPW_SHARED_LOWER_BOUND + 0x180)
+#define IPW_ORDINALS_TABLE_1            (IPW_SHARED_LOWER_BOUND + 0x184)
+#define IPW_ORDINALS_TABLE_2            (IPW_SHARED_LOWER_BOUND + 0x188)
+#define IPW_MEM_FIXED_OVERRIDE          (IPW_SHARED_LOWER_BOUND + 0x41C)
 
 struct ipw_fixed_rate {
 	u16 tx_rates;
 	u16 reserved;
 } __attribute__ ((packed));
 
-#define CX2_INDIRECT_ADDR_MASK (~0x3ul)
+#define IPW_INDIRECT_ADDR_MASK (~0x3ul)
 
 struct host_cmd {
 	u8 cmd;
@@ -1615,6 +1863,12 @@
 	u32 param[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
 } __attribute__ ((packed));
 
+struct ipw_cmd_log {
+	unsigned long jiffies;
+	int retcode;
+	struct host_cmd cmd;
+};
+
 #define CFG_BT_COEXISTENCE_MIN                  0x00
 #define CFG_BT_COEXISTENCE_DEFER                0x02
 #define CFG_BT_COEXISTENCE_KILL                 0x04
@@ -1643,15 +1897,6 @@
 #define REG_CHANNEL_MASK            0x00003FFF
 #define IPW_IBSS_11B_DEFAULT_MASK   0x87ff
 
-static const long ipw_frequencies[] = {
-	2412, 2417, 2422, 2427,
-	2432, 2437, 2442, 2447,
-	2452, 2457, 2462, 2467,
-	2472, 2484
-};
-
-#define FREQ_COUNT ARRAY_SIZE(ipw_frequencies)
-
 #define IPW_MAX_CONFIG_RETRIES 10
 
 static inline u32 frame_hdr_len(struct ieee80211_hdr_4addr *hdr)
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index 7a17bb3..f5d856d 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -12,7 +12,6 @@
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
-#include <linux/version.h>
 
 #include "hermes.h"
 
diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
index adc7499..109a96d 100644
--- a/drivers/net/wireless/prism54/isl_38xx.c
+++ b/drivers/net/wireless/prism54/isl_38xx.c
@@ -18,7 +18,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/delay.h>
@@ -112,9 +111,10 @@
 void
 isl38xx_trigger_device(int asleep, void __iomem *device_base)
 {
-	u32 reg, counter = 0;
+	u32 reg;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
+	u32 counter = 0;
 	struct timeval current_time;
 	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
 #endif
@@ -131,7 +131,6 @@
 		      current_time.tv_sec, (long)current_time.tv_usec,
 		      readl(device_base + ISL38XX_CTRL_STAT_REG));
 #endif
-		udelay(ISL38XX_WRITEIO_DELAY);
 
 		reg = readl(device_base + ISL38XX_INT_IDENT_REG);
 		if (reg == 0xabadface) {
@@ -145,7 +144,9 @@
 			while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
 			       (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) {
 				udelay(ISL38XX_WRITEIO_DELAY);
+#if VERBOSE > SHOW_ERROR_MESSAGES
 				counter++;
+#endif
 			}
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
@@ -153,10 +154,6 @@
 			      "%08li.%08li Device register read %08x\n",
 			      current_time.tv_sec, (long)current_time.tv_usec,
 			      readl(device_base + ISL38XX_CTRL_STAT_REG));
-#endif
-			udelay(ISL38XX_WRITEIO_DELAY);
-
-#if VERBOSE > SHOW_ERROR_MESSAGES
 			do_gettimeofday(&current_time);
 			DEBUG(SHOW_TRACING,
 			      "%08li.%08li Device asleep counter %i\n",
@@ -171,7 +168,6 @@
 
 		/* perform another read on the Device Status Register */
 		reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
-		udelay(ISL38XX_WRITEIO_DELAY);
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
 		do_gettimeofday(&current_time);
@@ -187,7 +183,6 @@
 
 		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
 				  ISL38XX_DEV_INT_REG);
-		udelay(ISL38XX_WRITEIO_DELAY);
 	}
 }
 
diff --git a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h
index e83e491..8af2098 100644
--- a/drivers/net/wireless/prism54/isl_38xx.h
+++ b/drivers/net/wireless/prism54/isl_38xx.h
@@ -20,7 +20,6 @@
 #ifndef _ISL_38XX_H
 #define _ISL_38XX_H
 
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 5c1a1ad..135a156 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -20,7 +20,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/if_arp.h>
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 78bdb35..5ddf295 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -19,7 +19,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 
 #include <linux/netdevice.h>
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index efbed43..0705316 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -23,7 +23,6 @@
 #ifndef _ISLPCI_DEV_H
 #define _ISLPCI_DEV_H
 
-#include <linux/version.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index fc1eb35..33d64d2 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -17,7 +17,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 
 #include <linux/pci.h>
@@ -227,17 +226,17 @@
 		priv->data_low_tx_full = 1;
 	}
 
+	/* set the transmission time */
+	ndev->trans_start = jiffies;
+	priv->statistics.tx_packets++;
+	priv->statistics.tx_bytes += skb->len;
+
 	/* trigger the device */
 	islpci_trigger(priv);
 
 	/* unlock the driver code */
 	spin_unlock_irqrestore(&priv->slock, flags);
 
-	/* set the transmission time */
-	ndev->trans_start = jiffies;
-	priv->statistics.tx_packets++;
-	priv->statistics.tx_bytes += skb->len;
-
 	return 0;
 
       drop_free:
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index dc040ca..b41d666 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -18,7 +18,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 4b3c98f..c822cad 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -4608,9 +4608,8 @@
 #endif
 
   /* Initialize the dev_link_t structure */
-  link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+  link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
   if (!link) return NULL;
-  memset(link, 0, sizeof(struct dev_link_t));
 
   /* The io structure describes IO port mapping */
   link->io.NumPorts1 = 8;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 3f8c27f..978fdc6 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1965,10 +1965,9 @@
 	int ret;
 
 	/* Initialize the dev_link_t structure */
-	link = kmalloc(sizeof(*link), GFP_KERNEL);
+	link = kzalloc(sizeof(*link), GFP_KERNEL);
 	if (!link)
 		goto out;
-	memset(link, 0, sizeof(struct dev_link_t));
 
 	/* The io structure describes IO port mapping */
 	link->io.NumPorts1	= 16;
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 2a42add..ea16805 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -2,6 +2,8 @@
 #include <linux/module.h>
 #include <linux/ioport.h>
 
+#include "pci.h"
+
 /*
  * This interrupt-safe spinlock protects all accesses to PCI
  * configuration space.
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 061ead2..c42b68d 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -32,8 +32,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <asm/semaphore.h>
-#include <asm/io.h>		
 #include <linux/pcieport_if.h>
 #include "pci_hotplug.h"
 
@@ -42,6 +40,7 @@
 extern int pciehp_poll_mode;
 extern int pciehp_poll_time;
 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)
@@ -49,39 +48,20 @@
 #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
 
-struct pci_func {
-	struct pci_func *next;
-	u8 bus;
-	u8 device;
-	u8 function;
-	u8 is_a_board;
-	u16 status;
-	u8 configured;
-	u8 switch_save;
-	u8 presence_save;
-	u32 base_length[0x06];
-	u8 base_type[0x06];
-	u16 reserved2;
-	u32 config_space[0x20];
-	struct pci_resource *mem_head;
-	struct pci_resource *p_mem_head;
-	struct pci_resource *io_head;
-	struct pci_resource *bus_head;
-	struct pci_dev* pci_dev;
+struct hotplug_params {
+	u8 cache_line_size;
+	u8 latency_timer;
+	u8 enable_serr;
+	u8 enable_perr;
 };
 
 struct slot {
 	struct slot *next;
 	u8 bus;
 	u8 device;
+	u16 status;
 	u32 number;
-	u8 is_a_board;
-	u8 configured;
 	u8 state;
-	u8 switch_save;
-	u8 presence_save;
-	u32 capabilities;
-	u16 reserved2;
 	struct timer_list task_event;
 	u8 hp_slot;
 	struct controller *ctrl;
@@ -90,42 +70,47 @@
 	struct list_head	slot_list;
 };
 
-struct pci_resource {
-	struct pci_resource * next;
-	u32 base;
-	u32 length;
-};
-
 struct event_info {
 	u32 event_type;
 	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 semaphore crit_sect;	/* critical section semaphore */
-	void *hpc_ctlr_handle;		/* HPC controller handle */
+	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_resource *mem_head;
-	struct pci_resource *p_mem_head;
-	struct pci_resource *io_head;
-	struct pci_resource *bus_head;
 	struct pci_dev *pci_dev;
 	struct pci_bus *pci_bus;
-	struct event_info event_queue[10];
+	struct event_info event_queue[MAX_EVENTS];
 	struct slot *slot;
 	struct hpc_ops *hpc_ops;
 	wait_queue_head_t queue;	/* sleep & wake process */
 	u8 next_event;
-	u8 seg;
 	u8 bus;
 	u8 device;
 	u8 function;
-	u8 rev;
 	u8 slot_device_offset;
-	u8 add_support;
-	enum pci_bus_speed speed;
 	u32 first_slot;		/* First physical slot number */  /* PCIE only has 1 slot */
 	u8 slot_bus;		/* Bus where the slots handled by this controller sit */
 	u8 ctrlcap;
@@ -133,20 +118,6 @@
 	u8 cap_base;
 };
 
-struct irq_mapping {
-	u8 barber_pole;
-	u8 valid_INT;
-	u8 interrupt[4];
-};
-
-struct resource_lists {
-	struct pci_resource *mem_head;
-	struct pci_resource *p_mem_head;
-	struct pci_resource *io_head;
-	struct pci_resource *bus_head;
-	struct irq_mapping *irqs;
-};
-
 #define INT_BUTTON_IGNORE		0
 #define INT_PRESENCE_ON			1
 #define INT_PRESENCE_OFF		2
@@ -200,21 +171,14 @@
  * error Messages
  */
 #define msg_initialization_err	"Initialization failure, error=%d\n"
-#define msg_HPC_rev_error	"Unsupported revision of the PCI hot plug controller found.\n"
-#define msg_HPC_non_pcie	"The PCI hot plug controller is not supported by this driver.\n"
-#define msg_HPC_not_supported	"This system is not supported by this version of pciephd module. Upgrade to a newer version of pciehpd\n"
-#define msg_unable_to_save	"Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n"
 #define msg_button_on		"PCI slot #%d - powering on due to button press.\n"
 #define msg_button_off		"PCI slot #%d - powering off due to button press.\n"
 #define msg_button_cancel	"PCI slot #%d - action canceled due to button press.\n"
 #define msg_button_ignore	"PCI slot #%d - button press ignored.  (action in progress...)\n"
 
 /* controller functions */
-extern int	pciehprm_find_available_resources	(struct controller *ctrl);
 extern int	pciehp_event_start_thread	(void);
 extern void	pciehp_event_stop_thread	(void);
-extern struct 	pci_func *pciehp_slot_create	(unsigned char busnumber);
-extern struct 	pci_func *pciehp_slot_find	(unsigned char bus, unsigned char device, unsigned char index);
 extern int	pciehp_enable_slot		(struct slot *slot);
 extern int	pciehp_disable_slot		(struct slot *slot);
 
@@ -224,25 +188,17 @@
 extern u8	pciehp_handle_power_fault	(u8 hp_slot, void *inst_id);
 /* extern void	long_delay (int delay); */
 
-/* resource functions */
-extern int	pciehp_resource_sort_and_combine	(struct pci_resource **head);
-
 /* pci functions */
-extern int	pciehp_set_irq			(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
-/*extern int	pciehp_get_bus_dev		(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/
-extern int	pciehp_save_config	 	(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
-extern int	pciehp_save_used_resources	(struct controller *ctrl, struct pci_func * func, int flag);
-extern int	pciehp_save_slot_config		(struct controller *ctrl, struct pci_func * new_slot);
-extern void	pciehp_destroy_board_resources	(struct pci_func * func);
-extern int	pciehp_return_board_resources	(struct pci_func * func, struct resource_lists * resources);
-extern void	pciehp_destroy_resource_list	(struct resource_lists * resources);
-extern int	pciehp_configure_device		(struct controller* ctrl, struct pci_func* func);
-extern int	pciehp_unconfigure_device	(struct pci_func* func);
+extern int	pciehp_configure_device		(struct slot *p_slot);
+extern int	pciehp_unconfigure_device	(struct slot *p_slot);
+extern int	pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev);
+extern void	pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
+	       	struct hotplug_params *hpp);
+
 
 
 /* Global variables */
 extern struct controller *pciehp_ctrl_list;
-extern struct pci_func *pciehp_slot_list[256];
 
 /* Inline functions */
 
@@ -252,12 +208,9 @@
 
 	p_slot = ctrl->slot;
 
-	dbg("p_slot = %p\n", p_slot);
-
 	while (p_slot && (p_slot->device != device)) {
 		tmp_slot = p_slot;
 		p_slot = p_slot->next;
-		dbg("In while loop, p_slot = %p\n", p_slot);
 	}
 	if (p_slot == NULL) {
 		err("ERROR: pciehp_find_slot device=0x%x\n", device);
@@ -273,7 +226,6 @@
 
 	DECLARE_WAITQUEUE(wait, current);
 
-	dbg("%s : start\n", __FUNCTION__);
 	add_wait_queue(&ctrl->queue, &wait);
 	if (!pciehp_poll_mode)
 		/* Sleep for up to 1 second */
@@ -285,19 +237,9 @@
 	if (signal_pending(current))
 		retval =  -EINTR;
 
-	dbg("%s : end\n", __FUNCTION__);
 	return retval;
 }
 
-/* Puts node back in the resource list pointed to by head */
-static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
-{
-	if (!node || !head)
-		return;
-	node->next = *head;
-	*head = node;
-}
-
 #define SLOT_NAME_SIZE 10
 
 static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
@@ -311,14 +253,7 @@
 	ACPI
 };
 
-typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id);
-
-int pcie_init(struct controller *ctrl, struct pcie_device *dev,
-		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);
-
+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,
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index cafc7ea..8df7048 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -27,27 +27,20 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <linux/pci.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
 #include "pciehp.h"
-#include "pciehprm.h"
 #include <linux/interrupt.h>
 
 /* Global variables */
 int pciehp_debug;
 int pciehp_poll_mode;
 int pciehp_poll_time;
+int pciehp_force;
 struct controller *pciehp_ctrl_list;
-struct pci_func *pciehp_slot_list[256];
 
 #define DRIVER_VERSION	"0.4"
 #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@@ -60,9 +53,11 @@
 module_param(pciehp_debug, bool, 0644);
 module_param(pciehp_poll_mode, bool, 0644);
 module_param(pciehp_poll_time, int, 0644);
+module_param(pciehp_force, bool, 0644);
 MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
 MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
 MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
+MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
 
 #define PCIE_MODULE_NAME "pciehp"
 
@@ -114,8 +109,6 @@
 	u32 slot_number;
 	int result = -ENOMEM;
 
-	dbg("%s\n",__FUNCTION__);
-
 	number_of_slots = ctrl->num_slots;
 	slot_device = ctrl->slot_device_offset;
 	slot_number = ctrl->first_slot;
@@ -370,7 +363,6 @@
 	u8 value;
 	struct pci_dev *pdev;
 	
-	dbg("%s: Called by hp_drv\n", __FUNCTION__);
 	ctrl = kmalloc(sizeof(*ctrl), GFP_KERNEL);
 	if (!ctrl) {
 		err("%s : out of memory\n", __FUNCTION__);
@@ -378,22 +370,15 @@
 	}
 	memset(ctrl, 0, sizeof(struct controller));
 
-	dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid);
-	
 	pdev = dev->port;
+	ctrl->pci_dev = pdev;
 
-	rc = pcie_init(ctrl, dev,
-		(php_intr_callback_t) pciehp_handle_attention_button,
-		(php_intr_callback_t) pciehp_handle_switch_change,
-		(php_intr_callback_t) pciehp_handle_presence_change,
-		(php_intr_callback_t) pciehp_handle_power_fault);
+	rc = pcie_init(ctrl, dev);
 	if (rc) {
 		dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME);
 		goto err_out_free_ctrl;
 	}
 
-	ctrl->pci_dev = pdev;
-
 	pci_set_drvdata(pdev, ctrl);
 
 	ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
@@ -402,7 +387,6 @@
 		rc = -ENOMEM;
 		goto err_out_unmap_mmio_region;
 	}
-	dbg("%s: ctrl->pci_bus %p\n", __FUNCTION__, ctrl->pci_bus);
 	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 */
@@ -424,25 +408,6 @@
 	first_device_num = ctrl->slot_device_offset;
 	num_ctlr_slots = ctrl->num_slots; 
 
-	/* Store PCI Config Space for all devices on this bus */
-	dbg("%s: Before calling pciehp_save_config, ctrl->bus %x,ctrl->slot_bus %x\n", 
-		__FUNCTION__,ctrl->bus, ctrl->slot_bus);
-	rc = pciehp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num);
-	if (rc) {
-		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
-		goto err_out_free_ctrl_bus;
-	}
-
-	/* Get IO, memory, and IRQ resources for new devices */
-	rc = pciehprm_find_available_resources(ctrl);
-	ctrl->add_support = !rc;
-	
-	if (rc) {
-		dbg("pciehprm_find_available_resources = %#x\n", rc);
-		err("unable to locate PCI configuration resources for hot plug add.\n");
-		goto err_out_free_ctrl_bus;
-	}
-
 	/* Setup the slot information structures */
 	rc = init_slots(ctrl);
 	if (rc) {
@@ -451,7 +416,6 @@
 	}
 
 	t_slot = pciehp_find_slot(ctrl, first_device_num);
-	dbg("%s: t_slot %p\n", __FUNCTION__, t_slot);
 
 	/*	Finish setting up the hot plug ctrl device */
 	ctrl->next_event = 0;
@@ -468,7 +432,6 @@
 	down(&ctrl->crit_sect);
 
 	t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
-	dbg("%s: adpater value %x\n", __FUNCTION__, value);
 	
 	if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
 		rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
@@ -501,7 +464,6 @@
 
 static int pcie_start_thread(void)
 {
-	int loop;
 	int retval = 0;
 	
 	dbg("Initialize + Start the notification/polling mechanism \n");
@@ -512,32 +474,11 @@
 		return retval;
 	}
 
-	dbg("Initialize slot lists\n");
-	/* One slot list for each bus in the system */
-	for (loop = 0; loop < 256; loop++) {
-		pciehp_slot_list[loop] = NULL;
-	}
-
 	return retval;
 }
 
-static inline void __exit
-free_pciehp_res(struct pci_resource *res)
-{
-	struct pci_resource *tres;
-
-	while (res) {
-		tres = res;
-		res = res->next;
-		kfree(tres);
-	}
-}
-
 static void __exit unload_pciehpd(void)
 {
-	struct pci_func *next;
-	struct pci_func *TempSlot;
-	int loop;
 	struct controller *ctrl;
 	struct controller *tctrl;
 
@@ -546,11 +487,6 @@
 	while (ctrl) {
 		cleanup_slots(ctrl);
 
-		free_pciehp_res(ctrl->io_head);
-		free_pciehp_res(ctrl->mem_head);
-		free_pciehp_res(ctrl->p_mem_head);
-		free_pciehp_res(ctrl->bus_head);
-
 		kfree (ctrl->pci_bus);
 
 		ctrl->hpc_ops->release_ctlr(ctrl);
@@ -561,20 +497,6 @@
 		kfree(tctrl);
 	}
 
-	for (loop = 0; loop < 256; loop++) {
-		next = pciehp_slot_list[loop];
-		while (next != NULL) {
-			free_pciehp_res(next->io_head);
-			free_pciehp_res(next->mem_head);
-			free_pciehp_res(next->p_mem_head);
-			free_pciehp_res(next->bus_head);
-
-			TempSlot = next;
-			next = next->next;
-			kfree(TempSlot);
-		}
-	}
-
 	/* Stop the notification mechanism */
 	pciehp_event_stop_thread();
 
@@ -639,21 +561,16 @@
 	if (retval)
 		goto error_hpc_init;
 
-	retval = pciehprm_init(PCI);
-	if (!retval) {
- 		retval = pcie_port_service_register(&hpdriver_portdrv);
- 		dbg("pcie_port_service_register = %d\n", retval);
-  		info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
- 		if (retval)
- 		   dbg("%s: Failure to register service\n", __FUNCTION__);
-	}
+	retval = pcie_port_service_register(&hpdriver_portdrv);
+ 	dbg("pcie_port_service_register = %d\n", retval);
+  	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+ 	if (retval)
+		dbg("%s: Failure to register service\n", __FUNCTION__);
 
 error_hpc_init:
 	if (retval) {
-		pciehprm_cleanup();
 		pciehp_event_stop_thread();
-	} else
-		pciehprm_print_pirt();
+	};
 
 	return retval;
 }
@@ -663,9 +580,6 @@
 	dbg("unload_pciehpd()\n");
 	unload_pciehpd();
 
-	pciehprm_cleanup();
-
-	dbg("pcie_port_service_unregister\n");
 	pcie_port_service_unregister(&hpdriver_portdrv);
 
 	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 898f6da..5e582ec 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -27,25 +27,14 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/wait.h>
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include "../pci.h"
 #include "pciehp.h"
-#include "pciehprm.h"
 
-static u32 configure_new_device(struct controller *ctrl, struct pci_func *func,
-	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
-static int configure_new_function( struct controller *ctrl, struct pci_func *func,
-	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
 static void interrupt_event_handler(struct controller *ctrl);
 
 static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
@@ -60,22 +49,18 @@
 	struct slot *p_slot;
 	u8 rc = 0;
 	u8 getstatus;
-	struct pci_func *func;
 	struct event_info *taskInfo;
 
 	/* Attention Button Change */
 	dbg("pciehp:  Attention button interrupt received.\n");
 	
-	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
-
 	/* This is the structure that tells the worker thread what to do */
 	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
 	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
-	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	
-	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
 	taskInfo->hp_slot = hp_slot;
 
 	rc++;
@@ -117,24 +102,20 @@
 	struct slot *p_slot;
 	u8 rc = 0;
 	u8 getstatus;
-	struct pci_func *func;
 	struct event_info *taskInfo;
 
 	/* Switch Change */
 	dbg("pciehp:  Switch interrupt received.\n");
 
-	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
-
 	/* This is the structure that tells the worker thread
 	 * what to do
 	 */
 	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
-	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
 	taskInfo->hp_slot = hp_slot;
 
 	rc++;
 	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 
 	if (getstatus) {
@@ -142,14 +123,12 @@
 		 * Switch opened
 		 */
 		info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
-		func->switch_save = 0;
 		taskInfo->event_type = INT_SWITCH_OPEN;
 	} else {
 		/*
 		 *  Switch closed
 		 */
 		info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
-		func->switch_save = 0x10;
 		taskInfo->event_type = INT_SWITCH_CLOSE;
 	}
 
@@ -163,20 +142,17 @@
 {
 	struct controller *ctrl = (struct controller *) inst_id;
 	struct slot *p_slot;
-	u8 rc = 0;
-	struct pci_func *func;
+	u8 presence_save, rc = 0;
 	struct event_info *taskInfo;
 
 	/* Presence Change */
 	dbg("pciehp:  Presence/Notify input change.\n");
 
-	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
-
 	/* This is the structure that tells the worker thread
 	 * what to do
 	 */
 	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
-	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
 	taskInfo->hp_slot = hp_slot;
 
 	rc++;
@@ -185,8 +161,8 @@
 	/* Switch is open, assume a presence change
 	 * Save the presence state
 	 */
-	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
-	if (func->presence_save) {
+	p_slot->hpc_ops->get_adapter_status(p_slot, &presence_save);
+	if (presence_save) {
 		/*
 		 * Card Present
 		 */
@@ -211,19 +187,16 @@
 	struct controller *ctrl = (struct controller *) inst_id;
 	struct slot *p_slot;
 	u8 rc = 0;
-	struct pci_func *func;
 	struct event_info *taskInfo;
 
 	/* power fault */
 	dbg("pciehp:  Power fault interrupt received.\n");
 
-	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
-
 	/* this is the structure that tells the worker thread
 	 * what to do
 	 */
 	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
-	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
 	taskInfo->hp_slot = hp_slot;
 
 	rc++;
@@ -234,7 +207,7 @@
 		 * power fault Cleared
 		 */
 		info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
-		func->status = 0x00;
+		p_slot->status = 0x00;
 		taskInfo->event_type = INT_POWER_FAULT_CLEAR;
 	} else {
 		/*
@@ -243,7 +216,7 @@
 		info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
 		taskInfo->event_type = INT_POWER_FAULT;
 		/* set power fault status for this board */
-		func->status = 0xFF;
+		p_slot->status = 0xFF;
 		info("power fault bit %x set\n", hp_slot);
 	}
 	if (rc)
@@ -252,810 +225,6 @@
 	return rc;
 }
 
-
-/**
- * sort_by_size: sort nodes by their length, smallest first.
- *
- * @head: list to sort
- */
-static int sort_by_size(struct pci_resource **head)
-{
-	struct pci_resource *current_res;
-	struct pci_resource *next_res;
-	int out_of_order = 1;
-
-	if (!(*head))
-		return 1;
-
-	if (!((*head)->next))
-		return 0;
-
-	while (out_of_order) {
-		out_of_order = 0;
-
-		/* Special case for swapping list head */
-		if (((*head)->next) &&
-		    ((*head)->length > (*head)->next->length)) {
-			out_of_order++;
-			current_res = *head;
-			*head = (*head)->next;
-			current_res->next = (*head)->next;
-			(*head)->next = current_res;
-		}
-
-		current_res = *head;
-
-		while (current_res->next && current_res->next->next) {
-			if (current_res->next->length > current_res->next->next->length) {
-				out_of_order++;
-				next_res = current_res->next;
-				current_res->next = current_res->next->next;
-				current_res = current_res->next;
-				next_res->next = current_res->next;
-				current_res->next = next_res;
-			} else
-				current_res = current_res->next;
-		}
-	}  /* End of out_of_order loop */
-
-	return 0;
-}
-
-
-/*
- * sort_by_max_size
- *
- * Sorts nodes on the list by their length.
- * Largest first.
- *
- */
-static int sort_by_max_size(struct pci_resource **head)
-{
-	struct pci_resource *current_res;
-	struct pci_resource *next_res;
-	int out_of_order = 1;
-
-	if (!(*head))
-		return 1;
-
-	if (!((*head)->next))
-		return 0;
-
-	while (out_of_order) {
-		out_of_order = 0;
-
-		/* Special case for swapping list head */
-		if (((*head)->next) &&
-		    ((*head)->length < (*head)->next->length)) {
-			out_of_order++;
-			current_res = *head;
-			*head = (*head)->next;
-			current_res->next = (*head)->next;
-			(*head)->next = current_res;
-		}
-
-		current_res = *head;
-
-		while (current_res->next && current_res->next->next) {
-			if (current_res->next->length < current_res->next->next->length) {
-				out_of_order++;
-				next_res = current_res->next;
-				current_res->next = current_res->next->next;
-				current_res = current_res->next;
-				next_res->next = current_res->next;
-				current_res->next = next_res;
-			} else
-				current_res = current_res->next;
-		}
-	}  /* End of out_of_order loop */
-
-	return 0;
-}
-
-
-/**
- * do_pre_bridge_resource_split: return one unused resource node
- * @head: list to scan
- *
- */
-static struct pci_resource *
-do_pre_bridge_resource_split(struct pci_resource **head,
-				struct pci_resource **orig_head, u32 alignment)
-{
-	struct pci_resource *prevnode = NULL;
-	struct pci_resource *node;
-	struct pci_resource *split_node;
-	u32 rc;
-	u32 temp_dword;
-	dbg("do_pre_bridge_resource_split\n");
-
-	if (!(*head) || !(*orig_head))
-		return NULL;
-
-	rc = pciehp_resource_sort_and_combine(head);
-
-	if (rc)
-		return NULL;
-
-	if ((*head)->base != (*orig_head)->base)
-		return NULL;
-
-	if ((*head)->length == (*orig_head)->length)
-		return NULL;
-
-
-	/* If we got here, there the bridge requires some of the resource, but
-	 *  we may be able to split some off of the front
-	 */	
-	node = *head;
-
-	if (node->length & (alignment -1)) {
-		/* this one isn't an aligned length, so we'll make a new entry
-		 * and split it up.
-		 */
-		split_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-		if (!split_node)
-			return NULL;
-
-		temp_dword = (node->length | (alignment-1)) + 1 - alignment;
-
-		split_node->base = node->base;
-		split_node->length = temp_dword;
-
-		node->length -= temp_dword;
-		node->base += split_node->length;
-
-		/* Put it in the list */
-		*head = split_node;
-		split_node->next = node;
-	}
-
-	if (node->length < alignment)
-		return NULL;
-
-	/* Now unlink it */
-	if (*head == node) {
-		*head = node->next;
-	} else {
-		prevnode = *head;
-		while (prevnode->next != node)
-			prevnode = prevnode->next;
-
-		prevnode->next = node->next;
-	}
-	node->next = NULL;
-
-	return node;
-}
-
-
-/**
- * do_bridge_resource_split: return one unused resource node
- * @head: list to scan
- *
- */
-static struct pci_resource *
-do_bridge_resource_split(struct pci_resource **head, u32 alignment)
-{
-	struct pci_resource *prevnode = NULL;
-	struct pci_resource *node;
-	u32 rc;
-	u32 temp_dword;
-
-	if (!(*head))
-		return NULL;
-
-	rc = pciehp_resource_sort_and_combine(head);
-
-	if (rc)
-		return NULL;
-
-	node = *head;
-
-	while (node->next) {
-		prevnode = node;
-		node = node->next;
-		kfree(prevnode);
-	}
-
-	if (node->length < alignment) {
-		kfree(node);
-		return NULL;
-	}
-
-	if (node->base & (alignment - 1)) {
-		/* Short circuit if adjusted size is too small */
-		temp_dword = (node->base | (alignment-1)) + 1;
-		if ((node->length - (temp_dword - node->base)) < alignment) {
-			kfree(node);
-			return NULL;
-		}
-
-		node->length -= (temp_dword - node->base);
-		node->base = temp_dword;
-	}
-
-	if (node->length & (alignment - 1)) {
-		/* There's stuff in use after this node */
-		kfree(node);
-		return NULL;
-	}
-
-	return node;
-}
-
-
-/*
- * get_io_resource
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length that is not in the
- * ISA aliasing window.  If it finds a node larger than "size"
- * it will split it up.
- *
- * size must be a power of two.
- */
-static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size)
-{
-	struct pci_resource *prevnode;
-	struct pci_resource *node;
-	struct pci_resource *split_node = NULL;
-	u32 temp_dword;
-
-	if (!(*head))
-		return NULL;
-
-	if ( pciehp_resource_sort_and_combine(head) )
-		return NULL;
-
-	if ( sort_by_size(head) )
-		return NULL;
-
-	for (node = *head; node; node = node->next) {
-		if (node->length < size)
-			continue;
-
-		if (node->base & (size - 1)) {
-			/* this one isn't base aligned properly
-			   so we'll make a new entry and split it up */
-			temp_dword = (node->base | (size-1)) + 1;
-
-			/*/ Short circuit if adjusted size is too small */
-			if ((node->length - (temp_dword - node->base)) < size)
-				continue;
-
-			split_node = kmalloc(sizeof(struct pci_resource),
-						GFP_KERNEL);
-
-			if (!split_node)
-				return NULL;
-
-			split_node->base = node->base;
-			split_node->length = temp_dword - node->base;
-			node->base = temp_dword;
-			node->length -= split_node->length;
-
-			/* Put it in the list */
-			split_node->next = node->next;
-			node->next = split_node;
-		} /* End of non-aligned base */
-
-		/* Don't need to check if too small since we already did */
-		if (node->length > size) {
-			/* this one is longer than we need
-			   so we'll make a new entry and split it up */
-			split_node = kmalloc(sizeof(struct pci_resource),
-						GFP_KERNEL);
-
-			if (!split_node)
-				return NULL;
-
-			split_node->base = node->base + size;
-			split_node->length = node->length - size;
-			node->length = size;
-
-			/* Put it in the list */
-			split_node->next = node->next;
-			node->next = split_node;
-		}  /* End of too big on top end */
-
-		/* For IO make sure it's not in the ISA aliasing space */
-		if (node->base & 0x300L)
-			continue;
-
-		/* If we got here, then it is the right size 
-		   Now take it out of the list */
-		if (*head == node) {
-			*head = node->next;
-		} else {
-			prevnode = *head;
-			while (prevnode->next != node)
-				prevnode = prevnode->next;
-
-			prevnode->next = node->next;
-		}
-		node->next = NULL;
-		/* Stop looping */
-		break;
-	}
-
-	return node;
-}
-
-
-/*
- * get_max_resource
- *
- * Gets the largest node that is at least "size" big from the
- * list pointed to by head.  It aligns the node on top and bottom
- * to "size" alignment before returning it.
- * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M
- *  This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot.
- */
-static struct pci_resource *get_max_resource(struct pci_resource **head, u32 size)
-{
-	struct pci_resource *max;
-	struct pci_resource *temp;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-	u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 };
-	int i;
-
-	if (!(*head))
-		return NULL;
-
-	if (pciehp_resource_sort_and_combine(head))
-		return NULL;
-
-	if (sort_by_max_size(head))
-		return NULL;
-
-	for (max = *head;max; max = max->next) {
-
-		/* If not big enough we could probably just bail, 
-		   instead we'll continue to the next. */
-		if (max->length < size)
-			continue;
-
-		if (max->base & (size - 1)) {
-			/* this one isn't base aligned properly
-			   so we'll make a new entry and split it up */
-			temp_dword = (max->base | (size-1)) + 1;
-
-			/* Short circuit if adjusted size is too small */
-			if ((max->length - (temp_dword - max->base)) < size)
-				continue;
-
-			split_node = kmalloc(sizeof(struct pci_resource),
-						GFP_KERNEL);
-
-			if (!split_node)
-				return NULL;
-
-			split_node->base = max->base;
-			split_node->length = temp_dword - max->base;
-			max->base = temp_dword;
-			max->length -= split_node->length;
-
-			/* Put it next in the list */
-			split_node->next = max->next;
-			max->next = split_node;
-		}
-
-		if ((max->base + max->length) & (size - 1)) {
-			/* this one isn't end aligned properly at the top
-			   so we'll make a new entry and split it up */
-			split_node = kmalloc(sizeof(struct pci_resource),
-						GFP_KERNEL);
-
-			if (!split_node)
-				return NULL;
-			temp_dword = ((max->base + max->length) & ~(size - 1));
-			split_node->base = temp_dword;
-			split_node->length = max->length + max->base
-					     - split_node->base;
-			max->length -= split_node->length;
-
-			/* Put it in the list */
-			split_node->next = max->next;
-			max->next = split_node;
-		}
-
-		/* Make sure it didn't shrink too much when we aligned it */
-		if (max->length < size)
-			continue;
-
-		for ( i = 0; max_size[i] > size; i++) {
-			if (max->length > max_size[i]) {
-				split_node = kmalloc(sizeof(struct pci_resource),
-							GFP_KERNEL);
-				if (!split_node)
-					break;	/* return NULL; */
-				split_node->base = max->base + max_size[i];
-				split_node->length = max->length - max_size[i];
-				max->length = max_size[i];
-				/* Put it next in the list */
-				split_node->next = max->next;
-				max->next = split_node;
-				break;
-			}
-		}
-
-		/* Now take it out of the list */
-		temp = (struct pci_resource*) *head;
-		if (temp == max) {
-			*head = max->next;
-		} else {
-			while (temp && temp->next != max) {
-				temp = temp->next;
-			}
-
-			temp->next = max->next;
-		}
-
-		max->next = NULL;
-		return max;
-	}
-
-	/* If we get here, we couldn't find one */
-	return NULL;
-}
-
-
-/*
- * get_resource
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length.  If it finds a node
- * larger than "size" it will split it up.
- *
- * size must be a power of two.
- */
-static struct pci_resource *get_resource(struct pci_resource **head, u32 size)
-{
-	struct pci_resource *prevnode;
-	struct pci_resource *node;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-
-	if (!(*head))
-		return NULL;
-
-	if ( pciehp_resource_sort_and_combine(head) )
-		return NULL;
-
-	if ( sort_by_size(head) )
-		return NULL;
-
-	for (node = *head; node; node = node->next) {
-		dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n",
-		    __FUNCTION__, size, node, node->base, node->length);
-		if (node->length < size)
-			continue;
-
-		if (node->base & (size - 1)) {
-			dbg("%s: not aligned\n", __FUNCTION__);
-			/* this one isn't base aligned properly
-			   so we'll make a new entry and split it up */
-			temp_dword = (node->base | (size-1)) + 1;
-
-			/* Short circuit if adjusted size is too small */
-			if ((node->length - (temp_dword - node->base)) < size)
-				continue;
-
-			split_node = kmalloc(sizeof(struct pci_resource),
-						GFP_KERNEL);
-
-			if (!split_node)
-				return NULL;
-
-			split_node->base = node->base;
-			split_node->length = temp_dword - node->base;
-			node->base = temp_dword;
-			node->length -= split_node->length;
-
-			/* Put it in the list */
-			split_node->next = node->next;
-			node->next = split_node;
-		} /* End of non-aligned base */
-
-		/* Don't need to check if too small since we already did */
-		if (node->length > size) {
-			dbg("%s: too big\n", __FUNCTION__);
-			/* this one is longer than we need
-			   so we'll make a new entry and split it up */
-			split_node = kmalloc(sizeof(struct pci_resource),
-						GFP_KERNEL);
-
-			if (!split_node)
-				return NULL;
-
-			split_node->base = node->base + size;
-			split_node->length = node->length - size;
-			node->length = size;
-
-			/* Put it in the list */
-			split_node->next = node->next;
-			node->next = split_node;
-		}  /* End of too big on top end */
-
-		dbg("%s: got one!!!\n", __FUNCTION__);
-		/* If we got here, then it is the right size
-		   Now take it out of the list */
-		if (*head == node) {
-			*head = node->next;
-		} else {
-			prevnode = *head;
-			while (prevnode->next != node)
-				prevnode = prevnode->next;
-
-			prevnode->next = node->next;
-		}
-		node->next = NULL;
-		/* Stop looping */
-		break;
-	}
-	return node;
-}
-
-
-/*
- * pciehp_resource_sort_and_combine
- *
- * Sorts all of the nodes in the list in ascending order by
- * their base addresses.  Also does garbage collection by
- * combining adjacent nodes.
- *
- * returns 0 if success
- */
-int pciehp_resource_sort_and_combine(struct pci_resource **head)
-{
-	struct pci_resource *node1;
-	struct pci_resource *node2;
-	int out_of_order = 1;
-
-	dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
-
-	if (!(*head))
-		return 1;
-
-	dbg("*head->next = %p\n",(*head)->next);
-
-	if (!(*head)->next)
-		return 0;	/* only one item on the list, already sorted! */
-
-	dbg("*head->base = 0x%x\n",(*head)->base);
-	dbg("*head->next->base = 0x%x\n",(*head)->next->base);
-	while (out_of_order) {
-		out_of_order = 0;
-
-		/* Special case for swapping list head */
-		if (((*head)->next) &&
-		    ((*head)->base > (*head)->next->base)) {
-			node1 = *head;
-			(*head) = (*head)->next;
-			node1->next = (*head)->next;
-			(*head)->next = node1;
-			out_of_order++;
-		}
-
-		node1 = (*head);
-
-		while (node1->next && node1->next->next) {
-			if (node1->next->base > node1->next->next->base) {
-				out_of_order++;
-				node2 = node1->next;
-				node1->next = node1->next->next;
-				node1 = node1->next;
-				node2->next = node1->next;
-				node1->next = node2;
-			} else
-				node1 = node1->next;
-		}
-	}  /* End of out_of_order loop */
-
-	node1 = *head;
-
-	while (node1 && node1->next) {
-		if ((node1->base + node1->length) == node1->next->base) {
-			/* Combine */
-			dbg("8..\n");
-			node1->length += node1->next->length;
-			node2 = node1->next;
-			node1->next = node1->next->next;
-			kfree(node2);
-		} else
-			node1 = node1->next;
-	}
-
-	return 0;
-}
-
-
-/**
- * pciehp_slot_create - Creates a node and adds it to the proper bus.
- * @busnumber - bus where new node is to be located
- *
- * Returns pointer to the new node or NULL if unsuccessful
- */
-struct pci_func *pciehp_slot_create(u8 busnumber)
-{
-	struct pci_func *new_slot;
-	struct pci_func *next;
-	dbg("%s: busnumber %x\n", __FUNCTION__, busnumber);
-	new_slot = kmalloc(sizeof(struct pci_func), GFP_KERNEL);
-
-	if (new_slot == NULL)
-		return new_slot;
-
-	memset(new_slot, 0, sizeof(struct pci_func));
-
-	new_slot->next = NULL;
-	new_slot->configured = 1;
-
-	if (pciehp_slot_list[busnumber] == NULL) {
-		pciehp_slot_list[busnumber] = new_slot;
-	} else {
-		next = pciehp_slot_list[busnumber];
-		while (next->next != NULL)
-			next = next->next;
-		next->next = new_slot;
-	}
-	return new_slot;
-}
-
-
-/**
- * slot_remove - Removes a node from the linked list of slots.
- * @old_slot: slot to remove
- *
- * Returns 0 if successful, !0 otherwise.
- */
-static int slot_remove(struct pci_func * old_slot)
-{
-	struct pci_func *next;
-
-	if (old_slot == NULL)
-		return 1;
-
-	next = pciehp_slot_list[old_slot->bus];
-
-	if (next == NULL)
-		return 1;
-
-	if (next == old_slot) {
-		pciehp_slot_list[old_slot->bus] = old_slot->next;
-		pciehp_destroy_board_resources(old_slot);
-		kfree(old_slot);
-		return 0;
-	}
-
-	while ((next->next != old_slot) && (next->next != NULL)) {
-		next = next->next;
-	}
-
-	if (next->next == old_slot) {
-		next->next = old_slot->next;
-		pciehp_destroy_board_resources(old_slot);
-		kfree(old_slot);
-		return 0;
-	} else
-		return 2;
-}
-
-
-/**
- * bridge_slot_remove - Removes a node from the linked list of slots.
- * @bridge: bridge to remove
- *
- * Returns 0 if successful, !0 otherwise.
- */
-static int bridge_slot_remove(struct pci_func *bridge)
-{
-	u8 subordinateBus, secondaryBus;
-	u8 tempBus;
-	struct pci_func *next;
-
-	if (bridge == NULL)
-		return 1;
-
-	secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
-	subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
-
-	for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
-		next = pciehp_slot_list[tempBus];
-
-		while (!slot_remove(next)) {
-			next = pciehp_slot_list[tempBus];
-		}
-	}
-
-	next = pciehp_slot_list[bridge->bus];
-
-	if (next == NULL) {
-		return 1;
-	}
-
-	if (next == bridge) {
-		pciehp_slot_list[bridge->bus] = bridge->next;
-		kfree(bridge);
-		return 0;
-	}
-
-	while ((next->next != bridge) && (next->next != NULL)) {
-		next = next->next;
-	}
-
-	if (next->next == bridge) {
-		next->next = bridge->next;
-		kfree(bridge);
-		return 0;
-	} else
-		return 2;
-}
-
-
-/**
- * pciehp_slot_find - Looks for a node by bus, and device, multiple functions accessed
- * @bus: bus to find
- * @device: device to find
- * @index: is 0 for first function found, 1 for the second...
- *
- * Returns pointer to the node if successful, %NULL otherwise.
- */
-struct pci_func *pciehp_slot_find(u8 bus, u8 device, u8 index)
-{
-	int found = -1;
-	struct pci_func *func;
-
-	func = pciehp_slot_list[bus];
-	dbg("%s: bus %x device %x index %x\n",
-		__FUNCTION__, bus, device, index);
-	if (func != NULL) {
-		dbg("%s: func-> bus %x device %x function %x pci_dev %p\n",
-			__FUNCTION__, func->bus, func->device, func->function,
-			func->pci_dev);
-	} else
-		dbg("%s: func == NULL\n", __FUNCTION__);
-
-	if ((func == NULL) || ((func->device == device) && (index == 0)))
-		return func;
-
-	if (func->device == device)
-		found++;
-
-	while (func->next != NULL) {
-		func = func->next;
-
-		dbg("%s: In while loop, func-> bus %x device %x function %x pci_dev %p\n",
-			__FUNCTION__, func->bus, func->device, func->function,
-			func->pci_dev);
-		if (func->device == device)
-			found++;
-		dbg("%s: while loop, found %d, index %d\n", __FUNCTION__,
-			found, index);
-
-		if ((found == index) || (func->function == index)) {
-			dbg("%s: Found bus %x dev %x func %x\n", __FUNCTION__,
-					func->bus, func->device, func->function);
-			return func;
-		}
-	}
-
-	return NULL;
-}
-
-static int is_bridge(struct pci_func * func)
-{
-	/* Check the header type */
-	if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01)
-		return 1;
-	else
-		return 0;
-}
-
-
 /* The following routines constitute the bulk of the 
    hotplug controller logic
  */
@@ -1100,20 +269,17 @@
  * Configures board
  *
  */
-static u32 board_added(struct pci_func * func, struct controller * ctrl)
+static int board_added(struct slot *p_slot)
 {
 	u8 hp_slot;
-	int index;
-	u32 temp_register = 0xFFFFFFFF;
-	u32 rc = 0;
-	struct pci_func *new_func = NULL;
-	struct slot *p_slot;
-	struct resource_lists res_lists;
+	int rc = 0;
+	struct controller *ctrl = p_slot->ctrl;
 
-	p_slot = pciehp_find_slot(ctrl, func->device);
-	hp_slot = func->device - ctrl->slot_device_offset;
+	hp_slot = p_slot->device - ctrl->slot_device_offset;
 
-	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
+	dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
+			__FUNCTION__, p_slot->device,
+			ctrl->slot_device_offset, hp_slot);
 
 	/* Wait for exclusive access to hardware */
 	down(&ctrl->crit_sect);
@@ -1141,9 +307,7 @@
 	up(&ctrl->crit_sect);
 
 	/* Wait for ~1 second */
-	dbg("%s: before long_delay\n", __FUNCTION__);
 	wait_for_ctrl_irq (ctrl);
-	dbg("%s: afterlong_delay\n", __FUNCTION__);
 
 	/*  Check link training status */
 	rc = p_slot->hpc_ops->check_lnk_status(ctrl);  
@@ -1153,98 +317,47 @@
 		return rc;
 	}
 
-	dbg("%s: func status = %x\n", __FUNCTION__, func->status);
+	dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status);
 
 	/* Check for a power fault */
-	if (func->status == 0xFF) {
+	if (p_slot->status == 0xFF) {
 		/* power fault occurred, but it was benign */
-		temp_register = 0xFFFFFFFF;
-		dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
 		rc = POWER_FAILURE;
-		func->status = 0;
-	} else {
-		/* Get vendor/device ID u32 */
-		rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), 
-			PCI_VENDOR_ID, &temp_register);
-		dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc);
-		dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register);
-
-		if (rc != 0) {
-			/* Something's wrong here */
-			temp_register = 0xFFFFFFFF;
-			dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register);
-		}
-		/* Preset return code.  It will be changed later if things go okay. */
-		rc = NO_ADAPTER_PRESENT;
+		p_slot->status = 0;
+		goto err_exit;
 	}
 
-	/* All F's is an empty slot or an invalid board */
-	if (temp_register != 0xFFFFFFFF) {	  /* Check for a board in the slot */
-		res_lists.io_head = ctrl->io_head;
-		res_lists.mem_head = ctrl->mem_head;
-		res_lists.p_mem_head = ctrl->p_mem_head;
-		res_lists.bus_head = ctrl->bus_head;
-		res_lists.irqs = NULL;
+	rc = pciehp_configure_device(p_slot);
+	if (rc) {
+		err("Cannot add device 0x%x:%x\n", p_slot->bus,
+				p_slot->device);
+		goto err_exit;
+	}
 
-		rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0);
-		dbg("%s: back from configure_new_device\n", __FUNCTION__);
+	p_slot->status = 0;
 
-		ctrl->io_head = res_lists.io_head;
-		ctrl->mem_head = res_lists.mem_head;
-		ctrl->p_mem_head = res_lists.p_mem_head;
-		ctrl->bus_head = res_lists.bus_head;
+	/*
+	 * Some PCI Express root ports require fixup after hot-plug operation.
+	 */
+	if (pcie_mch_quirk)
+		pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
+	if (PWR_LED(ctrl->ctrlcap)) {
+		/* Wait for exclusive access to hardware */
+  		down(&ctrl->crit_sect);
 
-		pciehp_resource_sort_and_combine(&(ctrl->mem_head));
-		pciehp_resource_sort_and_combine(&(ctrl->p_mem_head));
-		pciehp_resource_sort_and_combine(&(ctrl->io_head));
-		pciehp_resource_sort_and_combine(&(ctrl->bus_head));
-
-		if (rc) {
-			set_slot_off(ctrl, p_slot);
-			return rc;
-		}
-		pciehp_save_slot_config(ctrl, func);
-
-		func->status = 0;
-		func->switch_save = 0x10;
-		func->is_a_board = 0x01;
-
-		/* next, we will instantiate the linux pci_dev structures 
-		 * (with appropriate driver notification, if already present) 
-		 */
-		index = 0;
-		do {
-			new_func = pciehp_slot_find(ctrl->slot_bus, func->device, index++);
-			if (new_func && !new_func->pci_dev) {
-				dbg("%s:call pci_hp_configure_dev, func %x\n", 
-					__FUNCTION__, index);
-				pciehp_configure_device(ctrl, new_func);
-			}
-		} while (new_func);
-
- 		/* 
- 		 * Some PCI Express root ports require fixup after hot-plug operation.
- 		 */
- 		if (pcie_mch_quirk)
- 			pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
- 
-  		if (PWR_LED(ctrl->ctrlcap)) {
-  			/* Wait for exclusive access to hardware */
-  			down(&ctrl->crit_sect);
-   
-  			p_slot->hpc_ops->green_led_on(p_slot);
+  		p_slot->hpc_ops->green_led_on(p_slot);
   
-  			/* Wait for the command to complete */
-  			wait_for_ctrl_irq (ctrl);
+  		/* Wait for the command to complete */
+  		wait_for_ctrl_irq (ctrl);
   	
-  			/* Done with exclusive hardware access */
-  			up(&ctrl->crit_sect);
-  		}
-	} else {
-		set_slot_off(ctrl, p_slot);
-		return -1;
-	}
+  		/* Done with exclusive hardware access */
+  		up(&ctrl->crit_sect);
+  	}
 	return 0;
+
+err_exit:
+	set_slot_off(ctrl, p_slot);
+	return -1;
 }
 
 
@@ -1252,55 +365,25 @@
  * remove_board - Turns off slot and LED's
  *
  */
-static u32 remove_board(struct pci_func *func, struct controller *ctrl)
+static int remove_board(struct slot *p_slot)
 {
-	int index;
-	u8 skip = 0;
 	u8 device;
 	u8 hp_slot;
-	u32 rc;
-	struct resource_lists res_lists;
-	struct pci_func *temp_func;
-	struct slot *p_slot;
+	int rc;
+	struct controller *ctrl = p_slot->ctrl;
 
-	if (func == NULL)
+	if (pciehp_unconfigure_device(p_slot))
 		return 1;
 
-	if (pciehp_unconfigure_device(func))
-		return 1;
+	device = p_slot->device;
 
-	device = func->device;
-
-	hp_slot = func->device - ctrl->slot_device_offset;
+	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);
 
-	if ((ctrl->add_support) &&
-		!(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) {
-		/* Here we check to see if we've saved any of the board's
-		 * resources already.  If so, we'll skip the attempt to
-		 * determine what's being used.
-		 */
-		index = 0;
-
-		temp_func = func;
-
-		while ((temp_func = pciehp_slot_find(temp_func->bus, temp_func->device, index++))) {
-			if (temp_func->bus_head || temp_func->mem_head
-			    || temp_func->p_mem_head || temp_func->io_head) {
-				skip = 1;
-				break;
-			}
-		}
-
-		if (!skip)
-			rc = pciehp_save_used_resources(ctrl, func, DISABLE_CARD);
-	}
 	/* Change status to shutdown */
-	if (func->is_a_board)
-		func->status = 0x01;
-	func->configured = 0;
+	p_slot->status = 0x01;
 
 	/* Wait for exclusive access to hardware */
 	down(&ctrl->crit_sect);
@@ -1328,56 +411,6 @@
 	/* Done with exclusive hardware access */
 	up(&ctrl->crit_sect);
 
-	if (ctrl->add_support) {
-		while (func) {
-			res_lists.io_head = ctrl->io_head;
-			res_lists.mem_head = ctrl->mem_head;
-			res_lists.p_mem_head = ctrl->p_mem_head;
-			res_lists.bus_head = ctrl->bus_head;
-
-			dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", 
-				func->bus, func->device, func->function);
-
-			pciehp_return_board_resources(func, &res_lists);
-
-			ctrl->io_head = res_lists.io_head;
-			ctrl->mem_head = res_lists.mem_head;
-			ctrl->p_mem_head = res_lists.p_mem_head;
-			ctrl->bus_head = res_lists.bus_head;
-
-			pciehp_resource_sort_and_combine(&(ctrl->mem_head));
-			pciehp_resource_sort_and_combine(&(ctrl->p_mem_head));
-			pciehp_resource_sort_and_combine(&(ctrl->io_head));
-			pciehp_resource_sort_and_combine(&(ctrl->bus_head));
-
-			if (is_bridge(func)) {
-				dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
-					ctrl->seg, func->bus, func->device, func->function);
-				bridge_slot_remove(func);
-			} else {
-				dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
-					ctrl->seg, func->bus, func->device, func->function);
-				slot_remove(func);
-			}
-
-			func = pciehp_slot_find(ctrl->slot_bus, device, 0);
-		}
-
-		/* Setup slot structure with entry for empty slot */
-		func = pciehp_slot_create(ctrl->slot_bus);
-
-		if (func == NULL) {
-			return 1;
-		}
-
-		func->bus = ctrl->slot_bus;
-		func->device = device;
-		func->function = 0;
-		func->configured = 0;
-		func->switch_save = 0x10;
-		func->is_a_board = 0;
-	}
-
 	return 0;
 }
 
@@ -1411,13 +444,15 @@
 	p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (getstatus) {
 		p_slot->state = POWEROFF_STATE;
-		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+		dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__,
+				p_slot->bus, p_slot->device);
 
 		pciehp_disable_slot(p_slot);
 		p_slot->state = STATIC_STATE;
 	} else {
 		p_slot->state = POWERON_STATE;
-		dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+		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 */
@@ -1459,13 +494,15 @@
 	p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
 	if (!getstatus) {
 		p_slot->state = POWEROFF_STATE;
-		dbg("In removing board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+		dbg("%s: removing bus:device(%x:%x)\n",
+				__FUNCTION__, p_slot->bus, p_slot->device);
 
 		pciehp_disable_slot(p_slot);
 		p_slot->state = STATIC_STATE;
 	} else {
 		p_slot->state = POWERON_STATE;
-		dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+		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 */
@@ -1531,7 +568,6 @@
 		err ("Can't start up our event thread\n");
 		return -1;
 	}
-	dbg("Our event thread pid = %d\n", pid);
 	return 0;
 }
 
@@ -1539,9 +575,7 @@
 void pciehp_event_stop_thread(void)
 {
 	event_finished = 1;
-	dbg("event_thread finish command given\n");
 	up(&event_semaphore);
-	dbg("wait for event_thread to exit\n");
 	down(&event_exit);
 }
 
@@ -1573,7 +607,6 @@
 {
 	int loop = 0;
 	int change = 1;
-	struct pci_func *func;
 	u8 hp_slot;
 	u8 getstatus;
 	struct slot *p_slot;
@@ -1581,16 +614,12 @@
 	while (change) {
 		change = 0;
 
-		for (loop = 0; loop < 10; loop++) {
+		for (loop = 0; loop < MAX_EVENTS; loop++) {
 			if (ctrl->event_queue[loop].event_type != 0) {
 				hp_slot = ctrl->event_queue[loop].hp_slot;
 
-				func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
-
 				p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
-				dbg("hp_slot %d, func %p, p_slot %p\n", hp_slot, func, p_slot);
-
 				if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
 					dbg("button cancel\n");
 					del_timer(&p_slot->task_event);
@@ -1682,7 +711,6 @@
 						p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
 						p_slot->task_event.data = (unsigned long) p_slot;
 
-						dbg("add_timer p_slot = %p\n", (void *) p_slot);
 						add_timer(&p_slot->task_event);
 					}
 				}
@@ -1737,13 +765,6 @@
 {
 	u8 getstatus = 0;
 	int rc;
-	struct pci_func *func;
-
-	func = pciehp_slot_find(p_slot->bus, p_slot->device, 0);
-	if (!func) {
-		dbg("%s: Error! slot NULL\n", __FUNCTION__);
-		return 1;
-	}
 
 	/* Check to see if (latch closed, card present, power off) */
 	down(&p_slot->ctrl->crit_sect);
@@ -1773,45 +794,11 @@
 	}
 	up(&p_slot->ctrl->crit_sect);
 
-	slot_remove(func);
-
-	func = pciehp_slot_create(p_slot->bus);
-	if (func == NULL)
-		return 1;
-
-	func->bus = p_slot->bus;
-	func->device = p_slot->device;
-	func->function = 0;
-	func->configured = 0;
-	func->is_a_board = 1;
-
-	/* We have to save the presence info for these slots */
-	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
-	func->switch_save = !getstatus? 0x10:0;
 
-	rc = board_added(func, p_slot->ctrl);
+	rc = board_added(p_slot);
 	if (rc) {
-		if (is_bridge(func))
-			bridge_slot_remove(func);
-		else
-			slot_remove(func);
-
-		/* Setup slot structure with entry for empty slot */
-		func = pciehp_slot_create(p_slot->bus);
-		if (func == NULL)
-			return 1;	/* Out of memory */
-
-		func->bus = p_slot->bus;
-		func->device = p_slot->device;
-		func->function = 0;
-		func->configured = 0;
-		func->is_a_board = 1;
-
-		/* We have to save the presence info for these slots */
-		p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
 		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
-		func->switch_save = !getstatus? 0x10:0;
 	}
 
 	if (p_slot)
@@ -1823,14 +810,8 @@
 
 int pciehp_disable_slot(struct slot *p_slot)
 {
-	u8 class_code, header_type, BCR;
-	u8 index = 0;
 	u8 getstatus = 0;
-	u32 rc = 0;
 	int ret = 0;
-	unsigned int devfn;
-	struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate;
-	struct pci_func *func;
 
 	if (!p_slot->ctrl)
 		return 1;
@@ -1867,838 +848,8 @@
 
 	up(&p_slot->ctrl->crit_sect);
 
-	func = pciehp_slot_find(p_slot->bus, p_slot->device, index++);
-
-	/* Make sure there are no video controllers here
-	 * for all func of p_slot
-	 */
-	while (func && !rc) {
-		pci_bus->number = func->bus;
-		devfn = PCI_DEVFN(func->device, func->function);
-
-		/* Check the Class Code */
-		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
-		if (rc)
-			return rc;
-
-		if (class_code == PCI_BASE_CLASS_DISPLAY) {
-			/* Display/Video adapter (not supported) */
-			rc = REMOVE_NOT_SUPPORTED;
-		} else {
-			/* See if it's a bridge */
-			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
-			if (rc)
-				return rc;
-
-			/* If it's a bridge, check the VGA Enable bit */
-			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
-				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
-				if (rc)
-					return rc;
-
-				/* If the VGA Enable bit is set, remove isn't supported */
-				if (BCR & PCI_BRIDGE_CTL_VGA) {
-					rc = REMOVE_NOT_SUPPORTED;
-				}
-			}
-		}
-
-		func = pciehp_slot_find(p_slot->bus, p_slot->device, index++);
-	}
-
-	func = pciehp_slot_find(p_slot->bus, p_slot->device, 0);
-	if ((func != NULL) && !rc) {
-		rc = remove_board(func, p_slot->ctrl);
-	} else if (!rc)
-		rc = 1;
-
-	if (p_slot)
-		update_slot_info(p_slot);
-
-	return rc;
+	ret = remove_board(p_slot);
+	update_slot_info(p_slot);
+	return ret;
 }
 
-
-/**
- * configure_new_device - Configures the PCI header information of one board.
- *
- * @ctrl: pointer to controller structure
- * @func: pointer to function structure
- * @behind_bridge: 1 if this is a recursive call, 0 if not
- * @resources: pointer to set of resource lists
- *
- * Returns 0 if success
- *
- */
-static u32 configure_new_device(struct controller * ctrl, struct pci_func * func,
-	u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev)
-{
-	u8 temp_byte, function, max_functions, stop_it;
-	int rc;
-	u32 ID;
-	struct pci_func *new_slot;
-	struct pci_bus lpci_bus, *pci_bus;
-	int index;
-
-	new_slot = func;
-
-	dbg("%s\n", __FUNCTION__);
-	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
-	pci_bus = &lpci_bus;
-	pci_bus->number = func->bus;
-
-	/* Check for Multi-function device */
-	rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte);
-	if (rc) {
-		dbg("%s: rc = %d\n", __FUNCTION__, rc);
-		return rc;
-	}
-
-	if (temp_byte & 0x80)	/* Multi-function device */
-		max_functions = 8;
-	else
-		max_functions = 1;
-
-	function = 0;
-
-	do {
-		rc = configure_new_function(ctrl, new_slot, behind_bridge,
-					resources, bridge_bus, bridge_dev);
-
-		if (rc) {
-			dbg("configure_new_function failed: %d\n", rc);
-			index = 0;
-
-			while (new_slot) {
-				new_slot = pciehp_slot_find(new_slot->bus,
-						new_slot->device, index++);
-
-				if (new_slot)
-					pciehp_return_board_resources(new_slot,
-						resources);
-			}
-
-			return rc;
-		}
-
-		function++;
-
-		stop_it = 0;
-
-		/*  The following loop skips to the next present function
-		 *  and creates a board structure
-		 */
-
-		while ((function < max_functions) && (!stop_it)) {
-			pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
-
-			if (ID == 0xFFFFFFFF) {	  /* There's nothing there. */
-				function++;
-			} else {  /* There's something there */
-				/* Setup slot structure. */
-				new_slot = pciehp_slot_create(func->bus);
-
-				if (new_slot == NULL) {
-					/* Out of memory */
-					return 1;
-				}
-
-				new_slot->bus = func->bus;
-				new_slot->device = func->device;
-				new_slot->function = function;
-				new_slot->is_a_board = 1;
-				new_slot->status = 0;
-
-				stop_it++;
-			}
-		}
-
-	} while (function < max_functions);
-	dbg("returning from %s\n", __FUNCTION__);
-
-	return 0;
-}
-
-/*
- * Configuration logic that involves the hotplug data structures and 
- * their bookkeeping
- */
-
-/**
- * configure_bridge: fill bridge's registers, either configure or disable it.
- */
-static int
-configure_bridge(struct pci_bus *pci_bus, unsigned int devfn,
-			struct pci_resource *mem_node,
-			struct pci_resource **hold_mem_node,
-			int base_addr, int limit_addr)
-{
-	u16 temp_word;
-	u32 rc;
-
-	if (mem_node) {
-		memcpy(*hold_mem_node, mem_node, sizeof(struct pci_resource));
-		mem_node->next = NULL;
-
-		/* set Mem base and Limit registers */
-		RES_CHECK(mem_node->base, 16);
-		temp_word = (u16)(mem_node->base >> 16);
-		rc = pci_bus_write_config_word(pci_bus, devfn, base_addr, temp_word);
-
-		RES_CHECK(mem_node->base + mem_node->length - 1, 16);
-		temp_word = (u16)((mem_node->base + mem_node->length - 1) >> 16);
-		rc = pci_bus_write_config_word(pci_bus, devfn, limit_addr, temp_word);
-	} else {
-		temp_word = 0xFFFF;
-		rc = pci_bus_write_config_word(pci_bus, devfn, base_addr, temp_word);
-
-		temp_word = 0x0000;
-		rc = pci_bus_write_config_word(pci_bus, devfn, limit_addr, temp_word);
-
-		kfree(*hold_mem_node);
-		*hold_mem_node = NULL;
-	}
-	return rc;
-}
-
-static int
-configure_new_bridge(struct controller *ctrl, struct pci_func *func,
-		u8 behind_bridge, struct resource_lists *resources,
-		struct pci_bus *pci_bus)
-{
-	int cloop;
-	u8 temp_byte;
-	u8 device;
-	u16 temp_word;
-	u32 rc;
-	u32 ID;
-	unsigned int devfn;
-	struct pci_resource *mem_node;
-	struct pci_resource *p_mem_node;
-	struct pci_resource *io_node;
-	struct pci_resource *bus_node;
-	struct pci_resource *hold_mem_node;
-	struct pci_resource *hold_p_mem_node;
-	struct pci_resource *hold_IO_node;
-	struct pci_resource *hold_bus_node;
-	struct irq_mapping irqs;
-	struct pci_func *new_slot;
-	struct resource_lists temp_resources;
-
-	devfn = PCI_DEVFN(func->device, func->function);
-
-	/* set Primary bus */
-	dbg("set Primary bus = 0x%x\n", func->bus);
-	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
-	if (rc)
-		return rc;
-
-	/* find range of busses to use */
-	bus_node = get_max_resource(&resources->bus_head, 1L);
-
-	/* If we don't have any busses to allocate, we can't continue */
-	if (!bus_node) {
-		err("Got NO bus resource to use\n");
-		return -ENOMEM;
-	}
-	dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length);
-
-	/* set Secondary bus */
-	temp_byte = (u8)bus_node->base;
-	dbg("set Secondary bus = 0x%x\n", temp_byte);
-	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
-	if (rc)
-		return rc;
-
-	/* set subordinate bus */
-	temp_byte = (u8)(bus_node->base + bus_node->length - 1);
-	dbg("set subordinate bus = 0x%x\n", temp_byte);
-	rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
-	if (rc)
-		return rc;
-
-	/* Set HP parameters (Cache Line Size, Latency Timer) */
-	rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
-	if (rc)
-		return rc;
-
-	/* Setup the IO, memory, and prefetchable windows */
-
-	io_node = get_max_resource(&(resources->io_head), 0x1000L);
-	if (io_node) {
-		dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base,
-				io_node->length, io_node->next);
-	}
-
-	mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
-	if (mem_node) {
-		dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base,
-				mem_node->length, mem_node->next);
-	}
-
-	if (resources->p_mem_head)
-		p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L);
-	else {
-		/*
-		 * In some platform implementation, MEM and PMEM are not
-		 *  distinguished, and hence ACPI _CRS has only MEM entries
-		 *  for both MEM and PMEM.
-		 */
-		dbg("using MEM for PMEM\n");
-		p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
-	}
-	if (p_mem_node) {
-		dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base,
-				p_mem_node->length, p_mem_node->next);
-	}
-
-	/* set up the IRQ info */
-	if (!resources->irqs) {
-		irqs.barber_pole = 0;
-		irqs.interrupt[0] = 0;
-		irqs.interrupt[1] = 0;
-		irqs.interrupt[2] = 0;
-		irqs.interrupt[3] = 0;
-		irqs.valid_INT = 0;
-	} else {
-		irqs.barber_pole = resources->irqs->barber_pole;
-		irqs.interrupt[0] = resources->irqs->interrupt[0];
-		irqs.interrupt[1] = resources->irqs->interrupt[1];
-		irqs.interrupt[2] = resources->irqs->interrupt[2];
-		irqs.interrupt[3] = resources->irqs->interrupt[3];
-		irqs.valid_INT = resources->irqs->valid_INT;
-	}
-
-	/* set up resource lists that are now aligned on top and bottom
-	 * for anything behind the bridge.
-	 */
-	temp_resources.bus_head = bus_node;
-	temp_resources.io_head = io_node;
-	temp_resources.mem_head = mem_node;
-	temp_resources.p_mem_head = p_mem_node;
-	temp_resources.irqs = &irqs;
-
-	/* Make copies of the nodes we are going to pass down so that
-	 * if there is a problem,we can just use these to free resources
-	 */
-	hold_bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-	hold_IO_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-	hold_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-	hold_p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-	if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
-		kfree(hold_bus_node);
-		kfree(hold_IO_node);
-		kfree(hold_mem_node);
-		kfree(hold_p_mem_node);
-
-		return 1;
-	}
-
-	memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
-
-	bus_node->base += 1;
-	bus_node->length -= 1;
-	bus_node->next = NULL;
-
-	/* If we have IO resources copy them and fill in the bridge's
-	 * IO range registers
-	 */
-	if (io_node) {
-		memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
-		io_node->next = NULL;
-
-		/* set IO base and Limit registers */
-		RES_CHECK(io_node->base, 8);
-		temp_byte = (u8)(io_node->base >> 8);
-		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
-
-		RES_CHECK(io_node->base + io_node->length - 1, 8);
-		temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8);
-		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
-	} else {
-		kfree(hold_IO_node);
-		hold_IO_node = NULL;
-	}
-
-	/* If we have memory resources copy them and fill in the bridge's
-	 * memory range registers.  Otherwise, fill in the range
-	 * registers with values that disable them.
-	 */
-	rc = configure_bridge(pci_bus, devfn, mem_node, &hold_mem_node,
-				PCI_MEMORY_BASE, PCI_MEMORY_LIMIT);
-
-	/* If we have prefetchable memory resources copy them and 
-	 * fill in the bridge's memory range registers.  Otherwise,
-	 * fill in the range registers with values that disable them.
-	 */
-	rc = configure_bridge(pci_bus, devfn, p_mem_node, &hold_p_mem_node,
-				PCI_PREF_MEMORY_BASE, PCI_PREF_MEMORY_LIMIT);
-
-	/* Adjust this to compensate for extra adjustment in first loop */
-	irqs.barber_pole--;
-
-	rc = 0;
-
-	/* Here we actually find the devices and configure them */
-	for (device = 0; (device <= 0x1F) && !rc; device++) {
-		irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
-
-		ID = 0xFFFFFFFF;
-		pci_bus->number = hold_bus_node->base;
-		pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
-		pci_bus->number = func->bus;
-
-		if (ID != 0xFFFFFFFF) {	  /*  device Present */
-			/* Setup slot structure. */
-			new_slot = pciehp_slot_create(hold_bus_node->base);
-
-			if (new_slot == NULL) {
-				/* Out of memory */
-				rc = -ENOMEM;
-				continue;
-			}
-
-			new_slot->bus = hold_bus_node->base;
-			new_slot->device = device;
-			new_slot->function = 0;
-			new_slot->is_a_board = 1;
-			new_slot->status = 0;
-
-			rc = configure_new_device(ctrl, new_slot, 1,
-					&temp_resources, func->bus,
-					func->device);
-			dbg("configure_new_device rc=0x%x\n",rc);
-		}	/* End of IF (device in slot?) */
-	}		/* End of FOR loop */
-
-	if (rc) {
-		pciehp_destroy_resource_list(&temp_resources);
-
-		return_resource(&(resources->bus_head), hold_bus_node);
-		return_resource(&(resources->io_head), hold_IO_node);
-		return_resource(&(resources->mem_head), hold_mem_node);
-		return_resource(&(resources->p_mem_head), hold_p_mem_node);
-		return(rc);
-	}
-
-	/* save the interrupt routing information */
-	if (resources->irqs) {
-		resources->irqs->interrupt[0] = irqs.interrupt[0];
-		resources->irqs->interrupt[1] = irqs.interrupt[1];
-		resources->irqs->interrupt[2] = irqs.interrupt[2];
-		resources->irqs->interrupt[3] = irqs.interrupt[3];
-		resources->irqs->valid_INT = irqs.valid_INT;
-	} else if (!behind_bridge) {
-		/* We need to hook up the interrupts here */
-		for (cloop = 0; cloop < 4; cloop++) {
-			if (irqs.valid_INT & (0x01 << cloop)) {
-				rc = pciehp_set_irq(func->bus, func->device,
-							0x0A + cloop, irqs.interrupt[cloop]);
-				if (rc) {
-					pciehp_destroy_resource_list (&temp_resources);
-					return_resource(&(resources->bus_head), hold_bus_node);
-					return_resource(&(resources->io_head), hold_IO_node);
-					return_resource(&(resources->mem_head), hold_mem_node);
-					return_resource(&(resources->p_mem_head), hold_p_mem_node);
-					return rc;
-				}
-			}
-		}	/* end of for loop */
-	}
-
-	/* Return unused bus resources
-	 * First use the temporary node to store information for the board
-	 */
-	if (hold_bus_node && bus_node && temp_resources.bus_head) {
-		hold_bus_node->length = bus_node->base - hold_bus_node->base;
-
-		hold_bus_node->next = func->bus_head;
-		func->bus_head = hold_bus_node;
-
-		temp_byte = (u8)(temp_resources.bus_head->base - 1);
-
-		/* set subordinate bus */
-		dbg("re-set subordinate bus = 0x%x\n", temp_byte);
-		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
-
-		if (temp_resources.bus_head->length == 0) {
-			kfree(temp_resources.bus_head);
-			temp_resources.bus_head = NULL;
-		} else {
-			dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
-				func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length);
-			return_resource(&(resources->bus_head), temp_resources.bus_head);
-		}
-	}
-
-	/* If we have IO space available and there is some left,
-	 * return the unused portion
-	 */
-	if (hold_IO_node && temp_resources.io_head) {
-		io_node = do_pre_bridge_resource_split(&(temp_resources.io_head),
-							&hold_IO_node, 0x1000);
-
-		/* Check if we were able to split something off */
-		if (io_node) {
-			hold_IO_node->base = io_node->base + io_node->length;
-
-			RES_CHECK(hold_IO_node->base, 8);
-			temp_byte = (u8)((hold_IO_node->base) >> 8);
-			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
-
-			return_resource(&(resources->io_head), io_node);
-		}
-
-		io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000);
-
-		/*  Check if we were able to split something off */
-		if (io_node) {
-			/* First use the temporary node to store information for the board */
-			hold_IO_node->length = io_node->base - hold_IO_node->base;
-
-			/* If we used any, add it to the board's list */
-			if (hold_IO_node->length) {
-				hold_IO_node->next = func->io_head;
-				func->io_head = hold_IO_node;
-
-				RES_CHECK(io_node->base - 1, 8);
-				temp_byte = (u8)((io_node->base - 1) >> 8);
-				rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
-
-				return_resource(&(resources->io_head), io_node);
-			} else {
-				/* it doesn't need any IO */
-				temp_byte = 0x00;
-				rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
-
-				return_resource(&(resources->io_head), io_node);
-				kfree(hold_IO_node);
-			}
-		} else {
-			/* it used most of the range */
-			hold_IO_node->next = func->io_head;
-			func->io_head = hold_IO_node;
-		}
-	} else if (hold_IO_node) {
-		/* it used the whole range */
-		hold_IO_node->next = func->io_head;
-		func->io_head = hold_IO_node;
-	}
-
-	/* If we have memory space available and there is some left,
-	 * return the unused portion
-	 */
-	if (hold_mem_node && temp_resources.mem_head) {
-		mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L);
-
-		/* Check if we were able to split something off */
-		if (mem_node) {
-			hold_mem_node->base = mem_node->base + mem_node->length;
-
-			RES_CHECK(hold_mem_node->base, 16);
-			temp_word = (u16)((hold_mem_node->base) >> 16);
-			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
-
-			return_resource(&(resources->mem_head), mem_node);
-		}
-
-		mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L);
-
-		/* Check if we were able to split something off */
-		if (mem_node) {
-			/* First use the temporary node to store information for the board */
-			hold_mem_node->length = mem_node->base - hold_mem_node->base;
-
-			if (hold_mem_node->length) {
-				hold_mem_node->next = func->mem_head;
-				func->mem_head = hold_mem_node;
-
-				/* configure end address */
-				RES_CHECK(mem_node->base - 1, 16);
-				temp_word = (u16)((mem_node->base - 1) >> 16);
-				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
-
-				/* Return unused resources to the pool */
-				return_resource(&(resources->mem_head), mem_node);
-			} else {
-				/* it doesn't need any Mem */
-				temp_word = 0x0000;
-				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
-
-				return_resource(&(resources->mem_head), mem_node);
-				kfree(hold_mem_node);
-			}
-		} else {
-			/* it used most of the range */
-			hold_mem_node->next = func->mem_head;
-			func->mem_head = hold_mem_node;
-		}
-	} else if (hold_mem_node) {
-		/* it used the whole range */
-		hold_mem_node->next = func->mem_head;
-		func->mem_head = hold_mem_node;
-	}
-
-	/* If we have prefetchable memory space available and there is some 
-	 * left at the end, return the unused portion
-	 */
-	if (hold_p_mem_node && temp_resources.p_mem_head) {
-		p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
-								&hold_p_mem_node, 0x100000L);
-
-		/* Check if we were able to split something off */
-		if (p_mem_node) {
-			hold_p_mem_node->base = p_mem_node->base + p_mem_node->length;
-
-			RES_CHECK(hold_p_mem_node->base, 16);
-			temp_word = (u16)((hold_p_mem_node->base) >> 16);
-			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
-
-			return_resource(&(resources->p_mem_head), p_mem_node);
-		}
-
-		p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L);
-
-		/* Check if we were able to split something off */
-		if (p_mem_node) {
-			/* First use the temporary node to store information for the board */
-			hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base;
-
-			/* If we used any, add it to the board's list */
-			if (hold_p_mem_node->length) {
-				hold_p_mem_node->next = func->p_mem_head;
-				func->p_mem_head = hold_p_mem_node;
-
-				RES_CHECK(p_mem_node->base - 1, 16);
-				temp_word = (u16)((p_mem_node->base - 1) >> 16);
-				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
-
-				return_resource(&(resources->p_mem_head), p_mem_node);
-			} else {
-				/* it doesn't need any PMem */
-				temp_word = 0x0000;
-				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
-
-				return_resource(&(resources->p_mem_head), p_mem_node);
-				kfree(hold_p_mem_node);
-			}
-		} else {
-			/* it used the most of the range */
-			hold_p_mem_node->next = func->p_mem_head;
-			func->p_mem_head = hold_p_mem_node;
-		}
-	} else if (hold_p_mem_node) {
-		/* it used the whole range */
-		hold_p_mem_node->next = func->p_mem_head;
-		func->p_mem_head = hold_p_mem_node;
-	}
-
-	/* We should be configuring an IRQ and the bridge's base address
-	 * registers if it needs them.  Although we have never seen such
-	 * a device
-	 */
-
-	pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
-
-	dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function);
-
-	return rc;
-}
-
-/**
- * configure_new_function - Configures the PCI header information of one device
- *
- * @ctrl: pointer to controller structure
- * @func: pointer to function structure
- * @behind_bridge: 1 if this is a recursive call, 0 if not
- * @resources: pointer to set of resource lists
- *
- * Calls itself recursively for bridged devices.
- * Returns 0 if success
- *
- */
-static int
-configure_new_function(struct controller *ctrl, struct pci_func *func,
-		u8 behind_bridge, struct resource_lists *resources,
-		u8 bridge_bus, u8 bridge_dev)
-{
-	int cloop;
-	u8 temp_byte;
-	u8 class_code;
-	u32 rc;
-	u32 temp_register;
-	u32 base;
-	unsigned int devfn;
-	struct pci_resource *mem_node;
-	struct pci_resource *io_node;
-	struct pci_bus lpci_bus, *pci_bus;
-
-	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
-	pci_bus = &lpci_bus;
-	pci_bus->number = func->bus;
-	devfn = PCI_DEVFN(func->device, func->function);
-
-	/* Check for Bridge */
-	rc = pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte);
-	if (rc)
-		return rc;
-	dbg("%s: bus %x dev %x func %x temp_byte = %x\n", __FUNCTION__,
-		func->bus, func->device, func->function, temp_byte);
-
-	if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
-		rc = configure_new_bridge(ctrl, func, behind_bridge, resources,
-						pci_bus);
-
-		if (rc)
-			return rc;
-	} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
-		/* Standard device */
-		u64	base64;
-		rc = pci_bus_read_config_byte(pci_bus, devfn, 0x0B, &class_code);
-
-		if (class_code == PCI_BASE_CLASS_DISPLAY)
-			return DEVICE_TYPE_NOT_SUPPORTED;
-
-		/* Figure out IO and memory needs */
-		for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
-			temp_register = 0xFFFFFFFF;
-
-			rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
-			rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register);
-			dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, 
-				func->bus, func->device, func->function);
-
-			if (!temp_register)
-				continue;
-
-			base64 = 0L;
-			if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) {
-				/* Map IO */
-
-				/* set base = amount of IO space */
-				base = temp_register & 0xFFFFFFFC;
-				base = ~base + 1;
-
-				dbg("NEED IO length(0x%x)\n", base);
-				io_node = get_io_resource(&(resources->io_head),(ulong)base);
-
-				/* allocate the resource to the board */
-				if (io_node) {
-					dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length);
-					base = (u32)io_node->base;
-					io_node->next = func->io_head;
-					func->io_head = io_node;
-				} else {
-					err("Got NO IO resource(length=0x%x)\n", base);
-					return -ENOMEM;
-				}
-			} else {	/* map MEM */
-				int prefetchable = 1;
-				struct pci_resource **res_node = &func->p_mem_head;
-				char *res_type_str = "PMEM";
-				u32	temp_register2;
-
-				if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) {
-					prefetchable = 0;
-					res_node = &func->mem_head;
-					res_type_str++;
-				}
-
-				base = temp_register & 0xFFFFFFF0;
-				base = ~base + 1;
-
-				switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
-				case PCI_BASE_ADDRESS_MEM_TYPE_32:
-					dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base);
-
-					if (prefetchable && resources->p_mem_head)
-						mem_node=get_resource(&(resources->p_mem_head), (ulong)base);
-					else {
-						if (prefetchable)
-							dbg("using MEM for PMEM\n");
-						mem_node = get_resource(&(resources->mem_head), (ulong)base);
-					}
-
-					/* allocate the resource to the board */
-					if (mem_node) {
-						base = (u32)mem_node->base; 
-						mem_node->next = *res_node;
-						*res_node = mem_node;
-						dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, 
-							mem_node->length);
-					} else {
-						err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base);
-						return -ENOMEM;
-					}
-					break;
-				case PCI_BASE_ADDRESS_MEM_TYPE_64:
-					rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
-					dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, 
-						temp_register, base);
-
-					if (prefetchable && resources->p_mem_head)
-						mem_node = get_resource(&(resources->p_mem_head), (ulong)base);
-					else {
-						if (prefetchable)
-							dbg("using MEM for PMEM\n");
-						mem_node = get_resource(&(resources->mem_head), (ulong)base);
-					}
-
-					/* allocate the resource to the board */
-					if (mem_node) {
-						base64 = mem_node->base; 
-						mem_node->next = *res_node;
-						*res_node = mem_node;
-						dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), 
-							(u32)base64, mem_node->length);
-					} else {
-						err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base);
-						return -ENOMEM;
-					}
-					break;
-				default:
-					dbg("reserved BAR type=0x%x\n", temp_register);
-					break;
-				}
-
-			}
-
-			if (base64) {
-				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
-				cloop += 4;
-				base64 >>= 32;
-
-				if (base64) {
-					dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64);
-					base64 = 0x0L;
-				}
-
-				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
-			} else {
-				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base);
-			}
-		}		/* End of base register loop */
-
-		/* disable ROM base Address */
-		rc = pci_bus_write_config_dword (pci_bus, devfn, PCI_ROM_ADDRESS, 0x00);
-
-		/* Set HP parameters (Cache Line Size, Latency Timer) */
-		rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL);
-		if (rc)
-			return rc;
-
-		pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL);
-
-		dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, 
-			func->function);
-	}  /* End of Not-A-Bridge else */
-	else {
-		/* It's some strange type of PCI adapter (Cardbus?) */
-		return DEVICE_TYPE_NOT_SUPPORTED;
-	}
-
-	func->configured = 1;
-
-	return 0;
-}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 7a0e27f..4a3cecc 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -27,16 +27,10 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
 #include <linux/pci.h>
-#include <asm/system.h>
 #include "../pci.h"
 #include "pciehp.h"
 
@@ -217,23 +211,6 @@
 #define MRL_STATE		0x0020
 #define PRSN_STATE		0x0040
 
-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 */
-};
-
-
 static spinlock_t hpc_event_lock;
 
 DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
@@ -297,7 +274,6 @@
 
 	DBG_ENTER_ROUTINE 
 	
-	dbg("%s : Enter\n", __FUNCTION__);
 	if (!php_ctlr) {
 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
 		return -1;
@@ -308,7 +284,6 @@
 			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
 			return retval;
 		}
-	dbg("%s : hp_register_read_word SLOT_STATUS %x\n", __FUNCTION__, slot_status);
 	
 	if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { 
 		/* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue 
@@ -316,14 +291,11 @@
 		dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
 	}
 
-	dbg("%s: Before hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd);
 	retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE);
 	if (retval) {
 		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 		return retval;
 	}
-	dbg("%s : hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd | CMD_CMPL_INTR_ENABLE);
-	dbg("%s : Exit\n", __FUNCTION__);
 
 	DBG_LEAVE_ROUTINE 
 	return retval;
@@ -509,7 +481,6 @@
 	u16 slot_status;
 	u8 pwr_fault;
 	int retval = 0;
-	u8 status;
 
 	DBG_ENTER_ROUTINE 
 
@@ -521,15 +492,13 @@
 	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__);
+		err("%s : Cannot check for power fault\n", __FUNCTION__);
 		return retval;
 	}
 	pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
-	status = (pwr_fault != 1) ? 1 : 0;
 	
 	DBG_LEAVE_ROUTINE
-	/* Note: Logic 0 => fault */
-	return status;
+	return pwr_fault;
 }
 
 static int hpc_set_attention_status(struct slot *slot, u8 value)
@@ -539,7 +508,8 @@
 	u16 slot_ctrl;
 	int rc = 0;
 
-	dbg("%s: \n", __FUNCTION__);
+	DBG_ENTER_ROUTINE
+
 	if (!php_ctlr) {
 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
 		return -1;
@@ -555,7 +525,6 @@
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return rc;
 	}
-	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
 
 	switch (value) {
 		case 0 :	/* turn off */
@@ -576,6 +545,7 @@
 	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_LEAVE_ROUTINE
 	return rc;
 }
 
@@ -587,7 +557,8 @@
 	u16 slot_ctrl;
 	int rc = 0;
        	
-	dbg("%s: \n", __FUNCTION__);	
+	DBG_ENTER_ROUTINE
+
 	if (!php_ctlr) {
 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
 		return ;
@@ -604,7 +575,6 @@
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return;
 	}
-	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
 	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
 	if (!pciehp_poll_mode)
 		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
@@ -612,6 +582,7 @@
 	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_LEAVE_ROUTINE
 	return;
 }
 
@@ -622,7 +593,8 @@
 	u16 slot_ctrl;
 	int rc = 0;
 
-	dbg("%s: \n", __FUNCTION__);	
+	DBG_ENTER_ROUTINE
+
 	if (!php_ctlr) {
 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
 		return ;
@@ -639,7 +611,6 @@
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return;
 	}
-	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
 
 	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300;
 
@@ -648,6 +619,7 @@
 	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_LEAVE_ROUTINE
 	return;
 }
 
@@ -658,7 +630,8 @@
 	u16 slot_ctrl;
 	int rc = 0; 
 	
-	dbg("%s: \n", __FUNCTION__);	
+	DBG_ENTER_ROUTINE
+
 	if (!php_ctlr) {
 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
 		return ;
@@ -675,7 +648,6 @@
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return;
 	}
-	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
 
 	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200;
 
@@ -684,6 +656,7 @@
 	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_LEAVE_ROUTINE
 	return;
 }
 
@@ -780,7 +753,6 @@
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
-	dbg("%s: \n", __FUNCTION__);	
 
 	if (!php_ctlr) {
 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
@@ -799,8 +771,6 @@
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return retval;
 	}
-	dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base),
-		slot_ctrl);
 
 	slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON;
 
@@ -829,7 +799,6 @@
 	int retval = 0;
 
 	DBG_ENTER_ROUTINE 
-	dbg("%s: \n", __FUNCTION__);	
 
 	if (!php_ctlr) {
 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
@@ -848,8 +817,6 @@
 		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
 		return retval;
 	}
-	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base),
-		slot_ctrl);
 
 	slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF;
 
@@ -924,7 +891,6 @@
 			return IRQ_NONE;
 		}
 
-		dbg("%s: Set Mask Hot-plug Interrupt Enable\n", __FUNCTION__);
 		dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
 		temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
 
@@ -933,7 +899,6 @@
 			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 			return IRQ_NONE;
 		}
-		dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
 		
 		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
 		if (rc) {
@@ -949,14 +914,12 @@
 			err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
 			return IRQ_NONE;
 		}
-		dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word);
 	}
 	
 	if (intr_loc & CMD_COMPLETED) {
 		/* 
 		 * Command Complete Interrupt Pending 
 		 */
-		dbg("%s: In Command Complete Interrupt Pending\n", __FUNCTION__);
 		wake_up_interruptible(&ctrl->queue);
 	}
 
@@ -989,7 +952,6 @@
 		}
 
 		dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
-		dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
 		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);
@@ -997,14 +959,12 @@
 			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 			return IRQ_NONE;
 		}
-		dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); 	
 	
 		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); 
 		
 		/* Clear command complete interrupt caused by this write */
 		temp_word = 0x1F;
@@ -1248,12 +1208,7 @@
 	.check_lnk_status		= hpc_check_lnk_status,
 };
 
-int pcie_init(struct controller * ctrl,
-	struct pcie_device *dev,
-	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)
+int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 {
 	struct php_ctlr_state_s *php_ctlr, *p;
 	void *instance_id = ctrl;
@@ -1282,8 +1237,8 @@
 	pdev = dev->port;
 	php_ctlr->pci_dev = pdev;	/* save pci_dev in context */
 
-	dbg("%s: pdev->vendor %x pdev->device %x\n", __FUNCTION__,
-		pdev->vendor, pdev->device);
+	dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
+			__FUNCTION__, pdev->vendor, pdev->device);
 
 	saved_cap_base = pcie_cap_base;
 
@@ -1340,8 +1295,6 @@
 		first = 0;
 	}
 
-	dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, 
-		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
 	for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
 		if (pci_resource_len(pdev, rc) > 0)
 			dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc,
@@ -1359,13 +1312,12 @@
 
 	/* find the IRQ */
 	php_ctlr->irq = dev->irq;
-	dbg("HPC interrupt = %d\n", php_ctlr->irq);
 
 	/* Save interrupt callback info */
-	php_ctlr->attention_button_callback = attention_button_callback;
-	php_ctlr->switch_change_callback = switch_change_callback;
-	php_ctlr->presence_change_callback = presence_change_callback;
-	php_ctlr->power_fault_callback = power_fault_callback;
+	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 */
@@ -1387,15 +1339,12 @@
 		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word);
 
 	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__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base)
-		, slot_status);
 
 	temp_word = 0x1F; /* Clear all events */
 	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
@@ -1403,7 +1352,6 @@
 		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word);
 
 	if (pciehp_poll_mode)  {/* Install interrupt polling code */
 		/* Install and start the interrupt polling timer */
@@ -1419,13 +1367,14 @@
 		}
 	}
 
+	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);
 	if (rc) {
 		err("%s : hp_register_read_word SLOT_CTRL failed\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: slot_cap %x\n", __FUNCTION__, slot_cap);
 
 	intr_enable = intr_enable | PRSN_DETECT_ENABLE;
 
@@ -1445,7 +1394,6 @@
 	} else {
 		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
 	}
-	dbg("%s: temp_word %x\n", __FUNCTION__, temp_word);
 
 	/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
 	rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
@@ -1453,14 +1401,11 @@
 		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word);
 	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__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, 
-		SLOT_STATUS(ctrl->cap_base), slot_status);
 	
 	temp_word =  0x1F; /* Clear all events */
 	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
@@ -1468,8 +1413,16 @@
 		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
-	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word);
 	
+	if (pciehp_force) {
+		dbg("Bypassing BIOS check for pciehp use on %s\n",
+				pci_name(ctrl->pci_dev));
+	} else {
+		rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
+		if (rc)
+			goto abort_free_ctlr;
+	}
+
 	/*  Add this HPC instance into the HPC list */
 	spin_lock(&list_lock);
 	if (php_ctlr_list_head == 0) {
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index ff17d8e..647673a 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -27,801 +27,111 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/proc_fs.h>
 #include <linux/pci.h>
 #include "../pci.h"
 #include "pciehp.h"
-#ifndef CONFIG_IA64
-#include "../../../arch/i386/pci/pci.h"    /* horrible hack showing how processor dependant we are... */
-#endif
 
 
-int pciehp_configure_device (struct controller* ctrl, struct pci_func* func)  
+int pciehp_configure_device(struct slot *p_slot)
 {
-	unsigned char bus;
-	struct pci_bus *child;
-	int num;
+	struct pci_dev *dev;
+	struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
+	int num, fn;
 
-	if (func->pci_dev == NULL)
-		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
+	dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0));
+	if (dev) {
+		err("Device %s already exists at %x:%x, cannot hot-add\n",
+				pci_name(dev), p_slot->bus, p_slot->device);
+		return -EINVAL;
+	}
 
-	/* Still NULL ? Well then scan for it ! */
-	if (func->pci_dev == NULL) {
-		dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__);
+	num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
+	if (num == 0) {
+		err("No new device found\n");
+		return -ENODEV;
+	}
 
-		num = pci_scan_slot(ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function));
-
-		if (num)
-			pci_bus_add_devices(ctrl->pci_dev->subordinate);
-		
-		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
-		if (func->pci_dev == NULL) {
-			dbg("ERROR: pci_dev still null\n");
-			return 0;
+	for (fn = 0; fn < 8; fn++) {
+		if (!(dev = pci_find_slot(p_slot->bus,
+					PCI_DEVFN(p_slot->device, fn))))
+			continue;
+		if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+			err("Cannot hot-add display device %s\n",
+					pci_name(dev));
+			continue;
 		}
+		if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
+				(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
+			/* Find an unused bus number for the new bridge */
+			struct pci_bus *child;
+			unsigned char busnr, start = parent->secondary;
+			unsigned char end = parent->subordinate;
+			for (busnr = start; busnr <= end; busnr++) {
+				if (!pci_find_bus(pci_domain_nr(parent),
+							busnr))
+					break;
+			}
+			if (busnr >= end) {
+				err("No free bus for hot-added bridge\n");
+				continue;
+			}
+			child = pci_add_new_bus(parent, dev, busnr);
+			if (!child) {
+				err("Cannot add new bus for %s\n",
+						pci_name(dev));
+				continue;
+			}
+			child->subordinate = pci_do_scan_bus(child);
+			pci_bus_size_bridges(child);
+		}
+		/* TBD: program firmware provided _HPP values */
+		/* program_fw_provided_values(dev); */
 	}
 
-	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
-		child = pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
-		pci_do_scan_bus(child);
-
-	}
-
+	pci_bus_assign_resources(parent);
+	pci_bus_add_devices(parent);
+	pci_enable_bridges(parent);
 	return 0;
 }
 
-
-int pciehp_unconfigure_device(struct pci_func* func) 
+int pciehp_unconfigure_device(struct slot *p_slot)
 {
 	int rc = 0;
 	int j;
-	struct pci_bus *pbus;
+	u8 bctl = 0;
 
-	dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus,
-				func->device, func->function);
-	pbus = func->pci_dev->bus;
+	dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
+				p_slot->device);
 
 	for (j=0; j<8 ; j++) {
-		struct pci_dev* temp = pci_find_slot(func->bus,
-				(func->device << 3) | j);
-		if (temp) {
-			pci_remove_bus_device(temp);
+		struct pci_dev* temp = pci_find_slot(p_slot->bus,
+				(p_slot->device << 3) | j);
+		if (!temp)
+			continue;
+		if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+			err("Cannot remove display device %s\n",
+					pci_name(temp));
+			continue;
 		}
+		if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+			pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
+			if (bctl & PCI_BRIDGE_CTL_VGA) {
+				err("Cannot remove display device %s\n",
+						pci_name(temp));
+				continue;
+			}
+		}
+		pci_remove_bus_device(temp);
 	}
 	/* 
 	 * Some PCI Express root ports require fixup after hot-plug operation.
 	 */
 	if (pcie_mch_quirk) 
-		pci_fixup_device(pci_fixup_final, pbus->self);
+		pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev);
 	
 	return rc;
 }
 
-/*
- * pciehp_set_irq
- *
- * @bus_num: bus number of PCI device
- * @dev_num: device number of PCI device
- * @slot: pointer to u8 where slot number will be returned
- */
-int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
-{
-#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_IO_APIC)
-	int rc;
-	u16 temp_word;
-	struct pci_dev fakedev;
-	struct pci_bus fakebus;
-
-	fakedev.devfn = dev_num << 3;
-	fakedev.bus = &fakebus;
-	fakebus.number = bus_num;
-	dbg("%s: dev %d, bus %d, pin %d, num %d\n",
-	    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
-	rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);
-	dbg("%s: rc %d\n", __FUNCTION__, rc);
-	if (!rc)
-		return !rc;
-
-	/* set the Edge Level Control Register (ELCR) */
-	temp_word = inb(0x4d0);
-	temp_word |= inb(0x4d1) << 8;
-
-	temp_word |= 0x01 << irq_num;
-
-	/* This should only be for x86 as it sets the Edge Level Control Register */
-	outb((u8) (temp_word & 0xFF), 0x4d0);
-	outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
-#endif
-	return 0;
-}
-
-/* More PCI configuration routines; this time centered around hotplug controller */
-
-
-/*
- * pciehp_save_config
- *
- * Reads configuration for all slots in a PCI bus and saves info.
- *
- * Note:  For non-hot plug busses, the slot # saved is the device #
- *
- * returns 0 if success
- */
-int pciehp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num)
-{
-	int rc;
-	u8 class_code;
-	u8 header_type;
-	u32 ID;
-	u8 secondary_bus;
-	struct pci_func *new_slot;
-	int sub_bus;
-	int max_functions;
-	int function;
-	u8 DevError;
-	int device = 0;
-	int cloop = 0;
-	int stop_it;
-	int index;
-	int is_hot_plug = num_ctlr_slots || first_device_num;
-	struct pci_bus lpci_bus, *pci_bus;
-	int FirstSupported, LastSupported;
-
-	dbg("%s: Enter\n", __FUNCTION__);
-
-	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
-	pci_bus = &lpci_bus;
-
-	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__,
-				num_ctlr_slots, first_device_num);
-
-	/*   Decide which slots are supported */
-	if (is_hot_plug) {
-		/*********************************
-		 *  is_hot_plug is the slot mask
-		 *********************************/
-		FirstSupported = first_device_num;
-		LastSupported = FirstSupported + num_ctlr_slots - 1;
-	} else {
-		FirstSupported = 0;
-		LastSupported = 0x1F;
-	}
-
-	dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported,
-					LastSupported);
-
-	/*   Save PCI configuration space for all devices in supported slots */
-	dbg("%s: pci_bus->number = %x\n", __FUNCTION__, pci_bus->number);
-	pci_bus->number = busnumber;
-	dbg("%s: bus = %x, dev = %x\n", __FUNCTION__, busnumber, device);
-	for (device = FirstSupported; device <= LastSupported; device++) {
-		ID = 0xFFFFFFFF;
-		rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0),
-					PCI_VENDOR_ID, &ID);
-
-		if (ID != 0xFFFFFFFF) {	  /*  device in slot */
-			dbg("%s: ID = %x\n", __FUNCTION__, ID);
-			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0),
-					0x0B, &class_code);
-			if (rc)
-				return rc;
-
-			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0),
-					PCI_HEADER_TYPE, &header_type);
-			if (rc)
-				return rc;
-
-			dbg("class_code = %x, header_type = %x\n", class_code, header_type);
-
-			/* If multi-function device, set max_functions to 8 */
-			if (header_type & 0x80)
-				max_functions = 8;
-			else
-				max_functions = 1;
-
-			function = 0;
-
-			do {
-				DevError = 0;
-				dbg("%s: In do loop\n", __FUNCTION__);
-
-				if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   /* P-P Bridge */
-					/* Recurse the subordinate bus
-					 * get the subordinate bus number
-					 */
-					rc = pci_bus_read_config_byte(pci_bus,
-						PCI_DEVFN(device, function), 
-						PCI_SECONDARY_BUS, &secondary_bus);
-					if (rc) {
-						return rc;
-					} else {
-						sub_bus = (int) secondary_bus;
-
-						/* Save secondary bus cfg spc with this recursive call. */
-						rc = pciehp_save_config(ctrl, sub_bus, 0, 0);
-						if (rc)
-							return rc;
-					}
-				}
-
-				index = 0;
-				new_slot = pciehp_slot_find(busnumber, device, index++);
-
-				dbg("%s: new_slot = %p bus %x dev %x fun %x\n",
-				__FUNCTION__, new_slot, busnumber, device, index-1);
-
-				while (new_slot && (new_slot->function != (u8) function)) {
-					new_slot = pciehp_slot_find(busnumber, device, index++);
-					dbg("%s: while loop, new_slot = %p bus %x dev %x fun %x\n",
-					__FUNCTION__, new_slot, busnumber, device, index-1);
-				}
-				if (!new_slot) {
-					/* Setup slot structure. */
-					new_slot = pciehp_slot_create(busnumber);
-					dbg("%s: if, new_slot = %p bus %x dev %x fun %x\n",
-					__FUNCTION__, new_slot, busnumber, device, function);
-
-					if (new_slot == NULL)
-						return(1);
-				}
-
-				new_slot->bus = (u8) busnumber;
-				new_slot->device = (u8) device;
-				new_slot->function = (u8) function;
-				new_slot->is_a_board = 1;
-				new_slot->switch_save = 0x10;
-				/* In case of unsupported board */
-				new_slot->status = DevError;
-				new_slot->pci_dev = pci_find_slot(new_slot->bus,
-					(new_slot->device << 3) | new_slot->function);
-				dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev);
-
-				for (cloop = 0; cloop < 0x20; cloop++) {
-					rc = pci_bus_read_config_dword(pci_bus,
-						PCI_DEVFN(device, function),
-						cloop << 2, 
-						(u32 *) &(new_slot->config_space [cloop]));
-					/* dbg("new_slot->config_space[%x] = %x\n",
-						cloop, new_slot->config_space[cloop]); */
-					if (rc)
-						return rc;
-				}
-
-				function++;
-
-				stop_it = 0;
-
-				/*  this loop skips to the next present function
-				 *  reading in Class Code and Header type.
-				 */
-
-				while ((function < max_functions)&&(!stop_it)) {
-					dbg("%s: In while loop \n", __FUNCTION__);
-					rc = pci_bus_read_config_dword(pci_bus,
-							PCI_DEVFN(device, function),
-							PCI_VENDOR_ID, &ID);
-
-					if (ID == 0xFFFFFFFF) {  /* nothing there. */
-						function++;
-						dbg("Nothing there\n");
-					} else {  /* Something there */
-						rc = pci_bus_read_config_byte(pci_bus,
-							PCI_DEVFN(device, function),
-							0x0B, &class_code);
-						if (rc)
-							return rc;
-
-						rc = pci_bus_read_config_byte(pci_bus,
-							PCI_DEVFN(device, function),
-							PCI_HEADER_TYPE, &header_type);
-						if (rc)
-							return rc;
-
-						dbg("class_code = %x, header_type = %x\n", class_code, header_type);
-						stop_it++;
-					}
-				}
-
-			} while (function < max_functions);
-			/* End of IF (device in slot?) */
-		} else if (is_hot_plug) {
-			/* Setup slot structure with entry for empty slot */
-			new_slot = pciehp_slot_create(busnumber);
-
-			if (new_slot == NULL) {
-				return(1);
-			}
-			dbg("new_slot = %p, bus = %x, dev = %x, fun = %x\n", new_slot,
-				new_slot->bus, new_slot->device, new_slot->function);
-
-			new_slot->bus = (u8) busnumber;
-			new_slot->device = (u8) device;
-			new_slot->function = 0;
-			new_slot->is_a_board = 0;
-			new_slot->presence_save = 0;
-			new_slot->switch_save = 0;
-		}
-	} 			/* End of FOR loop */
-
-	dbg("%s: Exit\n", __FUNCTION__);
-	return(0);
-}
-
-
-/*
- * pciehp_save_slot_config
- *
- * Saves configuration info for all PCI devices in a given slot
- * including subordinate busses.
- *
- * returns 0 if success
- */
-int pciehp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot)
-{
-	int rc;
-	u8 class_code;
-	u8 header_type;
-	u32 ID;
-	u8 secondary_bus;
-	int sub_bus;
-	int max_functions;
-	int function;
-	int cloop = 0;
-	int stop_it;
-	struct pci_bus lpci_bus, *pci_bus;
-	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
-	pci_bus = &lpci_bus;
-	pci_bus->number = new_slot->bus;
-
-	ID = 0xFFFFFFFF;
-
-	pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0),
-					PCI_VENDOR_ID, &ID);
-
-	if (ID != 0xFFFFFFFF) {	  /*  device in slot */
-		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0),
-					0x0B, &class_code);
-
-		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0),
-					PCI_HEADER_TYPE, &header_type);
-
-		if (header_type & 0x80)	/* Multi-function device */
-			max_functions = 8;
-		else
-			max_functions = 1;
-
-		function = 0;
-
-		do {
-			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  /* PCI-PCI Bridge */
-				/*  Recurse the subordinate bus */
-				pci_bus_read_config_byte(pci_bus,
-					PCI_DEVFN(new_slot->device, function), 
-					PCI_SECONDARY_BUS, &secondary_bus);
-
-				sub_bus = (int) secondary_bus;
-
-				/* Save the config headers for the secondary bus. */
-				rc = pciehp_save_config(ctrl, sub_bus, 0, 0);
-
-				if (rc)
-					return rc;
-
-			}	/* End of IF */
-
-			new_slot->status = 0;
-
-			for (cloop = 0; cloop < 0x20; cloop++) {
-				pci_bus_read_config_dword(pci_bus,
-					PCI_DEVFN(new_slot->device, function), 
-					cloop << 2,
-					(u32 *) &(new_slot->config_space [cloop]));
-			}
-
-			function++;
-
-			stop_it = 0;
-
-			/*  this loop skips to the next present function
-			 *  reading in the Class Code and the Header type.
-			 */
-
-			while ((function < max_functions) && (!stop_it)) {
-				pci_bus_read_config_dword(pci_bus,
-					PCI_DEVFN(new_slot->device, function),
-					PCI_VENDOR_ID, &ID);
-
-				if (ID == 0xFFFFFFFF) {	 /* nothing there. */
-					function++;
-				} else {  /* Something there */
-					pci_bus_read_config_byte(pci_bus,
-						PCI_DEVFN(new_slot->device, function),
-						0x0B, &class_code);
-
-					pci_bus_read_config_byte(pci_bus,
-						PCI_DEVFN(new_slot->device, function),
-						PCI_HEADER_TYPE, &header_type);
-
-					stop_it++;
-				}
-			}
-
-		} while (function < max_functions);
-	}			/* End of IF (device in slot?) */
-	else {
-		return 2;
-	}
-
-	return 0;
-}
-
-
-/*
- * pciehp_save_used_resources
- *
- * Stores used resource information for existing boards.  this is
- * for boards that were in the system when this driver was loaded.
- * this function is for hot plug ADD
- *
- * returns 0 if success
- * if disable  == 1(DISABLE_CARD),
- *  it loops for all functions of the slot and disables them.
- * else, it just get resources of the function and return.
- */
-int pciehp_save_used_resources(struct controller *ctrl, struct pci_func *func, int disable)
-{
-	u8 cloop;
-	u8 header_type;
-	u8 secondary_bus;
-	u8 temp_byte;
-	u16 command;
-	u16 save_command;
-	u16 w_base, w_length;
-	u32 temp_register;
-	u32 save_base;
-	u32 base, length;
-	u64 base64 = 0;
-	int index = 0;
-	unsigned int devfn;
-	struct pci_resource *mem_node = NULL;
-	struct pci_resource *p_mem_node = NULL;
-	struct pci_resource *t_mem_node;
-	struct pci_resource *io_node;
-	struct pci_resource *bus_node;
-	struct pci_bus lpci_bus, *pci_bus;
-	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
-	pci_bus = &lpci_bus;
-
-	if (disable)
-		func = pciehp_slot_find(func->bus, func->device, index++);
-
-	while ((func != NULL) && func->is_a_board) {
-		pci_bus->number = func->bus;
-		devfn = PCI_DEVFN(func->device, func->function);
-
-		/* Save the command register */
-		pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command);
-
-		if (disable) {
-			/* disable card */
-			command = 0x00;
-			pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
-		}
-
-		/* Check for Bridge */
-		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
-
-		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {     /* PCI-PCI Bridge */
-			dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n",
-					func->bus, func->device, save_command);
-			if (disable) {
-				/* Clear Bridge Control Register */
-				command = 0x00;
-				pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
-			}
-
-			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
-			pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
-
-			bus_node = kmalloc(sizeof(struct pci_resource),
-						GFP_KERNEL);
-			if (!bus_node)
-				return -ENOMEM;
-
-			bus_node->base = (ulong)secondary_bus;
-			bus_node->length = (ulong)(temp_byte - secondary_bus + 1);
-
-			bus_node->next = func->bus_head;
-			func->bus_head = bus_node;
-
-			/* Save IO base and Limit registers */
-			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &temp_byte);
-			base = temp_byte;
-			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &temp_byte);
-			length = temp_byte;
-
-			if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) {
-				io_node = kmalloc(sizeof(struct pci_resource),
-							GFP_KERNEL);
-				if (!io_node)
-					return -ENOMEM;
-
-				io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8;
-				io_node->length = (ulong)(length - base + 0x10) << 8;
-
-				io_node->next = func->io_head;
-				func->io_head = io_node;
-			}
-
-			/* Save memory base and Limit registers */
-			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
-			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
-
-			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
-				mem_node = kmalloc(sizeof(struct pci_resource),
-						GFP_KERNEL);
-				if (!mem_node)
-					return -ENOMEM;
-
-				mem_node->base = (ulong)w_base << 16;
-				mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
-
-				mem_node->next = func->mem_head;
-				func->mem_head = mem_node;
-			}
-			/* Save prefetchable memory base and Limit registers */
-			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
-			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
-
-			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
-				p_mem_node = kmalloc(sizeof(struct pci_resource),
-						GFP_KERNEL);
-				if (!p_mem_node)
-					return -ENOMEM;
-
-				p_mem_node->base = (ulong)w_base << 16;
-				p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
-
-				p_mem_node->next = func->p_mem_head;
-				func->p_mem_head = p_mem_node;
-			}
-		} else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
-			dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n",
-					func->bus, func->device, save_command);
-
-			/* Figure out IO and memory base lengths */
-			for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
-				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
-
-				temp_register = 0xFFFFFFFF;
-				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
-				pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register);
-
-				if (!disable)
-					pci_bus_write_config_dword(pci_bus, devfn, cloop, save_base);
-
-				if (!temp_register)
-					continue;
-
-				base = temp_register;
-
-				if ((base & PCI_BASE_ADDRESS_SPACE_IO) &&
-						(!disable || (save_command & PCI_COMMAND_IO))) {
-					/* IO base */
-					/* set temp_register = amount of IO space requested */
-					base = base & 0xFFFFFFFCL;
-					base = (~base) + 1;
-
-					io_node = kmalloc(sizeof (struct pci_resource),
-								GFP_KERNEL);
-					if (!io_node)
-						return -ENOMEM;
-
-					io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK;
-					io_node->length = (ulong)base;
-					dbg("sur adapter: IO bar=0x%x(length=0x%x)\n",
-						io_node->base, io_node->length);
-
-					io_node->next = func->io_head;
-					func->io_head = io_node;
-				} else {  /* map Memory */
-					int prefetchable = 1;
-					/* struct pci_resources **res_node; */
-					char *res_type_str = "PMEM";
-					u32 temp_register2;
-
-					t_mem_node = kmalloc(sizeof (struct pci_resource),
-								GFP_KERNEL);
-					if (!t_mem_node)
-						return -ENOMEM;
-
-					if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) &&
-							(!disable || (save_command & PCI_COMMAND_MEMORY))) {
-						prefetchable = 0;
-						mem_node = t_mem_node;
-						res_type_str++;
-					} else
-						p_mem_node = t_mem_node;
-
-					base = base & 0xFFFFFFF0L;
-					base = (~base) + 1;
-
-					switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
-					case PCI_BASE_ADDRESS_MEM_TYPE_32:
-						if (prefetchable) {
-							p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
-							p_mem_node->length = (ulong)base;
-							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
-								res_type_str, 
-								p_mem_node->base,
-								p_mem_node->length);
-
-							p_mem_node->next = func->p_mem_head;
-							func->p_mem_head = p_mem_node;
-						} else {
-							mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
-							mem_node->length = (ulong)base;
-							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
-								res_type_str, 
-								mem_node->base,
-								mem_node->length);
-
-							mem_node->next = func->mem_head;
-							func->mem_head = mem_node;
-						}
-						break;
-					case PCI_BASE_ADDRESS_MEM_TYPE_64:
-						pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
-						base64 = temp_register2;
-						base64 = (base64 << 32) | save_base;
-
-						if (temp_register2) {
-							dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", 
-								res_type_str, temp_register2, (u32)base64);
-							base64 &= 0x00000000FFFFFFFFL;
-						}
-
-						if (prefetchable) {
-							p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
-							p_mem_node->length = base;
-							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
-								res_type_str, 
-								p_mem_node->base,
-								p_mem_node->length);
-
-							p_mem_node->next = func->p_mem_head;
-							func->p_mem_head = p_mem_node;
-						} else {
-							mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
-							mem_node->length = base;
-							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
-								res_type_str, 
-								mem_node->base,
-								mem_node->length);
-
-							mem_node->next = func->mem_head;
-							func->mem_head = mem_node;
-						}
-						cloop += 4;
-						break;
-					default:
-						dbg("asur: reserved BAR type=0x%x\n",
-							temp_register);
-						break;
-					}
-				} 
-			}	/* End of base register loop */
-		} else {	/* Some other unknown header type */
-			dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n",
-					func->bus, func->device);
-		}
-
-		/* find the next device in this slot */
-		if (!disable)
-			break;
-		func = pciehp_slot_find(func->bus, func->device, index++);
-	}
-
-	return 0;
-}
-
-
-/**
- * kfree_resource_list: release memory of all list members
- * @res: resource list to free
- */
-static inline void
-return_resource_list(struct pci_resource **func, struct pci_resource **res)
-{
-	struct pci_resource *node;
-	struct pci_resource *t_node;
-
-	node = *func;
-	*func = NULL;
-	while (node) {
-		t_node = node->next;
-		return_resource(res, node);
-		node = t_node;
-	}
-}
-
-/*
- * pciehp_return_board_resources
- *
- * this routine returns all resources allocated to a board to
- * the available pool.
- *
- * returns 0 if success
- */
-int pciehp_return_board_resources(struct pci_func * func,
-				struct resource_lists * resources)
-{
-	int rc;
-
-	dbg("%s\n", __FUNCTION__);
-
-	if (!func)
-		return 1;
-
-	return_resource_list(&(func->io_head),&(resources->io_head));
-	return_resource_list(&(func->mem_head),&(resources->mem_head));
-	return_resource_list(&(func->p_mem_head),&(resources->p_mem_head));
-	return_resource_list(&(func->bus_head),&(resources->bus_head));
-
-	rc = pciehp_resource_sort_and_combine(&(resources->mem_head));
-	rc |= pciehp_resource_sort_and_combine(&(resources->p_mem_head));
-	rc |= pciehp_resource_sort_and_combine(&(resources->io_head));
-	rc |= pciehp_resource_sort_and_combine(&(resources->bus_head));
-
-	return rc;
-}
-
-/**
- * kfree_resource_list: release memory of all list members
- * @res: resource list to free
- */
-static inline void
-kfree_resource_list(struct pci_resource **r)
-{
-	struct pci_resource *res, *tres;
-
-	res = *r;
-	*r = NULL;
-
-	while (res) {
-		tres = res;
-		res = res->next;
-		kfree(tres);
-	}
-}
-
-/**
- * pciehp_destroy_resource_list: put node back in the resource list
- * @resources: list to put nodes back
- */
-void pciehp_destroy_resource_list(struct resource_lists * resources)
-{
-	kfree_resource_list(&(resources->io_head));
-	kfree_resource_list(&(resources->mem_head));
-	kfree_resource_list(&(resources->p_mem_head));
-	kfree_resource_list(&(resources->bus_head));
-}
-
-/**
- * pciehp_destroy_board_resources: put node back in the resource list
- * @resources: list to put nodes back
- */
-void pciehp_destroy_board_resources(struct pci_func * func)
-{
-	kfree_resource_list(&(func->io_head));
-	kfree_resource_list(&(func->mem_head));
-	kfree_resource_list(&(func->p_mem_head));
-	kfree_resource_list(&(func->bus_head));
-}
diff --git a/drivers/pci/hotplug/pciehprm.h b/drivers/pci/hotplug/pciehprm.h
deleted file mode 100644
index 05f20fb..0000000
--- a/drivers/pci/hotplug/pciehprm.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * PCIEHPRM : PCIEHP Resource Manager for ACPI/non-ACPI platform
- *
- * Copyright (C) 1995,2001 Compaq Computer Corporation
- * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2001 IBM Corp.
- * Copyright (C) 2003-2004 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, GOOD TITLE or
- * NON INFRINGEMENT.  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.
- *
- * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
- *
- */
-
-#ifndef _PCIEHPRM_H_
-#define _PCIEHPRM_H_
-
-#ifdef	CONFIG_HOTPLUG_PCI_PCIE_PHPRM_NONACPI
-#include "pciehprm_nonacpi.h"
-#endif
-
-int pciehprm_init(enum php_ctlr_type ct);
-void pciehprm_cleanup(void);
-int pciehprm_print_pirt(void);
-int pciehprm_find_available_resources(struct controller *ctrl);
-int pciehprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type);
-void pciehprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type);
-
-#ifdef	DEBUG
-#define RES_CHECK(this, bits)	\
-	{ if (((this) & (bits - 1))) \
-		printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); }
-#else
-#define RES_CHECK(this, bits)
-#endif
-
-#endif				/* _PCIEHPRM_H_ */
diff --git a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c
index 1406db3..ae244e2 100644
--- a/drivers/pci/hotplug/pciehprm_acpi.c
+++ b/drivers/pci/hotplug/pciehprm_acpi.c
@@ -24,100 +24,20 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/acpi.h>
-#include <linux/efi.h>
 #include <linux/pci-acpi.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#ifdef	CONFIG_IA64
-#include <asm/iosapic.h>
-#endif
-#include <acpi/acpi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/actypes.h>
 #include "pciehp.h"
-#include "pciehprm.h"
-
-#define	PCI_MAX_BUS		0x100
-#define	ACPI_STA_DEVICE_PRESENT	0x01
 
 #define	METHOD_NAME__SUN	"_SUN"
 #define	METHOD_NAME__HPP	"_HPP"
 #define	METHOD_NAME_OSHP	"OSHP"
 
-/* Status code for running acpi method to gain native control */
-#define NC_NOT_RUN	0
-#define OSC_NOT_EXIST	1
-#define OSC_RUN_FAILED	2
-#define OSHP_NOT_EXIST	3
-#define OSHP_RUN_FAILED	4
-#define NC_RUN_SUCCESS	5
-
-#define	PHP_RES_BUS		0xA0
-#define	PHP_RES_IO		0xA1
-#define	PHP_RES_MEM		0xA2
-#define	PHP_RES_PMEM		0xA3
-
-#define	BRIDGE_TYPE_P2P		0x00
-#define	BRIDGE_TYPE_HOST	0x01
-
-/* this should go to drivers/acpi/include/ */
-struct acpi__hpp {
-	u8	cache_line_size;
-	u8	latency_timer;
-	u8	enable_serr;
-	u8	enable_perr;
-};
-
-struct acpi_php_slot {
-	struct acpi_php_slot	*next;
-	struct acpi_bridge	*bridge;
-	acpi_handle	handle;
-	int	seg;
-	int	bus;
-	int	dev;
-	int	fun;
-	u32	sun;
-	struct pci_resource *mem_head;
-	struct pci_resource *p_mem_head;
-	struct pci_resource *io_head;
-	struct pci_resource *bus_head;
-	void	*slot_ops;	/* _STA, _EJx, etc */
-	struct slot *slot;
-};		/* per func */
-
-struct acpi_bridge {
-	struct acpi_bridge	*parent;
-	struct acpi_bridge	*next;
-	struct acpi_bridge	*child;
-	acpi_handle	handle;
-	int seg;
-	int pbus;			/* pdev->bus->number		*/
-	int pdevice;			/* PCI_SLOT(pdev->devfn)	*/
-	int pfunction;			/* PCI_DEVFN(pdev->devfn)	*/
-	int bus;			/* pdev->subordinate->number	*/
-	struct acpi__hpp		*_hpp;
-	struct acpi_php_slot	*slots;
-	struct pci_resource 	*tmem_head;	/* total from crs	*/
-	struct pci_resource 	*tp_mem_head;	/* total from crs	*/
-	struct pci_resource 	*tio_head;	/* total from crs	*/
-	struct pci_resource 	*tbus_head;	/* total from crs	*/
-	struct pci_resource 	*mem_head;	/* available	*/
-	struct pci_resource 	*p_mem_head;	/* available	*/
-	struct pci_resource 	*io_head;	/* available	*/
-	struct pci_resource 	*bus_head;	/* available	*/
-	int scanned;
-	int type;
-};
-
-static struct acpi_bridge *acpi_bridges_head;
-
 static u8 * acpi_path_name( acpi_handle	handle)
 {
 	acpi_status		status;
@@ -133,85 +53,43 @@
 		return path_name;	
 }
 
-static void acpi_get__hpp ( struct acpi_bridge	*ab);
-static int acpi_run_oshp ( struct acpi_bridge	*ab);
-static int osc_run_status = NC_NOT_RUN;
-static int oshp_run_status = NC_NOT_RUN;
-
-static int acpi_add_slot_to_php_slots(
-	struct acpi_bridge	*ab,
-	int			bus_num,
-	acpi_handle		handle,
-	u32			adr,
-	u32			sun
-	)
-{
-	struct acpi_php_slot	*aps;
-	static long	samesun = -1;
-
-	aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);
-	if (!aps) {
-		err ("acpi_pciehprm: alloc for aps fail\n");
-		return -1;
-	}
-	memset(aps, 0, sizeof(struct acpi_php_slot));
-
-	aps->handle = handle;
-	aps->bus = bus_num;
-	aps->dev = (adr >> 16) & 0xffff;
-	aps->fun = adr & 0xffff;
-	aps->sun = sun;
-
-	aps->next = ab->slots;	/* cling to the bridge */
-	aps->bridge = ab;
-	ab->slots = aps;
-
-	ab->scanned += 1;
-	if (!ab->_hpp)
-		acpi_get__hpp(ab);
-	
-	if (osc_run_status == OSC_NOT_EXIST)
-		oshp_run_status = acpi_run_oshp(ab);
-
-	if (sun != samesun) {
-		info("acpi_pciehprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", 
-			aps->sun, ab->seg, aps->bus, aps->dev, aps->fun);
-		samesun = sun;
-	}
-	return 0;
-}
-
-static void acpi_get__hpp ( struct acpi_bridge	*ab)
+static acpi_status
+acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
 {
 	acpi_status		status;
 	u8			nui[4];
 	struct acpi_buffer	ret_buf = { 0, NULL};
 	union acpi_object	*ext_obj, *package;
-	u8			*path_name = acpi_path_name(ab->handle);
+	u8			*path_name = acpi_path_name(handle);
 	int			i, len = 0;
 
 	/* get _hpp */
-	status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+	status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf);
 	switch (status) {
 	case AE_BUFFER_OVERFLOW:
 		ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
 		if (!ret_buf.pointer) {
-			err ("acpi_pciehprm:%s alloc for _HPP fail\n", path_name);
-			return;
+			err ("%s:%s alloc for _HPP fail\n", __FUNCTION__,
+					path_name);
+			return AE_NO_MEMORY;
 		}
-		status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+		status = acpi_evaluate_object(handle, METHOD_NAME__HPP,
+				NULL, &ret_buf);
 		if (ACPI_SUCCESS(status))
 			break;
 	default:
 		if (ACPI_FAILURE(status)) {
-			err("acpi_pciehprm:%s _HPP fail=0x%x\n", path_name, status);
-			return;
+			dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__,
+					path_name, status);
+			return status;
 		}
 	}
 
 	ext_obj = (union acpi_object *) ret_buf.pointer;
 	if (ext_obj->type != ACPI_TYPE_PACKAGE) {
-		err ("acpi_pciehprm:%s _HPP obj not a package\n", path_name);
+		err ("%s:%s _HPP obj not a package\n", __FUNCTION__,
+				path_name);
+		status = AE_ERROR;
 		goto free_and_return;
 	}
 
@@ -224,1514 +102,153 @@
 			nui[i] = (u8)ext_obj->integer.value;
 			break;
 		default:
-			err ("acpi_pciehprm:%s _HPP obj type incorrect\n", path_name);
+			err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__,
+					path_name);
+			status = AE_ERROR;
 			goto free_and_return;
 		}
 	}
 
-	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
-	if (!ab->_hpp) {
-		err ("acpi_pciehprm:%s alloc for _HPP failed\n", path_name);
-		goto free_and_return;
-	}
-	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
+	hpp->cache_line_size = nui[0];
+	hpp->latency_timer = nui[1];
+	hpp->enable_serr = nui[2];
+	hpp->enable_perr = nui[3];
 
-	ab->_hpp->cache_line_size	= nui[0];
-	ab->_hpp->latency_timer		= nui[1];
-	ab->_hpp->enable_serr		= nui[2];
-	ab->_hpp->enable_perr		= nui[3];
-
-	dbg("  _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
-	dbg("  _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
-	dbg("  _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
-	dbg("  _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+	dbg("  _HPP: cache_line_size=0x%x\n", hpp->cache_line_size);
+	dbg("  _HPP: latency timer  =0x%x\n", hpp->latency_timer);
+	dbg("  _HPP: enable SERR    =0x%x\n", hpp->enable_serr);
+	dbg("  _HPP: enable PERR    =0x%x\n", hpp->enable_perr);
 
 free_and_return:
 	kfree(ret_buf.pointer);
+	return status;
 }
 
-static int acpi_run_oshp ( struct acpi_bridge	*ab)
+static acpi_status acpi_run_oshp(acpi_handle handle)
 {
 	acpi_status		status;
-	u8			*path_name = acpi_path_name(ab->handle);
+	u8			*path_name = acpi_path_name(handle);
 
 	/* run OSHP */
-	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL);
+	status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL);
 	if (ACPI_FAILURE(status)) {
-		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
-		oshp_run_status = (status == AE_NOT_FOUND) ? OSHP_NOT_EXIST : OSHP_RUN_FAILED;
+		dbg("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name,
+				status);
 	} else {
-		oshp_run_status = NC_RUN_SUCCESS;
-		dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);
-		dbg("acpi_pciehprm:%s oshp_run_status =0x%x\n", path_name, oshp_run_status);
+		dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name);
 	}
-	return oshp_run_status;
-}
-
-static acpi_status acpi_evaluate_crs(
-	acpi_handle		handle,
-	struct acpi_resource	**retbuf
-	)
-{
-	acpi_status		status;
-	struct acpi_buffer	crsbuf;
-	u8			*path_name = acpi_path_name(handle);
-
-	crsbuf.length  = 0;
-	crsbuf.pointer = NULL;
-
-	status = acpi_get_current_resources (handle, &crsbuf);
-
-	switch (status) {
-	case AE_BUFFER_OVERFLOW:
-		break;		/* found */
-	case AE_NOT_FOUND:
-		dbg("acpi_pciehprm:%s _CRS not found\n", path_name);
-		return status;
-	default:
-		err ("acpi_pciehprm:%s _CRS fail=0x%x\n", path_name, status);
-		return status;
-	}
-
-	crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL);
-	if (!crsbuf.pointer) {
-		err ("acpi_pciehprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name);
-		return AE_NO_MEMORY;
-	}
-
-	status = acpi_get_current_resources (handle, &crsbuf);
-	if (ACPI_FAILURE(status)) {
-		err("acpi_pciehprm: %s _CRS fail=0x%x.\n", path_name, status);
-		kfree(crsbuf.pointer);
-		return status;
-	}
-
-	*retbuf = crsbuf.pointer;
-
 	return status;
 }
 
-static void free_pci_resource ( struct pci_resource	*aprh)
+static int is_root_bridge(acpi_handle handle)
 {
-	struct pci_resource	*res, *next;
+	acpi_status status;
+	struct acpi_device_info *info;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	int i;
 
-	for (res = aprh; res; res = next) {
-		next = res->next;
-		kfree(res);
-	}
-}
-
-static void print_pci_resource ( struct pci_resource	*aprh)
-{
-	struct pci_resource	*res;
-
-	for (res = aprh; res; res = res->next)
-		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
-}
-
-static void print_slot_resources( struct acpi_php_slot	*aps)
-{
-	if (aps->bus_head) {
-		dbg("    BUS Resources:\n");
-		print_pci_resource (aps->bus_head);
-	}
-
-	if (aps->io_head) {
-		dbg("    IO Resources:\n");
-		print_pci_resource (aps->io_head);
-	}
-
-	if (aps->mem_head) {
-		dbg("    MEM Resources:\n");
-		print_pci_resource (aps->mem_head);
-	}
-
-	if (aps->p_mem_head) {
-		dbg("    PMEM Resources:\n");
-		print_pci_resource (aps->p_mem_head);
-	}
-}
-
-static void print_pci_resources( struct acpi_bridge	*ab)
-{
-	if (ab->tbus_head) {
-		dbg("    Total BUS Resources:\n");
-		print_pci_resource (ab->tbus_head);
-	}
-	if (ab->bus_head) {
-		dbg("    BUS Resources:\n");
-		print_pci_resource (ab->bus_head);
-	}
-
-	if (ab->tio_head) {
-		dbg("    Total IO Resources:\n");
-		print_pci_resource (ab->tio_head);
-	}
-	if (ab->io_head) {
-		dbg("    IO Resources:\n");
-		print_pci_resource (ab->io_head);
-	}
-
-	if (ab->tmem_head) {
-		dbg("    Total MEM Resources:\n");
-		print_pci_resource (ab->tmem_head);
-	}
-	if (ab->mem_head) {
-		dbg("    MEM Resources:\n");
-		print_pci_resource (ab->mem_head);
-	}
-
-	if (ab->tp_mem_head) {
-		dbg("    Total PMEM Resources:\n");
-		print_pci_resource (ab->tp_mem_head);
-	}
-	if (ab->p_mem_head) {
-		dbg("    PMEM Resources:\n");
-		print_pci_resource (ab->p_mem_head);
-	}
-	if (ab->_hpp) {
-		dbg("    _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
-		dbg("    _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
-		dbg("    _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
-		dbg("    _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
-	}
-}
-
-static int pciehprm_delete_resource(
-	struct pci_resource **aprh,
-	ulong base,
-	ulong size)
-{
-	struct pci_resource *res;
-	struct pci_resource *prevnode;
-	struct pci_resource *split_node;
-	ulong tbase;
-
-	pciehp_resource_sort_and_combine(aprh);
-
-	for (res = *aprh; res; res = res->next) {
-		if (res->base > base)
-			continue;
-
-		if ((res->base + res->length) < (base + size))
-			continue;
-
-		if (res->base < base) {
-			tbase = base;
-
-			if ((res->length - (tbase - res->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-			if (!split_node)
-				return -ENOMEM;
-
-			split_node->base = res->base;
-			split_node->length = tbase - res->base;
-			res->base = tbase;
-			res->length -= split_node->length;
-
-			split_node->next = res->next;
-			res->next = split_node;
-		}
-
-		if (res->length >= size) {
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-			if (!split_node)
-				return -ENOMEM;
-
-			split_node->base = res->base + size;
-			split_node->length = res->length - size;
-			res->length = size;
-
-			split_node->next = res->next;
-			res->next = split_node;
-		}
-
-		if (*aprh == res) {
-			*aprh = res->next;
-		} else {
-			prevnode = *aprh;
-			while (prevnode->next != res)
-				prevnode = prevnode->next;
-
-			prevnode->next = res->next;
-		}
-		res->next = NULL;
-		kfree(res);
-		break;
-	}
-
-	return 0;
-}
-
-static int pciehprm_delete_resources(
-	struct pci_resource **aprh,
-	struct pci_resource *this
-	)
-{
-	struct pci_resource *res;
-
-	for (res = this; res; res = res->next)
-		pciehprm_delete_resource(aprh, res->base, res->length);
-
-	return 0;
-}
-
-static int pciehprm_add_resource(
-	struct pci_resource **aprh,
-	ulong base,
-	ulong size)
-{
-	struct pci_resource *res;
-
-	for (res = *aprh; res; res = res->next) {
-		if ((res->base + res->length) == base) {
-			res->length += size;
-			size = 0L;
-			break;
-		}
-		if (res->next == *aprh)
-			break;
-	}
-
-	if (size) {
-		res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-		if (!res) {
-			err ("acpi_pciehprm: alloc for res fail\n");
-			return -ENOMEM;
-		}
-		memset(res, 0, sizeof (struct pci_resource));
-
-		res->base = base;
-		res->length = size;
-		res->next = *aprh;
-		*aprh = res;
-	}
-
-	return 0;
-}
-
-static int pciehprm_add_resources(
-	struct pci_resource **aprh,
-	struct pci_resource *this
-	)
-{
-	struct pci_resource *res;
-	int	rc = 0;
-
-	for (res = this; res && !rc; res = res->next)
-		rc = pciehprm_add_resource(aprh, res->base, res->length);
-
-	return rc;
-}
-
-static void acpi_parse_io (
-	struct acpi_bridge		*ab,
-	union acpi_resource_data	*data
-	)
-{
-	struct acpi_resource_io	*dataio;
-	dataio = (struct acpi_resource_io *) data;
-
-	dbg("Io Resource\n");
-	dbg("  %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10);
-	dbg("  Range minimum base: %08X\n", dataio->min_base_address);
-	dbg("  Range maximum base: %08X\n", dataio->max_base_address);
-	dbg("  Alignment: %08X\n", dataio->alignment);
-	dbg("  Range Length: %08X\n", dataio->range_length);
-}
-
-static void acpi_parse_fixed_io (
-	struct acpi_bridge	*ab,
-	union acpi_resource_data	*data
-	)
-{
-	struct acpi_resource_fixed_io  *datafio;
-	datafio = (struct acpi_resource_fixed_io *) data;
-
-	dbg("Fixed Io Resource\n");
-	dbg("  Range base address: %08X", datafio->base_address);
-	dbg("  Range length: %08X", datafio->range_length);
-}
-
-static void acpi_parse_address16_32 (
-	struct acpi_bridge	*ab,
-	union acpi_resource_data	*data,
-	acpi_resource_type	id
-	)
-{
-	/* 
-	 * acpi_resource_address16 == acpi_resource_address32
-	 * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data;
-	 */
-	struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data;
-	struct pci_resource **aprh, **tprh;
-
-	if (id == ACPI_RSTYPE_ADDRESS16)
-		dbg("acpi_pciehprm:16-Bit Address Space Resource\n");
-	else
-		dbg("acpi_pciehprm:32-Bit Address Space Resource\n");
-
-	switch (data32->resource_type) {
-	case ACPI_MEMORY_RANGE: 
-		dbg("  Resource Type: Memory Range\n");
-		aprh = &ab->mem_head;
-		tprh = &ab->tmem_head;
-
-		switch (data32->attribute.memory.cache_attribute) {
-		case ACPI_NON_CACHEABLE_MEMORY:
-			dbg("  Type Specific: Noncacheable memory\n");
-			break; 
-		case ACPI_CACHABLE_MEMORY:
-			dbg("  Type Specific: Cacheable memory\n");
-			break; 
-		case ACPI_WRITE_COMBINING_MEMORY:
-			dbg("  Type Specific: Write-combining memory\n");
-			break; 
-		case ACPI_PREFETCHABLE_MEMORY:
-			aprh = &ab->p_mem_head;
-			dbg("  Type Specific: Prefetchable memory\n");
-			break; 
-		default:
-			dbg("  Type Specific: Invalid cache attribute\n");
-			break;
-		}
-
-		dbg("  Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only");
-		break;
-
-	case ACPI_IO_RANGE: 
-		dbg("  Resource Type: I/O Range\n");
-		aprh = &ab->io_head;
-		tprh = &ab->tio_head;
-
-		switch (data32->attribute.io.range_attribute) {
-		case ACPI_NON_ISA_ONLY_RANGES:
-			dbg("  Type Specific: Non-ISA Io Addresses\n");
-			break; 
-		case ACPI_ISA_ONLY_RANGES:
-			dbg("  Type Specific: ISA Io Addresses\n");
-			break; 
-		case ACPI_ENTIRE_RANGE:
-			dbg("  Type Specific: ISA and non-ISA Io Addresses\n");
-			break; 
-		default:
-			dbg("  Type Specific: Invalid range attribute\n");
-			break;
-		}
-		break;
-
-	case ACPI_BUS_NUMBER_RANGE: 
-		dbg("  Resource Type: Bus Number Range(fixed)\n");
-		/* fixup to be compatible with the rest of php driver */
-		data32->min_address_range++;
-		data32->address_length--;
-		aprh = &ab->bus_head;
-		tprh = &ab->tbus_head;
-		break; 
-	default: 
-		dbg("  Resource Type: Invalid resource type. Exiting.\n");
-		return;
-	}
-
-	dbg("  Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer");
-	dbg("  %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive");
-	dbg("  Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not");
-	dbg("  Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not");
-	dbg("  Granularity: %08X\n", data32->granularity);
-	dbg("  Address range min: %08X\n", data32->min_address_range);
-	dbg("  Address range max: %08X\n", data32->max_address_range);
-	dbg("  Address translation offset: %08X\n", data32->address_translation_offset);
-	dbg("  Address Length: %08X\n", data32->address_length);
-
-	if (0xFF != data32->resource_source.index) {
-		dbg("  Resource Source Index: %X\n", data32->resource_source.index);
-		/* dbg("  Resource Source: %s\n", data32->resource_source.string_ptr); */
-	}
-
-	pciehprm_add_resource(aprh, data32->min_address_range, data32->address_length);
-}
-
-static acpi_status acpi_parse_crs(
-	struct acpi_bridge	*ab,
-	struct acpi_resource	*crsbuf
-	)
-{
-	acpi_status		status = AE_OK;
-	struct acpi_resource	*resource = crsbuf;
-	u8				count = 0;
-	u8				done = 0;
-
-	while (!done) {
-		dbg("acpi_pciehprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++);
-		switch (resource->id) {
-		case ACPI_RSTYPE_IRQ:
-			dbg("Irq -------- Resource\n");
-			break; 
-		case ACPI_RSTYPE_DMA:
-			dbg("DMA -------- Resource\n");
-			break; 
-		case ACPI_RSTYPE_START_DPF:
-			dbg("Start DPF -------- Resource\n");
-			break; 
-		case ACPI_RSTYPE_END_DPF:
-			dbg("End DPF -------- Resource\n");
-			break; 
-		case ACPI_RSTYPE_IO:
-			acpi_parse_io (ab, &resource->data);
-			break; 
-		case ACPI_RSTYPE_FIXED_IO:
-			acpi_parse_fixed_io (ab, &resource->data);
-			break; 
-		case ACPI_RSTYPE_VENDOR:
-			dbg("Vendor -------- Resource\n");
-			break; 
-		case ACPI_RSTYPE_END_TAG:
-			dbg("End_tag -------- Resource\n");
-			done = 1;
-			break; 
-		case ACPI_RSTYPE_MEM24:
-			dbg("Mem24 -------- Resource\n");
-			break; 
-		case ACPI_RSTYPE_MEM32:
-			dbg("Mem32 -------- Resource\n");
-			break; 
-		case ACPI_RSTYPE_FIXED_MEM32:
-			dbg("Fixed Mem32 -------- Resource\n");
-			break; 
-		case ACPI_RSTYPE_ADDRESS16:
-			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16);
-			break; 
-		case ACPI_RSTYPE_ADDRESS32:
-			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32);
-			break; 
-		case ACPI_RSTYPE_ADDRESS64:
-			info("Address64 -------- Resource unparsed\n");
-			break; 
-		case ACPI_RSTYPE_EXT_IRQ:
-			dbg("Ext Irq -------- Resource\n");
-			break; 
-		default:
-			dbg("Invalid -------- resource type 0x%x\n", resource->id);
-			break;
-		}
-
-		resource = (struct acpi_resource *) ((char *)resource + resource->length);
-	}
-
-	return status;
-}
-
-static acpi_status acpi_get_crs( struct acpi_bridge	*ab)
-{
-	acpi_status		status;
-	struct acpi_resource	*crsbuf;
-
-	status = acpi_evaluate_crs(ab->handle, &crsbuf);
+	status = acpi_get_object_info(handle, &buffer);
 	if (ACPI_SUCCESS(status)) {
-		status = acpi_parse_crs(ab, crsbuf);
-		kfree(crsbuf);
-
-		pciehp_resource_sort_and_combine(&ab->bus_head);
-		pciehp_resource_sort_and_combine(&ab->io_head);
-		pciehp_resource_sort_and_combine(&ab->mem_head);
-		pciehp_resource_sort_and_combine(&ab->p_mem_head);
-
-		pciehprm_add_resources (&ab->tbus_head, ab->bus_head);
-		pciehprm_add_resources (&ab->tio_head, ab->io_head);
-		pciehprm_add_resources (&ab->tmem_head, ab->mem_head);
-		pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
-	}
-
-	return status;
-}
-
-/* find acpi_bridge downword from ab.  */
-static struct acpi_bridge *
-find_acpi_bridge_by_bus(
-	struct acpi_bridge *ab,
-	int seg,
-	int bus		/* pdev->subordinate->number */
-	)
-{
-	struct acpi_bridge	*lab = NULL;
-
-	if (!ab)
-		return NULL;
-
-	if ((ab->bus == bus) && (ab->seg == seg))
-		return ab;
-
-	if (ab->child)
-		lab = find_acpi_bridge_by_bus(ab->child, seg, bus);
-
-	if (!lab)
-	if (ab->next)
-		lab = find_acpi_bridge_by_bus(ab->next, seg, bus);
-
-	return lab;
-}
-
-/*
- * Build a device tree of ACPI PCI Bridges
- */
-static void pciehprm_acpi_register_a_bridge (
-	struct acpi_bridge	**head,
-	struct acpi_bridge	*pab,	/* parent bridge to which child bridge is added */
-	struct acpi_bridge	*cab	/* child bridge to add */
-	)
-{
-	struct acpi_bridge	*lpab;
-	struct acpi_bridge	*lcab;
-
-	lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus);
-	if (!lpab) {
-		if (!(pab->type & BRIDGE_TYPE_HOST))
-			warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus);
-		pab->next = *head;
-		*head = pab;
-		lpab = pab;
-	}
-
-	if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab))
-		return;
-
-	lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus);
-	if (lcab) {
-		if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus))
-			err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus);
-		return;
-	} else
-		lcab = cab;
-
-	lcab->parent = lpab;
-	lcab->next = lpab->child;
-	lpab->child = lcab;
-}
-
-static acpi_status pciehprm_acpi_build_php_slots_callback(
-	acpi_handle		handle,
-	u32			Level,
-	void			*context,
-	void			**retval
-	)
-{
-	ulong		bus_num;
-	ulong		seg_num;
-	ulong		sun, adr;
-	ulong		padr = 0;
-	acpi_handle		phandle = NULL;
-	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
-	struct acpi_bridge	*lab;
-	acpi_status		status;
-	u8			*path_name = acpi_path_name(handle);
-
-	/* get _SUN */
-	status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun);
-	switch(status) {
-	case AE_NOT_FOUND:
-		return AE_OK;
-	default:
-		if (ACPI_FAILURE(status)) {
-			err("acpi_pciehprm:%s _SUN fail=0x%x\n", path_name, status);
-			return status;
+		info = buffer.pointer;
+		if ((info->valid & ACPI_VALID_HID) &&
+			!strcmp(PCI_ROOT_HID_STRING,
+					info->hardware_id.value)) {
+			acpi_os_free(buffer.pointer);
+			return 1;
+		}
+		if (info->valid & ACPI_VALID_CID) {
+			for (i=0; i < info->compatibility_id.count; i++) {
+				if (!strcmp(PCI_ROOT_HID_STRING,
+					info->compatibility_id.id[i].value)) {
+					acpi_os_free(buffer.pointer);
+					return 1;
+				}
+			}
 		}
 	}
-
-	/* get _ADR. _ADR must exist if _SUN exists */
-	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
-	if (ACPI_FAILURE(status)) {
-		err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
-		return status;
-	}
-
-	dbg("acpi_pciehprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr);
-
-	status = acpi_get_parent(handle, &phandle);
-	if (ACPI_FAILURE(status)) {
-		err("acpi_pciehprm:%s get_parent fail=0x%x\n", path_name, status);
-		return (status);
-	}
-
-	bus_num = pab->bus;
-	seg_num = pab->seg;
-
-	if (pab->bus == bus_num) {
-		lab = pab;
-	} else {
-		dbg("WARN: pab is not parent\n");
-		lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num);
-		if (!lab) {
-			dbg("acpi_pciehprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
-			lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL);
-			if (!lab) {
-				err("acpi_pciehprm: alloc for ab fail\n");
-				return AE_NO_MEMORY;
-			}
-			memset(lab, 0, sizeof(struct acpi_bridge));
-
-			lab->handle = phandle;
-			lab->pbus = pab->bus;
-			lab->pdevice = (int)(padr >> 16) & 0xffff;
-			lab->pfunction = (int)(padr & 0xffff);
-			lab->bus = (int)bus_num;
-			lab->scanned = 0;
-			lab->type = BRIDGE_TYPE_P2P;
-
-			pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab);
-		} else
-			dbg("acpi_pciehprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
-	}
-
-	acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun);
-
-	return (status);
-}
-
-static int pciehprm_acpi_build_php_slots(
-	struct acpi_bridge	*ab,
-	u32			depth
-	)
-{
-	acpi_status	status;
-	u8		*path_name = acpi_path_name(ab->handle);
-
-	/* Walk down this pci bridge to get _SUNs if any behind P2P */
-	status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
-				ab->handle,
-				depth,
-				pciehprm_acpi_build_php_slots_callback,
-				ab,
-				NULL );
-	if (ACPI_FAILURE(status)) {
-		dbg("acpi_pciehprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status);
-		return -1;
-	}
-
 	return 0;
 }
 
-static void build_a_bridge(
-	struct acpi_bridge	*pab,
-	struct acpi_bridge	*ab
-	)
+int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
 {
-	u8		*path_name = acpi_path_name(ab->handle);
-
-	pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab);
-
-	switch (ab->type) {
-	case BRIDGE_TYPE_HOST:
-		dbg("acpi_pciehprm: Registered PCI HOST Bridge(%02x)    on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
-			ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
-		break;
-	case BRIDGE_TYPE_P2P:
-		dbg("acpi_pciehprm: Registered PCI  P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
-			ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
-		break;
-	};
-
-	/* build any immediate PHP slots under this pci bridge */
-	pciehprm_acpi_build_php_slots(ab, 1);
-}
-
-static struct acpi_bridge * add_p2p_bridge(
-	acpi_handle handle,
-	struct acpi_bridge	*pab,	/* parent */
-	ulong	adr
-	)
-{
-	struct acpi_bridge	*ab;
-	struct pci_dev	*pdev;
-	ulong		devnum, funcnum;
-	u8			*path_name = acpi_path_name(handle);
-
-	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
-	if (!ab) {
-		err("acpi_pciehprm: alloc for ab fail\n");
-		return NULL;
-	}
-	memset(ab, 0, sizeof(struct acpi_bridge));
-
-	devnum = (adr >> 16) & 0xffff;
-	funcnum = adr & 0xffff;
-
-	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
-	if (!pdev || !pdev->subordinate) {
-		err("acpi_pciehprm:%s is not a P2P Bridge\n", path_name);
-		kfree(ab);
-		return NULL;
+	acpi_status status;
+	acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
+	struct pci_dev *pdev = dev;
+	u8 *path_name;
+	/*
+	 * Per PCI firmware specification, we should run the ACPI _OSC
+	 * method to get control of hotplug hardware before using it.
+	 * If an _OSC is missing, we look for an OSHP to do the same thing.
+	 * To handle different BIOS behavior, we look for _OSC and OSHP
+	 * within the scope of the hotplug controller and its parents, upto
+	 * the host bridge under which this controller exists.
+	 */
+	while (!handle) {
+		/*
+		 * This hotplug controller was not listed in the ACPI name
+		 * space at all. Try to get acpi handle of parent pci bus.
+		 */
+		if (!pdev || !pdev->bus->parent)
+			break;
+		dbg("Could not find %s in acpi namespace, trying parent\n",
+				pci_name(pdev));
+		if (!pdev->bus->parent->self)
+			/* Parent must be a host bridge */
+			handle = acpi_get_pci_rootbridge_handle(
+					pci_domain_nr(pdev->bus->parent),
+					pdev->bus->parent->number);
+		else
+			handle = DEVICE_ACPI_HANDLE(
+					&(pdev->bus->parent->self->dev));
+		pdev = pdev->bus->parent->self;
 	}
 
-	ab->handle = handle;
-	ab->seg = pab->seg;
-	ab->pbus = pab->bus;		/* or pdev->bus->number */
-	ab->pdevice = devnum;		/* or PCI_SLOT(pdev->devfn) */
-	ab->pfunction = funcnum;	/* or PCI_FUNC(pdev->devfn) */
-	ab->bus = pdev->subordinate->number;
-	ab->scanned = 0;
-	ab->type = BRIDGE_TYPE_P2P;
-
-	dbg("acpi_pciehprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n",
-		pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-		pab->bus, (u32)devnum, (u32)funcnum, path_name);
-
-	build_a_bridge(pab, ab);
-
-	return ab;
-}
-
-static acpi_status scan_p2p_bridge(
-	acpi_handle		handle,
-	u32			Level,
-	void			*context,
-	void			**retval
-	)
-{
-	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
-	struct acpi_bridge	*ab;
-	acpi_status		status;
-	ulong			adr = 0;
-	u8			*path_name = acpi_path_name(handle);
-	ulong			devnum, funcnum;
-	struct pci_dev		*pdev;
-
-	/* get device, function */
-	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
-	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND)
-			err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
-		return AE_OK;
-	}
-
-	devnum = (adr >> 16) & 0xffff;
-	funcnum = adr & 0xffff;
-
-	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
-	if (!pdev)
-		return AE_OK;
-	if (!pdev->subordinate)
-		return AE_OK;
-
-	ab = add_p2p_bridge(handle, pab, adr);
-	if (ab) {
-		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
-					handle,
-					(u32)1,
-					scan_p2p_bridge,
-					ab,
-					NULL);
-		if (ACPI_FAILURE(status))
-			dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status);
-	}
-
-	return AE_OK;
-}
-
-static struct acpi_bridge * add_host_bridge(
-	acpi_handle handle,
-	ulong	segnum,
-	ulong	busnum
-	)
-{
-	ulong			adr = 0;
-	acpi_status		status;
-	struct acpi_bridge	*ab;
-	u8			*path_name = acpi_path_name(handle);
-
-	/* get device, function: host br adr is always 0000 though.  */
-	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
-	if (ACPI_FAILURE(status)) {
-		err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
-		return NULL;
-	}
-	dbg("acpi_pciehprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, 
-		(u32)busnum, (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name);
-
-	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
-	if (!ab) {
-		err("acpi_pciehprm: alloc for ab fail\n");
-		return NULL;
-	}
-	memset(ab, 0, sizeof(struct acpi_bridge));
-
-	ab->handle = handle;
-	ab->seg = (int)segnum;
-	ab->bus = ab->pbus = (int)busnum;
-	ab->pdevice = (int)(adr >> 16) & 0xffff;
-	ab->pfunction = (int)(adr & 0xffff);
-	ab->scanned = 0;
-	ab->type = BRIDGE_TYPE_HOST;
-
-	/* get root pci bridge's current resources */
-	status = acpi_get_crs(ab);
-	if (ACPI_FAILURE(status)) {
-		err("acpi_pciehprm:%s evaluate _CRS fail=0x%x\n", path_name, status);
-		kfree(ab);
-		return NULL;
-	}
-
-	status = pci_osc_control_set (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); 
-	if (ACPI_FAILURE(status)) {
-		err("%s: status %x\n", __FUNCTION__, status);
-		osc_run_status = (status == AE_NOT_FOUND) ? OSC_NOT_EXIST : OSC_RUN_FAILED;
-	} else {
-		osc_run_status = NC_RUN_SUCCESS;
-	}	
-	dbg("%s: osc_run_status %x\n", __FUNCTION__, osc_run_status);
-	
-	build_a_bridge(ab, ab);
-
-	return ab;
-}
-
-static acpi_status acpi_scan_from_root_pci_callback (
-	acpi_handle	handle,
-	u32			Level,
-	void		*context,
-	void		**retval
-	)
-{
-	ulong		segnum = 0;
-	ulong		busnum = 0;
-	acpi_status		status;
-	struct acpi_bridge	*ab;
-	u8			*path_name = acpi_path_name(handle);
-
-	/* get bus number of this pci root bridge */
-	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum);
-	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND) {
-			err("acpi_pciehprm:%s evaluate _SEG fail=0x%x\n", path_name, status);
-			return status;
+	while (handle) {
+		path_name = acpi_path_name(handle);
+		dbg("Trying to get hotplug control for %s \n", path_name);
+		status = pci_osc_control_set(handle,
+				OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
+		if (status == AE_NOT_FOUND)
+			status = acpi_run_oshp(handle);
+		if (ACPI_SUCCESS(status)) {
+			dbg("Gained control for hotplug HW for pci %s (%s)\n",
+				pci_name(dev), path_name);
+			return 0;
 		}
-		segnum = 0;
-	}
-
-	/* get bus number of this pci root bridge */
-	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum);
-	if (ACPI_FAILURE(status)) {
-		err("acpi_pciehprm:%s evaluate _BBN fail=0x%x\n", path_name, status);
-		return (status);
-	}
-
-	ab = add_host_bridge(handle, segnum, busnum);
-	if (ab) {
-		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
-					handle,
-					1,
-					scan_p2p_bridge,
-					ab,
-					NULL);
+		if (is_root_bridge(handle))
+			break;
+		chandle = handle;
+		status = acpi_get_parent(chandle, &handle);
 		if (ACPI_FAILURE(status))
-			dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status);
+			break;
 	}
 
-	return AE_OK;
+	err("Cannot get control of hotplug hardware for pci %s\n",
+			pci_name(dev));
+	return -1;
 }
 
-static int pciehprm_acpi_scan_pci (void)
+void pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
+		struct hotplug_params *hpp)
 {
-	acpi_status	status;
+	acpi_status status = AE_NOT_FOUND;
+	struct pci_dev *pdev = dev;
 
 	/*
-	 * TBD: traverse LDM device tree with the help of
-	 *  unified ACPI augmented for php device population.
+	 * _HPP settings apply to all child buses, until another _HPP is
+	 * encountered. If we don't find an _HPP for the input pci dev,
+	 * look for it in the parent device scope since that would apply to
+	 * this pci dev. If we don't find any _HPP, use hardcoded defaults
 	 */
-	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
-				acpi_scan_from_root_pci_callback,
-				NULL,
-				NULL );
-	if (ACPI_FAILURE(status)) {
-		err("acpi_pciehprm:get_device PCI ROOT HID fail=0x%x\n", status);
-		return -1;
-	}
-
-	return 0;
-}
-
-int pciehprm_init(enum php_ctlr_type ctlr_type)
-{
-	int	rc;
-
-	if (ctlr_type != PCI)
-		return -ENODEV;
-
-	dbg("pciehprm ACPI init <enter>\n");
-	acpi_bridges_head = NULL;
-
-	/* construct PCI bus:device tree of acpi_handles */
-	rc = pciehprm_acpi_scan_pci();
-	if (rc)
-		return rc;
-
-	if ((oshp_run_status != NC_RUN_SUCCESS) && (osc_run_status != NC_RUN_SUCCESS)) {
-		err("Fails to gain control of native hot-plug\n");
-		rc = -ENODEV;
-	}
-
-	dbg("pciehprm ACPI init %s\n", (rc)?"fail":"success");
-	return rc;
-}
-
-static void free_a_slot(struct acpi_php_slot *aps)
-{
-	dbg("        free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun);
-
-	free_pci_resource (aps->io_head);
-	free_pci_resource (aps->bus_head);
-	free_pci_resource (aps->mem_head);
-	free_pci_resource (aps->p_mem_head);
-
-	kfree(aps);
-}
-
-static void free_a_bridge( struct acpi_bridge	*ab)
-{
-	struct acpi_php_slot	*aps, *next;
-
-	switch (ab->type) {
-	case BRIDGE_TYPE_HOST:
-		dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
-			ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
-		break;
-	case BRIDGE_TYPE_P2P:
-		dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
-			ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
-		break;
-	};
-
-	/* free slots first */
-	for (aps = ab->slots; aps; aps = next) {
-		next = aps->next;
-		free_a_slot(aps);
-	}
-
-	free_pci_resource (ab->io_head);
-	free_pci_resource (ab->tio_head);
-	free_pci_resource (ab->bus_head);
-	free_pci_resource (ab->tbus_head);
-	free_pci_resource (ab->mem_head);
-	free_pci_resource (ab->tmem_head);
-	free_pci_resource (ab->p_mem_head);
-	free_pci_resource (ab->tp_mem_head);
-
-	kfree(ab);
-}
-
-static void pciehprm_free_bridges ( struct acpi_bridge	*ab)
-{
-	if (!ab)
-		return;
-
-	if (ab->child)
-		pciehprm_free_bridges (ab->child);
-
-	if (ab->next)
-		pciehprm_free_bridges (ab->next);
-
-	free_a_bridge(ab);
-}
-
-void pciehprm_cleanup(void)
-{
-	pciehprm_free_bridges (acpi_bridges_head);
-}
-
-static int get_number_of_slots (
-	struct acpi_bridge	*ab,
-	int				selfonly
-	)
-{
-	struct acpi_php_slot	*aps;
-	int	prev_slot = -1;
-	int	slot_num = 0;
-
-	for ( aps = ab->slots; aps; aps = aps->next)
-		if (aps->dev != prev_slot) {
-			prev_slot = aps->dev;
-			slot_num++;
-		}
-
-	if (ab->child)
-		slot_num += get_number_of_slots (ab->child, 0);
-
-	if (selfonly)
-		return slot_num;
-
-	if (ab->next)
-		slot_num += get_number_of_slots (ab->next, 0);
-
-	return slot_num;
-}
-
-static int print_acpi_resources (struct acpi_bridge	*ab)
-{
-	struct acpi_php_slot		*aps;
-	int	i;
-
-	switch (ab->type) {
-	case BRIDGE_TYPE_HOST:
-		dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle));
-		break;
-	case BRIDGE_TYPE_P2P:
-		dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle));
-		break;
-	};
-
-	print_pci_resources (ab);
-
-	for ( i = -1, aps = ab->slots; aps; aps = aps->next) {
-		if (aps->dev == i)
-			continue;
-		dbg("  Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun);
-		print_slot_resources(aps);
-		i = aps->dev;
-	}
-
-	if (ab->child)
-		print_acpi_resources (ab->child);
-
-	if (ab->next)
-		print_acpi_resources (ab->next);
-
-	return 0;
-}
-
-int pciehprm_print_pirt(void)
-{
-	dbg("PCIEHPRM ACPI Slots\n");
-	if (acpi_bridges_head)
-		print_acpi_resources (acpi_bridges_head);
-
-	return 0;
-}
-
-static struct acpi_php_slot * get_acpi_slot (
-	struct acpi_bridge *ab,
-	u32 sun
-	)
-{
-	struct acpi_php_slot	*aps = NULL;
-
-	for ( aps = ab->slots; aps; aps = aps->next)
-		if (aps->sun == sun)
-			return aps;
-
-	if (!aps && ab->child) {
-		aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun);
-		if (aps)
-			return aps;
-	}
-
-	if (!aps && ab->next) {
-		aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun);
-		if (aps)
-			return aps;
-	}
-
-	return aps;
-
-}
-
-#if 0
-void * pciehprm_get_slot(struct slot *slot)
-{
-	struct acpi_bridge	*ab = acpi_bridges_head;
-	struct acpi_php_slot	*aps = get_acpi_slot (ab, slot->number);
-
-	aps->slot = slot;
-
-	dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun);
-
-	return (void *)aps;
-}
-#endif
-
-static void pciehprm_dump_func_res( struct pci_func *fun)
-{
-	struct pci_func *func = fun;
-
-	if (func->bus_head) {
-		dbg(":    BUS Resources:\n");
-		print_pci_resource (func->bus_head);
-	}
-	if (func->io_head) {
-		dbg(":    IO Resources:\n");
-		print_pci_resource (func->io_head);
-	}
-	if (func->mem_head) {
-		dbg(":    MEM Resources:\n");
-		print_pci_resource (func->mem_head);
-	}
-	if (func->p_mem_head) {
-		dbg(":    PMEM Resources:\n");
-		print_pci_resource (func->p_mem_head);
+	while (pdev && (ACPI_FAILURE(status))) {
+		acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
+		if (!handle)
+			break;
+		status = acpi_run_hpp(handle, hpp);
+		if (!(pdev->bus->parent))
+			break;
+		/* Check if a parent object supports _HPP */
+		pdev = pdev->bus->parent->self;
 	}
 }
 
-static void pciehprm_dump_ctrl_res( struct controller *ctlr)
-{
-	struct controller *ctrl = ctlr;
-
-	if (ctrl->bus_head) {
-		dbg(":    BUS Resources:\n");
-		print_pci_resource (ctrl->bus_head);
-	}
-	if (ctrl->io_head) {
-		dbg(":    IO Resources:\n");
-		print_pci_resource (ctrl->io_head);
-	}
-	if (ctrl->mem_head) {
-		dbg(":    MEM Resources:\n");
-		print_pci_resource (ctrl->mem_head);
-	}
-	if (ctrl->p_mem_head) {
-		dbg(":    PMEM Resources:\n");
-		print_pci_resource (ctrl->p_mem_head);
-	}
-}
-
-static int pciehprm_get_used_resources (
-	struct controller *ctrl,
-	struct pci_func *func
-	)
-{
-	return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD);
-}
-
-static int configure_existing_function(
-	struct controller *ctrl,
-	struct pci_func *func
-	)
-{
-	int rc;
-
-	/* see how much resources the func has used. */
-	rc = pciehprm_get_used_resources (ctrl, func);
-
-	if (!rc) {
-		/* subtract the resources used by the func from ctrl resources */
-		rc  = pciehprm_delete_resources (&ctrl->bus_head, func->bus_head);
-		rc |= pciehprm_delete_resources (&ctrl->io_head, func->io_head);
-		rc |= pciehprm_delete_resources (&ctrl->mem_head, func->mem_head);
-		rc |= pciehprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
-		if (rc)
-			warn("aCEF: cannot del used resources\n");
-	} else
-		err("aCEF: cannot get used resources\n");
-
-	return rc;
-}
-
-static int bind_pci_resources_to_slots ( struct controller *ctrl)
-{
-	struct pci_func *func, new_func;
-	int busn = ctrl->slot_bus;
-	int devn, funn;
-	u32	vid;
-
-	for (devn = 0; devn < 32; devn++) {
-		for (funn = 0; funn < 8; funn++) {
-			/*
-			if (devn == ctrl->device && funn == ctrl->function)
-				continue;
-			*/
-			/* find out if this entry is for an occupied slot */
-			vid = 0xFFFFFFFF;
-			pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid);
-
-			if (vid != 0xFFFFFFFF) {
-				dbg("%s: vid = %x\n", __FUNCTION__, vid);
-				func = pciehp_slot_find(busn, devn, funn);
-				if (!func) {
-					memset(&new_func, 0, sizeof(struct pci_func));
-					new_func.bus = busn;
-					new_func.device = devn;
-					new_func.function = funn;
-					new_func.is_a_board = 1;
-					configure_existing_function(ctrl, &new_func);
-					pciehprm_dump_func_res(&new_func);
-				} else {
-					configure_existing_function(ctrl, func);
-					pciehprm_dump_func_res(func);
-				}
-				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int bind_pci_resources(
-	struct controller 	*ctrl,
-	struct acpi_bridge	*ab
-	)
-{
-	int		status = 0;
-
-	if (ab->bus_head) {
-		dbg("bapr:  BUS Resources add on PCI 0x%x\n", ab->bus);
-		status = pciehprm_add_resources (&ctrl->bus_head, ab->bus_head);
-		if (pciehprm_delete_resources (&ab->bus_head, ctrl->bus_head))
-			warn("bapr:  cannot sub BUS Resource on PCI 0x%x\n", ab->bus);
-		if (status) {
-			err("bapr:  BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
-			return status;
-		}
-	} else
-		info("bapr:  No BUS Resource on PCI 0x%x.\n", ab->bus);
-
-	if (ab->io_head) {
-		dbg("bapr:  IO Resources add on PCI 0x%x\n", ab->bus);
-		status = pciehprm_add_resources (&ctrl->io_head, ab->io_head);
-		if (pciehprm_delete_resources (&ab->io_head, ctrl->io_head))
-			warn("bapr:  cannot sub IO Resource on PCI 0x%x\n", ab->bus);
-		if (status) {
-			err("bapr:  IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
-			return status;
-		}
-	} else
-		info("bapr:  No  IO Resource on PCI 0x%x.\n", ab->bus);
-
-	if (ab->mem_head) {
-		dbg("bapr:  MEM Resources add on PCI 0x%x\n", ab->bus);
-		status = pciehprm_add_resources (&ctrl->mem_head, ab->mem_head);
-		if (pciehprm_delete_resources (&ab->mem_head, ctrl->mem_head))
-			warn("bapr:  cannot sub MEM Resource on PCI 0x%x\n", ab->bus);
-		if (status) {
-			err("bapr:  MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
-			return status;
-		}
-	} else
-		info("bapr:  No MEM Resource on PCI 0x%x.\n", ab->bus);
-
-	if (ab->p_mem_head) {
-		dbg("bapr:  PMEM Resources add on PCI 0x%x\n", ab->bus);
-		status = pciehprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head);
-		if (pciehprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head))
-			warn("bapr:  cannot sub PMEM Resource on PCI 0x%x\n", ab->bus);
-		if (status) {
-			err("bapr:  PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
-			return status;
-		}
-	} else
-		info("bapr:  No PMEM Resource on PCI 0x%x.\n", ab->bus);
-
-	return status;
-}
-
-static int no_pci_resources( struct acpi_bridge *ab)
-{
-	return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head);
-}
-
-static int find_pci_bridge_resources (
-	struct controller *ctrl,
-	struct acpi_bridge *ab
-	)
-{
-	int	rc = 0;
-	struct pci_func func;
-
-	memset(&func, 0, sizeof(struct pci_func));
-
-	func.bus = ab->pbus;
-	func.device = ab->pdevice;
-	func.function = ab->pfunction;
-	func.is_a_board = 1;
-
-	/* Get used resources for this PCI bridge */
-	rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD);
-
-	ab->io_head = func.io_head;
-	ab->mem_head = func.mem_head;
-	ab->p_mem_head = func.p_mem_head;
-	ab->bus_head = func.bus_head;
-	if (ab->bus_head)
-		pciehprm_delete_resource(&ab->bus_head, ctrl->pci_dev->subordinate->number, 1);
-
-	return rc;
-}
-
-static int get_pci_resources_from_bridge(
-	struct controller *ctrl,
-	struct acpi_bridge *ab
-	)
-{
-	int	rc = 0;
-
-	dbg("grfb:  Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus);
-
-	rc = find_pci_bridge_resources (ctrl, ab);
-
-	pciehp_resource_sort_and_combine(&ab->bus_head);
-	pciehp_resource_sort_and_combine(&ab->io_head);
-	pciehp_resource_sort_and_combine(&ab->mem_head);
-	pciehp_resource_sort_and_combine(&ab->p_mem_head);
-
-	pciehprm_add_resources (&ab->tbus_head, ab->bus_head);
-	pciehprm_add_resources (&ab->tio_head, ab->io_head);
-	pciehprm_add_resources (&ab->tmem_head, ab->mem_head);
-	pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
-
-	return rc;
-}
-
-static int get_pci_resources(
-	struct controller	*ctrl,
-	struct acpi_bridge	*ab
-	)
-{
-	int	rc = 0;
-
-	if (no_pci_resources(ab)) {
-		dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus);
-		rc = get_pci_resources_from_bridge(ctrl, ab);
-	}
-
-	return rc;
-}
-
-/*
- * Get resources for this ctrl.
- *  1. get total resources from ACPI _CRS or bridge (this ctrl)
- *  2. find used resources of existing adapters
- *	3. subtract used resources from total resources
- */
-int pciehprm_find_available_resources( struct controller *ctrl)
-{
-	int rc = 0;
-	struct acpi_bridge	*ab;
-
-	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number);
-	if (!ab) {
-		err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number);
-		return -1;
-	}
-	if (no_pci_resources(ab)) {
-		rc = get_pci_resources(ctrl, ab);
-		if (rc) {
-			err("pfar:cannot get pci resources of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number);
-			return -1;
-		}
-	}
-
-	rc = bind_pci_resources(ctrl, ab);
-	dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
-	pciehprm_dump_ctrl_res(ctrl);
-
-	bind_pci_resources_to_slots (ctrl);
-
-	dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
-	pciehprm_dump_ctrl_res(ctrl);
-
-	return rc;
-}
-
-int pciehprm_set_hpp(
-	struct controller *ctrl,
-	struct pci_func *func,
-	u8	card_type
-	)
-{
-	struct acpi_bridge	*ab;
-	struct pci_bus lpci_bus, *pci_bus;
-	int				rc = 0;
-	unsigned int	devfn;
-	u8				cls= 0x08;	/* default cache line size	*/
-	u8				lt = 0x40;	/* default latency timer	*/
-	u8				ep = 0;
-	u8				es = 0;
-
-	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
-	pci_bus = &lpci_bus;
-	pci_bus->number = func->bus;
-	devfn = PCI_DEVFN(func->device, func->function);
-
-	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
-
-	if (ab) {
-		if (ab->_hpp) {
-			lt  = (u8)ab->_hpp->latency_timer;
-			cls = (u8)ab->_hpp->cache_line_size;
-			ep  = (u8)ab->_hpp->enable_perr;
-			es  = (u8)ab->_hpp->enable_serr;
-		} else
-			dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
-	} else
-		dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
-
-
-	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
-		/* set subordinate Latency Timer */
-		rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt);
-	}
-
-	/* set base Latency Timer */
-	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt);
-	dbg("  set latency timer  =0x%02x: %x\n", lt, rc);
-
-	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls);
-	dbg("  set cache_line_size=0x%02x: %x\n", cls, rc);
-
-	return rc;
-}
-
-void pciehprm_enable_card(
-	struct controller *ctrl,
-	struct pci_func *func,
-	u8 card_type)
-{
-	u16 command, cmd, bcommand, bcmd;
-	struct pci_bus lpci_bus, *pci_bus;
-	struct acpi_bridge	*ab;
-	unsigned int devfn;
-	int rc;
-
-	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
-	pci_bus = &lpci_bus;
-	pci_bus->number = func->bus;
-	devfn = PCI_DEVFN(func->device, func->function);
-
-	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &cmd);
-
-	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
-		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcmd);
-	}
-
-	command  = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
-		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
-	bcommand  = bcmd | PCI_BRIDGE_CTL_NO_ISA;
-
-	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
-	if (ab) {
-		if (ab->_hpp) {
-			if (ab->_hpp->enable_perr) {
-				command |= PCI_COMMAND_PARITY;
-				bcommand |= PCI_BRIDGE_CTL_PARITY;
-			} else {
-				command &= ~PCI_COMMAND_PARITY;
-				bcommand &= ~PCI_BRIDGE_CTL_PARITY;
-			}
-			if (ab->_hpp->enable_serr) {
-				command |= PCI_COMMAND_SERR;
-				bcommand |= PCI_BRIDGE_CTL_SERR;
-			} else {
-				command &= ~PCI_COMMAND_SERR;
-				bcommand &= ~PCI_BRIDGE_CTL_SERR;
-			}
-		} else
-			dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
-	} else
-		dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
-
-	if (command != cmd) {
-		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
-	}
-	if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) {
-		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
-	}
-}
diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.c b/drivers/pci/hotplug/pciehprm_nonacpi.c
index 76c727c..29180df 100644
--- a/drivers/pci/hotplug/pciehprm_nonacpi.c
+++ b/drivers/pci/hotplug/pciehprm_nonacpi.c
@@ -27,479 +27,21 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/slab.h>
-
-#include <asm/uaccess.h>
-#ifdef CONFIG_IA64
-#include <asm/iosapic.h>
-#endif
-
 #include "pciehp.h"
-#include "pciehprm.h"
-#include "pciehprm_nonacpi.h"
 
-
-void pciehprm_cleanup(void)
+void pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
+		struct hotplug_params *hpp)
 {
 	return;
 }
 
-int pciehprm_print_pirt(void)
+int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
 {
 	return 0;
 }
-
-int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
-{
-
-	*sun = (u8) (ctrl->first_slot);
-	return 0;
-}
-
-
-static void print_pci_resource ( struct pci_resource	*aprh)
-{
-	struct pci_resource	*res;
-
-	for (res = aprh; res; res = res->next)
-		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
-}
-
-
-static void phprm_dump_func_res( struct pci_func *fun)
-{
-	struct pci_func *func = fun;
-
-	if (func->bus_head) {
-		dbg(":    BUS Resources:\n");
-		print_pci_resource (func->bus_head);
-	}
-	if (func->io_head) {
-		dbg(":    IO Resources:\n");
-		print_pci_resource (func->io_head);
-	}
-	if (func->mem_head) {
-		dbg(":    MEM Resources:\n");
-		print_pci_resource (func->mem_head);
-	}
-	if (func->p_mem_head) {
-		dbg(":    PMEM Resources:\n");
-		print_pci_resource (func->p_mem_head);
-	}
-}
-
-static int phprm_get_used_resources (
-	struct controller *ctrl,
-	struct pci_func *func
-	)
-{
-	return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD);
-}
-
-static int phprm_delete_resource(
-	struct pci_resource **aprh,
-	ulong base,
-	ulong size)
-{
-	struct pci_resource *res;
-	struct pci_resource *prevnode;
-	struct pci_resource *split_node;
-	ulong tbase;
-
-	pciehp_resource_sort_and_combine(aprh);
-
-	for (res = *aprh; res; res = res->next) {
-		if (res->base > base)
-			continue;
-
-		if ((res->base + res->length) < (base + size))
-			continue;
-
-		if (res->base < base) {
-			tbase = base;
-
-			if ((res->length - (tbase - res->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-			if (!split_node)
-				return -ENOMEM;
-
-			split_node->base = res->base;
-			split_node->length = tbase - res->base;
-			res->base = tbase;
-			res->length -= split_node->length;
-
-			split_node->next = res->next;
-			res->next = split_node;
-		}
-
-		if (res->length >= size) {
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-			if (!split_node)
-				return -ENOMEM;
-
-			split_node->base = res->base + size;
-			split_node->length = res->length - size;
-			res->length = size;
-
-			split_node->next = res->next;
-			res->next = split_node;
-		}
-
-		if (*aprh == res) {
-			*aprh = res->next;
-		} else {
-			prevnode = *aprh;
-			while (prevnode->next != res)
-				prevnode = prevnode->next;
-
-			prevnode->next = res->next;
-		}
-		res->next = NULL;
-		kfree(res);
-		break;
-	}
-
-	return 0;
-}
-
-
-static int phprm_delete_resources(
-	struct pci_resource **aprh,
-	struct pci_resource *this
-	)
-{
-	struct pci_resource *res;
-
-	for (res = this; res; res = res->next)
-		phprm_delete_resource(aprh, res->base, res->length);
-
-	return 0;
-}
-
-
-static int configure_existing_function(
-	struct controller *ctrl,
-	struct pci_func *func
-	)
-{
-	int rc;
-
-	/* see how much resources the func has used. */
-	rc = phprm_get_used_resources (ctrl, func);
-
-	if (!rc) {
-		/* subtract the resources used by the func from ctrl resources */
-		rc  = phprm_delete_resources (&ctrl->bus_head, func->bus_head);
-		rc |= phprm_delete_resources (&ctrl->io_head, func->io_head);
-		rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head);
-		rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
-		if (rc)
-			warn("aCEF: cannot del used resources\n");
-	} else
-		err("aCEF: cannot get used resources\n");
-
-	return rc;
-}
-
-static int pciehprm_delete_resource(
-	struct pci_resource **aprh,
-	ulong base,
-	ulong size)
-{
-	struct pci_resource *res;
-	struct pci_resource *prevnode;
-	struct pci_resource *split_node;
-	ulong tbase;
-
-	pciehp_resource_sort_and_combine(aprh);
-
-	for (res = *aprh; res; res = res->next) {
-		if (res->base > base)
-			continue;
-
-		if ((res->base + res->length) < (base + size))
-			continue;
-
-		if (res->base < base) {
-			tbase = base;
-
-			if ((res->length - (tbase - res->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-			if (!split_node)
-				return -ENOMEM;
-
-			split_node->base = res->base;
-			split_node->length = tbase - res->base;
-			res->base = tbase;
-			res->length -= split_node->length;
-
-			split_node->next = res->next;
-			res->next = split_node;
-		}
-
-		if (res->length >= size) {
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-			if (!split_node)
-				return -ENOMEM;
-
-			split_node->base = res->base + size;
-			split_node->length = res->length - size;
-			res->length = size;
-
-			split_node->next = res->next;
-			res->next = split_node;
-		}
-
-		if (*aprh == res) {
-			*aprh = res->next;
-		} else {
-			prevnode = *aprh;
-			while (prevnode->next != res)
-				prevnode = prevnode->next;
-
-			prevnode->next = res->next;
-		}
-		res->next = NULL;
-		kfree(res);
-		break;
-	}
-
-	return 0;
-}
-
-static int bind_pci_resources_to_slots ( struct controller *ctrl)
-{
-	struct pci_func *func, new_func;
-	int busn = ctrl->slot_bus;
-	int devn, funn;
-	u32	vid;
-
-	for (devn = 0; devn < 32; devn++) {
-		for (funn = 0; funn < 8; funn++) {
-			/*
-			if (devn == ctrl->device && funn == ctrl->function)
-				continue;
-			*/
-			/* find out if this entry is for an occupied slot */
-			vid = 0xFFFFFFFF;
-
-			pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid);
-
-			if (vid != 0xFFFFFFFF) {
-				dbg("%s: vid = %x bus %x dev %x fun %x\n", __FUNCTION__,
-				vid, busn, devn, funn);
-				func = pciehp_slot_find(busn, devn, funn);
-				dbg("%s: func = %p\n", __FUNCTION__,func);
-				if (!func) {
-					memset(&new_func, 0, sizeof(struct pci_func));
-					new_func.bus = busn;
-					new_func.device = devn;
-					new_func.function = funn;
-					new_func.is_a_board = 1;
-					configure_existing_function(ctrl, &new_func);
-					phprm_dump_func_res(&new_func);
-				} else {
-					configure_existing_function(ctrl, func);
-					phprm_dump_func_res(func);
-				}
-				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-			}
-		}
-	}
-
-	return 0;
-}
-
-static void phprm_dump_ctrl_res( struct controller *ctlr)
-{
-	struct controller *ctrl = ctlr;
-
-	if (ctrl->bus_head) {
-		dbg(":    BUS Resources:\n");
-		print_pci_resource (ctrl->bus_head);
-	}
-	if (ctrl->io_head) {
-		dbg(":    IO Resources:\n");
-		print_pci_resource (ctrl->io_head);
-	}
-	if (ctrl->mem_head) {
-		dbg(":    MEM Resources:\n");
-		print_pci_resource (ctrl->mem_head);
-	}
-	if (ctrl->p_mem_head) {
-		dbg(":    PMEM Resources:\n");
-		print_pci_resource (ctrl->p_mem_head);
-	}
-}
-
-/*
- * phprm_find_available_resources
- *
- *  Finds available memory, IO, and IRQ resources for programming
- *  devices which may be added to the system
- *  this function is for hot plug ADD!
- *
- * returns 0 if success
- */
-int pciehprm_find_available_resources(struct controller *ctrl)
-{
-	struct pci_func func;
-	u32 rc;
-
-	memset(&func, 0, sizeof(struct pci_func));
-
-	func.bus = ctrl->bus;
-	func.device = ctrl->device;
-	func.function = ctrl->function;
-	func.is_a_board = 1;
-
-	/* Get resources for this PCI bridge */
-	rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD);
-	dbg("%s: pciehp_save_used_resources rc = %d\n", __FUNCTION__, rc);
-
-	if (func.mem_head)
-		func.mem_head->next = ctrl->mem_head;
-	ctrl->mem_head = func.mem_head;
-
-	if (func.p_mem_head)
-		func.p_mem_head->next = ctrl->p_mem_head;
-	ctrl->p_mem_head = func.p_mem_head;
-
-	if (func.io_head)
-		func.io_head->next = ctrl->io_head;
-	ctrl->io_head = func.io_head;
-
-	if(func.bus_head)
-		func.bus_head->next = ctrl->bus_head;
-	ctrl->bus_head = func.bus_head;
-
-	if (ctrl->bus_head)
-		pciehprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1);
-	
-	dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
-	phprm_dump_ctrl_res(ctrl);
-
-	dbg("%s: before bind_pci_resources_to slots\n", __FUNCTION__);
-
-	bind_pci_resources_to_slots (ctrl);
-
-	dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
-	phprm_dump_ctrl_res(ctrl);
-
-	return (rc);
-}
-
-int pciehprm_set_hpp(
-	struct controller *ctrl,
-	struct pci_func *func,
-	u8	card_type)
-{
-	u32 rc;
-	u8 temp_byte;
-	struct pci_bus lpci_bus, *pci_bus;
-	unsigned int	devfn;
-	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
-	pci_bus = &lpci_bus;
-	pci_bus->number = func->bus;
-	devfn = PCI_DEVFN(func->device, func->function);
-
-	temp_byte = 0x40;	/* hard coded value for LT */
-	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
-		/* set subordinate Latency Timer */
-		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
-
-		if (rc) {
-			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, 
-				func->bus, func->device, func->function);
-			return rc;
-		}
-	}
-
-	/* set base Latency Timer */
-	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
-
-	if (rc) {
-		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
-		return rc;
-	}
-
-	/* set Cache Line size */
-	temp_byte = 0x08;	/* hard coded value for CLS */
-
-	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
-
-	if (rc) {
-		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
-	}
-
-	/* set enable_perr */
-	/* set enable_serr */
-
-	return rc;
-}
-
-void pciehprm_enable_card(
-	struct controller *ctrl,
-	struct pci_func *func,
-	u8 card_type)
-{
-	u16 command, bcommand;
-	struct pci_bus lpci_bus, *pci_bus;
-	unsigned int devfn;
-	int rc;
-
-	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
-	pci_bus = &lpci_bus;
-	pci_bus->number = func->bus;
-	devfn = PCI_DEVFN(func->device, func->function);
-
-	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
-
-	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
-		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
-		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
-
-	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
-
-	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
-
-		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
-
-		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
-			| PCI_BRIDGE_CTL_NO_ISA;
-
-		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
-	}
-}
-
-static int legacy_pciehprm_init_pci(void)
-{
-	return 0;
-}
-
-int pciehprm_init(enum php_ctlr_type ctrl_type)
-{
-	int retval;
-
-	switch (ctrl_type) {
-	case PCI:
-		retval = legacy_pciehprm_init_pci();
-		break;
-	default:
-		retval = -ENODEV;
-		break;
-	}
-
-	return retval;
-}
diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.h b/drivers/pci/hotplug/pciehprm_nonacpi.h
deleted file mode 100644
index b10603b..0000000
--- a/drivers/pci/hotplug/pciehprm_nonacpi.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
- *
- * Copyright (C) 1995,2001 Compaq Computer Corporation
- * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2001 IBM Corp.
- * Copyright (C) 2003-2004 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, GOOD TITLE or
- * NON INFRINGEMENT.  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.
- *
- * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
- *
- */
-
-#ifndef _PCIEHPRM_NONACPI_H_
-#define _PCIEHPRM_NONACPI_H_
-
-struct irq_info {
-	u8 bus, devfn;		/* bus, device and function */
-	struct {
-		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
-		u16 bitmap;	/* Available IRQs */
-	} __attribute__ ((packed)) irq[4];
-	u8 slot;		/* slot number, 0=onboard */
-	u8 rfu;
-} __attribute__ ((packed));
-
-struct irq_routing_table {
-	u32 signature;		/* PIRQ_SIGNATURE should be here */
-	u16 version;		/* PIRQ_VERSION */
-	u16 size;			/* Table size in bytes */
-	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
-	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
-	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
-	u32 miniport_data;	/* Crap */
-	u8 rfu[11];
-	u8 checksum;		/* Modulo 256 checksum must give zero */
-	struct irq_info slots[0];
-} __attribute__ ((packed));
-
-#endif				/* _PCIEHPRM_NONACPI_H_ */
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index fcb66b9..cc03609 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -134,43 +134,6 @@
 		rpadlpar_claim_one_bus(child_bus);
 }
 
-static int pci_add_secondary_bus(struct device_node *dn,
-		struct pci_dev *bridge_dev)
-{
-	struct pci_dn *pdn = dn->data;
-	struct pci_controller *hose = pdn->phb;
-	struct pci_bus *child;
-	u8 sec_busno;
-
-	/* Get busno of downstream bus */
-	pci_read_config_byte(bridge_dev, PCI_SECONDARY_BUS, &sec_busno);
-
-	/* Allocate and add to children of bridge_dev->bus */
-	child = pci_add_new_bus(bridge_dev->bus, bridge_dev, sec_busno);
-	if (!child) {
-		printk(KERN_ERR "%s: could not add secondary bus\n", __FUNCTION__);
-		return -ENOMEM;
-	}
-
-	sprintf(child->name, "PCI Bus #%02x", child->number);
-
-	/* Fixup subordinate bridge bases and resources */
-	pcibios_fixup_bus(child);
-
-	/* Claim new bus resources */
-	rpadlpar_claim_one_bus(bridge_dev->bus);
-
-	if (hose->last_busno < child->number)
-		hose->last_busno = child->number;
-
-	pdn->bussubno = child->number;
-
-	/* ioremap() for child bus, which may or may not succeed */
-	remap_bus_range(child);
-
-	return 0;
-}
-
 static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
 					struct device_node *dev_dn)
 {
@@ -188,29 +151,41 @@
 static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
 {
 	struct pci_dn *pdn = dn->data;
-	struct pci_controller *hose = pdn->phb;
+	struct pci_controller *phb = pdn->phb;
 	struct pci_dev *dev = NULL;
 
-	/* Scan phb bus for EADS device, adding new one to bus->devices */
-	if (!pci_scan_single_device(hose->bus, pdn->devfn)) {
-		printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__);
+	rpaphp_eeh_init_nodes(dn);
+	/* Add EADS device to PHB bus, adding new entry to bus->devices */
+	dev = of_create_pci_dev(dn, phb->bus, pdn->devfn);
+	if (!dev) {
+		printk(KERN_ERR "%s: failed to create pci dev for %s\n",
+				__FUNCTION__, dn->full_name);
 		return NULL;
 	}
 
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+	    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+		of_scan_pci_bridge(dn, dev);
+
+	rpaphp_init_new_devs(dev->subordinate);
+
+	/* Claim new bus resources */
+	rpadlpar_claim_one_bus(dev->bus);
+
+	/* ioremap() for child bus, which may or may not succeed */
+	(void) remap_bus_range(dev->bus);
+
 	/* Add new devices to global lists.  Register in proc, sysfs. */
-	pci_bus_add_devices(hose->bus);
+	pci_bus_add_devices(phb->bus);
 
 	/* Confirm new bridge dev was created */
-	dev = dlpar_find_new_dev(hose->bus, dn);
+	dev = dlpar_find_new_dev(phb->bus, dn);
 	if (dev) {
 		if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
 			printk(KERN_ERR "%s: unexpected header type %d\n",
 				__FUNCTION__, dev->hdr_type);
 			return NULL;
 		}
-
-		if (pci_add_secondary_bus(dn, dev))
-			return NULL;
 	}
 
 	return dev;
@@ -219,7 +194,6 @@
 static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
 {
 	struct pci_dev *dev;
-	int rc;
 
 	if (rpaphp_find_pci_bus(dn))
 		return -EINVAL;
@@ -232,15 +206,6 @@
 		return -EIO;
 	}
 
-	if (dn->child) {
-		rc = rpaphp_config_pci_adapter(dev->subordinate);
-		if (rc < 0) {
-			printk(KERN_ERR "%s: unable to enable slot %s\n",
-				__FUNCTION__, drc_name);
-			return -EIO;
-		}
-	}
-
 	/* Add hotplug slot */
 	if (rpaphp_add_slot(dn)) {
 		printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
@@ -306,7 +271,7 @@
 {
 	struct pci_controller *phb;
 
-	if (PCI_DN(dn)->phb) {
+	if (PCI_DN(dn) && PCI_DN(dn)->phb) {
 		/* PHB already exists */
 		return -EINVAL;
 	}
@@ -435,6 +400,8 @@
 				__FUNCTION__, drc_name);
 			return -EIO;
 		}
+	} else {
+		rpaphp_unconfig_pci_adapter(bus);
 	}
 
 	if (unmap_bus_range(bus)) {
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
index 71ea5f9..57ea71a 100644
--- a/drivers/pci/hotplug/rpaphp.h
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -93,6 +93,8 @@
 extern int rpaphp_enable_pci_slot(struct slot *slot);
 extern int register_pci_slot(struct slot *slot);
 extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value);
+extern void rpaphp_init_new_devs(struct pci_bus *bus);
+extern void rpaphp_eeh_init_nodes(struct device_node *dn);
 
 extern int rpaphp_config_pci_adapter(struct pci_bus *bus);
 extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus);
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
index f7c12d7..a7859a8 100644
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -154,8 +154,7 @@
 }
 
 /* Must be called before pci_bus_add_devices */
-static void 
-rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
+void rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
 {
 	struct pci_dev *dev;
 
@@ -184,6 +183,20 @@
 	}
 }
 
+static void rpaphp_eeh_add_bus_device(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		eeh_add_device_late(dev);
+		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+			struct pci_bus *subbus = dev->subordinate;
+			if (subbus)
+				rpaphp_eeh_add_bus_device (subbus);
+		}
+	}
+}
+
 static int rpaphp_pci_config_bridge(struct pci_dev *dev)
 {
 	u8 sec_busno;
@@ -217,6 +230,13 @@
 	return 0;
 }
 
+void rpaphp_init_new_devs(struct pci_bus *bus)
+{
+	rpaphp_fixup_new_pci_devices(bus, 0);
+	rpaphp_eeh_add_bus_device(bus);
+}
+EXPORT_SYMBOL_GPL(rpaphp_init_new_devs);
+
 /*****************************************************************************
  rpaphp_pci_config_slot() will  configure all devices under the
  given slot->dn and return the the first pci_dev.
@@ -233,36 +253,51 @@
 	if (!dn || !dn->child)
 		return NULL;
 
-	slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
+	if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
+		of_scan_bus(dn, bus);
+		if (list_empty(&bus->devices)) {
+			err("%s: No new device found\n", __FUNCTION__);
+			return NULL;
+		}
 
-	/* pci_scan_slot should find all children */
-	num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
-	if (num) {
-		rpaphp_fixup_new_pci_devices(bus, 1);
+		rpaphp_init_new_devs(bus);
 		pci_bus_add_devices(bus);
-	}
-	if (list_empty(&bus->devices)) {
-		err("%s: No new device found\n", __FUNCTION__);
-		return NULL;
-	}
-	list_for_each_entry(dev, &bus->devices, bus_list) {
-		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
-			rpaphp_pci_config_bridge(dev);
+		dev = list_entry(&bus->devices, struct pci_dev, bus_list);
+	} else {
+		slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
+
+		/* pci_scan_slot should find all children */
+		num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
+		if (num) {
+			rpaphp_fixup_new_pci_devices(bus, 1);
+			pci_bus_add_devices(bus);
+		}
+		if (list_empty(&bus->devices)) {
+			err("%s: No new device found\n", __FUNCTION__);
+			return NULL;
+		}
+		list_for_each_entry(dev, &bus->devices, bus_list) {
+			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+				rpaphp_pci_config_bridge(dev);
+
+			rpaphp_eeh_add_bus_device(bus);
+		}
 	}
 
 	return dev;
 }
 
-static void enable_eeh(struct device_node *dn)
+void rpaphp_eeh_init_nodes(struct device_node *dn)
 {
 	struct device_node *sib;
 
 	for (sib = dn->child; sib; sib = sib->sibling) 
-		enable_eeh(sib);
+		rpaphp_eeh_init_nodes(sib);
 	eeh_add_device_early(dn);
 	return;
 	
 }
+EXPORT_SYMBOL_GPL(rpaphp_eeh_init_nodes);
 
 static void print_slot_pci_funcs(struct pci_bus *bus)
 {
@@ -289,7 +324,7 @@
 	if (!dn)
 		goto exit;
 
-	enable_eeh(dn);
+	rpaphp_eeh_init_nodes(dn);
 	dev = rpaphp_pci_config_slot(bus);
 	if (!dev) {
 		err("%s: can't find any devices.\n", __FUNCTION__);
@@ -331,6 +366,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(rpaphp_unconfig_pci_adapter);
 
 static int setup_pci_hotplug_slot_info(struct slot *slot)
 {
@@ -444,8 +480,8 @@
 		retval = rpaphp_config_pci_adapter(slot->bus);
 		if (!retval) {
 			slot->state = CONFIGURED;
-			dbg("%s: PCI devices in slot[%s] has been configured\n", 
-				__FUNCTION__, slot->name);
+			info("%s: devices in slot[%s] configured\n",
+					__FUNCTION__, slot->name);
 		} else {
 			slot->state = NOT_CONFIGURED;
 			dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
index b8e95ac..38009bc 100644
--- a/drivers/pci/hotplug/shpchp_pci.c
+++ b/drivers/pci/hotplug/shpchp_pci.c
@@ -34,7 +34,7 @@
 #include "../pci.h"
 #include "shpchp.h"
 
-void program_fw_provided_values(struct pci_dev *dev)
+static void program_fw_provided_values(struct pci_dev *dev)
 {
 	u16 pci_cmd, pci_bctl;
 	struct pci_dev *cdev;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index a203355..202b750 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -23,6 +23,8 @@
 #include "pci.h"
 #include "msi.h"
 
+#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
+
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -92,6 +94,7 @@
 	struct msi_desc *entry;
 	struct msg_address address;
 	unsigned int irq = vector;
+	unsigned int dest_cpu = first_cpu(cpu_mask);
 
 	entry = (struct msi_desc *)msi_desc[vector];
 	if (!entry || !entry->dev)
@@ -108,9 +111,9 @@
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
 			&address.lo_address.value);
 		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_mask_to_apicid(cpu_mask) <<
-			MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
+		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
+									MSI_TARGET_CPU_SHIFT);
+		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
 			address.lo_address.value);
 		set_native_irq_info(irq, cpu_mask);
@@ -123,9 +126,9 @@
 
 		address.lo_address.value = readl(entry->mask_base + offset);
 		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_mask_to_apicid(cpu_mask) <<
-			MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
+		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
+									MSI_TARGET_CPU_SHIFT);
+		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
 		writel(address.lo_address.value, entry->mask_base + offset);
 		set_native_irq_info(irq, cpu_mask);
 		break;
@@ -259,14 +262,15 @@
 static void msi_address_init(struct msg_address *msi_address)
 {
 	unsigned int	dest_id;
+	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
 
 	memset(msi_address, 0, sizeof(struct msg_address));
 	msi_address->hi_address = (u32)0;
 	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_DEST_MODE;
+	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
 	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
 	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (MSI_TARGET_CPU << MSI_TARGET_CPU_SHIFT);
+	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
 }
 
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index e9e37ab..a9b00cc 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -91,9 +91,7 @@
 static acpi_status  
 acpi_run_osc (
 	acpi_handle	handle,
-	u32		level,
-	void		*context,
-	void		**retval )
+	void		*context)
 {
 	acpi_status		status;
 	struct acpi_object_list	input;
@@ -184,7 +182,7 @@
  *
  * Attempt to take control from Firmware on requested control bits.
  **/
-acpi_status pci_osc_control_set(u32 flags)
+acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
 {
 	acpi_status	status;
 	u32		ctrlset;
@@ -198,10 +196,7 @@
 		return AE_SUPPORT;
 	}
 	ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
-	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
-				acpi_run_osc,
-				ctrlset_buf,
-				NULL );
+	status = acpi_run_osc(handle, ctrlset_buf);
 	if (ACPI_FAILURE (status)) {
 		ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
 	}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 94e68c5..a9046d4 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -37,7 +37,7 @@
  * Adds a new dynamic pci device ID to this driver,
  * and causes the driver to probe for all devices again.
  */
-static inline ssize_t
+static ssize_t
 store_new_id(struct device_driver *driver, const char *buf, size_t count)
 {
 	struct pci_dynid *dynid;
@@ -364,15 +364,16 @@
 };
 
 /**
- * pci_register_driver - register a new pci driver
+ * __pci_register_driver - register a new pci driver
  * @drv: the driver structure to register
+ * @owner: owner module of drv
  * 
  * 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 pci_register_driver(struct pci_driver *drv)
+int __pci_register_driver(struct pci_driver *drv, struct module *owner)
 {
 	int error;
 
@@ -389,7 +390,7 @@
 		printk(KERN_WARNING "Warning: PCI driver %s has a struct "
 			"device_driver shutdown method, please update!\n",
 			drv->name);
-	drv->driver.owner = drv->owner;
+	drv->driver.owner = owner;
 	drv->driver.kobj.ktype = &pci_driver_kobj_type;
 
 	spin_lock_init(&drv->dynids.lock);
@@ -526,7 +527,7 @@
 
 EXPORT_SYMBOL(pci_match_id);
 EXPORT_SYMBOL(pci_match_device);
-EXPORT_SYMBOL(pci_register_driver);
+EXPORT_SYMBOL(__pci_register_driver);
 EXPORT_SYMBOL(pci_unregister_driver);
 EXPORT_SYMBOL(pci_dev_driver);
 EXPORT_SYMBOL(pci_bus_type);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e74d758..8e287a8 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -63,11 +63,38 @@
 	return max;
 }
 
+static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap)
+{
+	u8 id;
+	int ttl = 48;
+
+	while (ttl--) {
+		pci_bus_read_config_byte(bus, devfn, pos, &pos);
+		if (pos < 0x40)
+			break;
+		pos &= ~3;
+		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID,
+					 &id);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+		pos += PCI_CAP_LIST_NEXT;
+	}
+	return 0;
+}
+
+int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
+{
+	return __pci_find_next_cap(dev->bus, dev->devfn,
+				   pos + PCI_CAP_LIST_NEXT, cap);
+}
+EXPORT_SYMBOL_GPL(pci_find_next_capability);
+
 static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap)
 {
 	u16 status;
-	u8 pos, id;
-	int ttl = 48;
+	u8 pos;
 
 	pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
 	if (!(status & PCI_STATUS_CAP_LIST))
@@ -76,24 +103,15 @@
 	switch (hdr_type) {
 	case PCI_HEADER_TYPE_NORMAL:
 	case PCI_HEADER_TYPE_BRIDGE:
-		pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos);
+		pos = PCI_CAPABILITY_LIST;
 		break;
 	case PCI_HEADER_TYPE_CARDBUS:
-		pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &pos);
+		pos = PCI_CB_CAPABILITY_LIST;
 		break;
 	default:
 		return 0;
 	}
-	while (ttl-- && pos >= 0x40) {
-		pos &= ~3;
-		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id);
-		if (id == 0xff)
-			break;
-		if (id == cap)
-			return pos;
-		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos);
-	}
-	return 0;
+	return __pci_find_next_cap(bus, devfn, pos, cap);
 }
 
 /**
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 5627ce1..3a4f49f 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -462,11 +462,11 @@
 
 	pci_read_config_word(dev, 0x70, &hm);
 	hm &= PCI_BASE_ADDRESS_IO_MASK;
-	quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1, "vt82c868 HW-mon");
+	quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1, "vt82c686 HW-mon");
 
 	pci_read_config_dword(dev, 0x90, &smb);
 	smb &= PCI_BASE_ADDRESS_IO_MASK;
-	quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c868 SMB");
+	quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB");
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_vt82c686_acpi );
 
@@ -1243,6 +1243,21 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
 
+
+static void __devinit fixup_rev1_53c810(struct pci_dev* dev)
+{
+	/* rev 1 ncr53c810 chips don't set the class at all which means
+	 * they don't get their resources remapped. Fix that here.
+	 */
+
+	if (dev->class == PCI_CLASS_NOT_DEFINED) {
+		printk(KERN_INFO "NCR 53c810 rev 1 detected, setting PCI class.\n");
+		dev->class = PCI_CLASS_STORAGE_SCSI;
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810);
+
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
 {
 	while (f < end) {
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index ccf2003..309eb55 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -156,7 +156,7 @@
 
 config PCMCIA_M8XX
         tristate "MPC8xx PCMCIA support"
-        depends on PCMCIA && PPC
+        depends on PCMCIA && PPC && 8xx 
         select PCCARD_NONSTATIC
         help
         Say Y here to include support for PowerPC 8xx series PCMCIA
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index fe37541..bcecf51 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -25,7 +25,7 @@
 obj-$(CONFIG_I82365)				+= i82365.o
 obj-$(CONFIG_I82092)				+= i82092.o
 obj-$(CONFIG_TCIC)				+= tcic.o
-obj-$(CONFIG_PCMCIA_M8XX)                              += m8xx_pcmcia.o
+obj-$(CONFIG_PCMCIA_M8XX)			+= m8xx_pcmcia.o
 obj-$(CONFIG_HD64465_PCMCIA)			+= hd64465_ss.o
 obj-$(CONFIG_PCMCIA_SA1100)			+= sa11xx_core.o sa1100_cs.o
 obj-$(CONFIG_PCMCIA_SA1111)			+= sa11xx_core.o sa1111_cs.o
@@ -47,10 +47,10 @@
 au1x00_ss-$(CONFIG_MIPS_PB1500)			+= au1000_pb1x00.o
 au1x00_ss-$(CONFIG_MIPS_DB1000)			+= au1000_db1x00.o
 au1x00_ss-$(CONFIG_MIPS_DB1100)			+= au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1200)                 += au1000_db1x00.o
+au1x00_ss-$(CONFIG_MIPS_DB1200)			+= au1000_db1x00.o
 au1x00_ss-$(CONFIG_MIPS_DB1500)			+= au1000_db1x00.o
 au1x00_ss-$(CONFIG_MIPS_DB1550)			+= au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_XXS1500)               += au1000_xxs1500.o
+au1x00_ss-$(CONFIG_MIPS_XXS1500)		+= au1000_xxs1500.o
 
 sa1111_cs-y					+= sa1111_generic.o
 sa1111_cs-$(CONFIG_ASSABET_NEPONSET)		+= sa1100_neponset.o
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c
index 24cfee1..abc13f2 100644
--- a/drivers/pcmcia/au1000_db1x00.c
+++ b/drivers/pcmcia/au1000_db1x00.c
@@ -30,6 +30,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index b0e7908..f2c970b 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -22,6 +22,8 @@
 #define __ASM_AU1000_PCMCIA_H
 
 /* include the world */
+#include <linux/config.h>
+
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index d414a3b..fd5522e 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -21,6 +21,7 @@
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -30,7 +31,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
-#include <linux/version.h>
 #include <linux/types.h>
 
 #include <pcmcia/cs_types.h>
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index f113b69..01874b0 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -27,7 +27,6 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
@@ -35,7 +34,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
-#include <linux/version.h>
 #include <linux/types.h>
 
 #include <pcmcia/cs_types.h>
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 7ce455d..4ddd762 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1366,6 +1366,7 @@
     if (sockets == 0) {
 	printk("not found.\n");
 	platform_device_unregister(&i82365_device);
+	release_region(i365_base, 2);
 	driver_unregister(&i82365_driver);
 	return -ENODEV;
     }
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index f8bed87..6d9f71c 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -39,7 +39,6 @@
 
 #include <asm/io.h>
 #include <asm/bitops.h>
-#include <asm/segment.h>
 #include <asm/system.h>
 
 #include <linux/kernel.h>
@@ -50,6 +49,7 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
@@ -546,29 +546,11 @@
 	free_irq(pcmcia_schlvl, NULL);
 }
 
-/* copied from tcic.c */
-
-static int m8xx_drv_suspend(struct device *dev, pm_message_t state, u32 level)
-{
-        int ret = 0;
-        if (level == SUSPEND_SAVE_STATE)
-                ret = pcmcia_socket_dev_suspend(dev, state);
-        return ret;
-}
-
-static int m8xx_drv_resume(struct device *dev, u32 level)
-{
-        int ret = 0;
-        if (level == RESUME_RESTORE_STATE)
-                ret = pcmcia_socket_dev_resume(dev);
-        return ret;
-}
-
 static struct device_driver m8xx_driver = {
         .name = "m8xx-pcmcia",
         .bus = &platform_bus_type,
-        .suspend = m8xx_drv_suspend,
-        .resume = m8xx_drv_resume,
+        .suspend = pcmcia_socket_dev_suspend,
+        .resume = pcmcia_socket_dev_resume,
 };
 
 static struct platform_device m8xx_device = {
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index fe5ea36..56c5883 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -22,16 +22,20 @@
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/hardware/scoop.h>
-#ifdef CONFIG_SA1100_COLLIE
-#include <asm/arch-sa1100/collie.h>
-#else
-#include <asm/arch-pxa/pxa-regs.h>
-#endif
 
 #include "soc_common.h"
 
 #define	NO_KEEP_VS 0x0001
 
+/* PCMCIA to Scoop linkage
+
+   There is no easy way to link multiple scoop devices into one
+   single entity for the pxa2xx_pcmcia device so this structure
+   is used which is setup by the platform code
+*/
+struct scoop_pcmcia_config *platform_scoop_config;
+#define SCOOP_DEV platform_scoop_config->devs
+
 static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev)
 {
 	reset_scoop(scoopdev->dev);
@@ -43,38 +47,16 @@
 {
 	int ret;
 
-#ifndef CONFIG_SA1100_COLLIE
-	/*
-	 * Setup default state of GPIO outputs
-	 * before we enable them as outputs.
-	 */
-	GPSR(GPIO48_nPOE) =
-		GPIO_bit(GPIO48_nPOE) |
-		GPIO_bit(GPIO49_nPWE) |
-		GPIO_bit(GPIO50_nPIOR) |
-		GPIO_bit(GPIO51_nPIOW) |
-		GPIO_bit(GPIO52_nPCE_1) |
-		GPIO_bit(GPIO53_nPCE_2);
-
-	pxa_gpio_mode(GPIO48_nPOE_MD);
-	pxa_gpio_mode(GPIO49_nPWE_MD);
-	pxa_gpio_mode(GPIO50_nPIOR_MD);
-	pxa_gpio_mode(GPIO51_nPIOW_MD);
-	pxa_gpio_mode(GPIO52_nPCE_1_MD);
-	pxa_gpio_mode(GPIO53_nPCE_2_MD);
-	pxa_gpio_mode(GPIO54_pSKTSEL_MD);
-	pxa_gpio_mode(GPIO55_nPREG_MD);
-	pxa_gpio_mode(GPIO56_nPWAIT_MD);
-	pxa_gpio_mode(GPIO57_nIOIS16_MD);
-#endif
+	if (platform_scoop_config->pcmcia_init)
+		platform_scoop_config->pcmcia_init();
 
 	/* Register interrupts */
-	if (scoop_devs[skt->nr].cd_irq >= 0) {
+	if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
 		struct pcmcia_irqs cd_irq;
 
 		cd_irq.sock = skt->nr;
-		cd_irq.irq  = scoop_devs[skt->nr].cd_irq;
-		cd_irq.str  = scoop_devs[skt->nr].cd_irq_str;
+		cd_irq.irq  = SCOOP_DEV[skt->nr].cd_irq;
+		cd_irq.str  = SCOOP_DEV[skt->nr].cd_irq_str;
 		ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1);
 
 		if (ret) {
@@ -83,19 +65,19 @@
 		}
 	}
 
-	skt->irq = scoop_devs[skt->nr].irq;
+	skt->irq = SCOOP_DEV[skt->nr].irq;
 
 	return 0;
 }
 
 static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-	if (scoop_devs[skt->nr].cd_irq >= 0) {
+	if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
 		struct pcmcia_irqs cd_irq;
 
 		cd_irq.sock = skt->nr;
-		cd_irq.irq  = scoop_devs[skt->nr].cd_irq;
-		cd_irq.str  = scoop_devs[skt->nr].cd_irq_str;
+		cd_irq.irq  = SCOOP_DEV[skt->nr].cd_irq;
+		cd_irq.str  = SCOOP_DEV[skt->nr].cd_irq_str;
 		soc_pcmcia_free_irqs(skt, &cd_irq, 1);
 	}
 }
@@ -105,9 +87,9 @@
 				    struct pcmcia_state *state)
 {
 	unsigned short cpr, csr;
-	struct device *scoop = scoop_devs[skt->nr].dev;
+	struct device *scoop = SCOOP_DEV[skt->nr].dev;
 
-	cpr = read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR);
+	cpr = read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR);
 
 	write_scoop_reg(scoop, SCOOP_IRM, 0x00FF);
 	write_scoop_reg(scoop, SCOOP_ISR, 0x0000);
@@ -116,21 +98,25 @@
 	if (csr & 0x0004) {
 		/* card eject */
 		write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
-		scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
+		SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
 	}
-	else if (!(scoop_devs[skt->nr].keep_vs & NO_KEEP_VS)) {
+	else if (!(SCOOP_DEV[skt->nr].keep_vs & NO_KEEP_VS)) {
 		/* keep vs1,vs2 */
 		write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
-		csr |= scoop_devs[skt->nr].keep_vs;
+		csr |= SCOOP_DEV[skt->nr].keep_vs;
 	}
 	else if (cpr & 0x0003) {
 		/* power on */
 		write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
-		scoop_devs[skt->nr].keep_vs = (csr & 0x00C0);
+		SCOOP_DEV[skt->nr].keep_vs = (csr & 0x00C0);
 	}
 	else {
 		/* card detect */
-		write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
+	        if ((machine_is_spitz() || machine_is_borzoi()) && skt->nr == 1) {
+	                write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+	        } else {
+		        write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
+	        }
 	}
 
 	state->detect = (csr & 0x0004) ? 0 : 1;
@@ -144,7 +130,6 @@
 	if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) {
 		printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr);
 	}
-
 }
 
 
@@ -152,7 +137,7 @@
 				       const socket_state_t *state)
 {
 	unsigned long flags;
-	struct device *scoop = scoop_devs[skt->nr].dev;
+	struct device *scoop = SCOOP_DEV[skt->nr].dev;
 
 	unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr;
 
@@ -177,8 +162,13 @@
 	nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080;
 	nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E;
 
-	ncpr |= (state->Vcc == 33) ? 0x0001 :
-				(state->Vcc == 50) ? 0x0002 : 0;
+	if ((machine_is_spitz() || machine_is_borzoi() || machine_is_akita()) && skt->nr == 0) {
+	        ncpr |= (state->Vcc == 33) ? 0x0002 :
+		        (state->Vcc == 50) ? 0x0002 : 0;
+	} else {
+	        ncpr |= (state->Vcc == 33) ? 0x0001 :
+		        (state->Vcc == 50) ? 0x0002 : 0;
+	}
 	nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0;
 	ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0;
 	nccr |= (state->flags&SS_RESET)? 0x0080: 0;
@@ -190,18 +180,22 @@
 			((skt->status&SS_WRPROT) ? 0x0008 : 0);
 
 	if (!(ncpr & 0x0003)) {
-		scoop_devs[skt->nr].keep_rd = 0;
-	} else if (!scoop_devs[skt->nr].keep_rd) {
+		SCOOP_DEV[skt->nr].keep_rd = 0;
+	} else if (!SCOOP_DEV[skt->nr].keep_rd) {
 		if (nccr & 0x0080)
-			scoop_devs[skt->nr].keep_rd = 1;
+			SCOOP_DEV[skt->nr].keep_rd = 1;
 		else
 			nccr |= 0x0080;
 	}
 
 	if (mcr != nmcr)
 		write_scoop_reg(scoop, SCOOP_MCR, nmcr);
-	if (cpr != ncpr)
-		write_scoop_reg(scoop, SCOOP_CPR, ncpr);
+	if (cpr != ncpr) {
+		if (platform_scoop_config->power_ctrl)
+			platform_scoop_config->power_ctrl(scoop, ncpr , skt->nr);
+		else
+		        write_scoop_reg(scoop, SCOOP_CPR, ncpr);
+	}
 	if (ccr != nccr)
 		write_scoop_reg(scoop, SCOOP_CCR, nccr);
 	if (imr != nimr)
@@ -214,43 +208,43 @@
 
 static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 {
-	sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
+	sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]);
 
 	/* Enable interrupt */
-	write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0);
-	write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101);
-	scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
+	write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_IMR, 0x00C0);
+	write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_MCR, 0x0101);
+	SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
 
 	if (machine_is_collie())
 		/* We need to disable SS_OUTPUT_ENA here. */
-		write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080);
+		write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080);
 }
 
 static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
 	/* CF_BUS_OFF */
-	sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
+	sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]);
 
 	if (machine_is_collie())
 		/* We need to disable SS_OUTPUT_ENA here. */
-		write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080);
+		write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080);
 }
 
 static struct pcmcia_low_level sharpsl_pcmcia_ops = {
-	.owner				= THIS_MODULE,
-	.hw_init			= sharpsl_pcmcia_hw_init,
-	.hw_shutdown		= sharpsl_pcmcia_hw_shutdown,
-	.socket_state		= sharpsl_pcmcia_socket_state,
-	.configure_socket	= sharpsl_pcmcia_configure_socket,
-	.socket_init		= sharpsl_pcmcia_socket_init,
-	.socket_suspend		= sharpsl_pcmcia_socket_suspend,
-	.first				= 0,
-	.nr					= 0,
+	.owner                  = THIS_MODULE,
+	.hw_init                = sharpsl_pcmcia_hw_init,
+	.hw_shutdown            = sharpsl_pcmcia_hw_shutdown,
+	.socket_state           = sharpsl_pcmcia_socket_state,
+	.configure_socket       = sharpsl_pcmcia_configure_socket,
+	.socket_init            = sharpsl_pcmcia_socket_init,
+	.socket_suspend         = sharpsl_pcmcia_socket_suspend,
+	.first                  = 0,
+	.nr                     = 0,
 };
 
-static struct platform_device *sharpsl_pcmcia_device;
-
 #ifdef CONFIG_SA1100_COLLIE
+#include "sa11xx_base.h"
+
 int __init pcmcia_collie_init(struct device *dev)
 {
        int ret = -ENODEV;
@@ -263,11 +257,13 @@
 
 #else
 
+static struct platform_device *sharpsl_pcmcia_device;
+
 static int __init sharpsl_pcmcia_init(void)
 {
 	int ret;
 
-	sharpsl_pcmcia_ops.nr=scoop_num;
+	sharpsl_pcmcia_ops.nr=platform_scoop_config->num_devs;
 	sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL);
 	if (!sharpsl_pcmcia_device)
 		return -ENOMEM;
@@ -275,7 +271,7 @@
 	memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device));
 	sharpsl_pcmcia_device->name = "pxa2xx-pcmcia";
 	sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
-	sharpsl_pcmcia_device->dev.parent=scoop_devs[0].dev;
+	sharpsl_pcmcia_device->dev.parent=platform_scoop_config->devs[0].dev;
 
 	ret = platform_device_register(sharpsl_pcmcia_device);
 	if (ret)
diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h
index 3b4da5a..f7bf45c 100644
--- a/drivers/s390/char/keyboard.h
+++ b/drivers/s390/char/keyboard.h
@@ -41,14 +41,14 @@
 /*
  * Helper Functions.
  */
-extern inline void
+static inline void
 kbd_put_queue(struct tty_struct *tty, int ch)
 {
 	tty_insert_flip_char(tty, ch, 0);
 	tty_schedule_flip(tty);
 }
 
-extern inline void
+static inline void
 kbd_puts_queue(struct tty_struct *tty, char *cp)
 {
 	while (*cp)
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 6b8aa6a..328e31c 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -265,7 +265,7 @@
 /*
  * Some instructions as assembly
  */
-extern __inline__ int 
+static inline int
 do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2)
 {
 	int cc;
@@ -300,7 +300,7 @@
 	return cc;
 }
 
-extern __inline__ int
+static inline int
 do_siga_input(unsigned int irq, unsigned int mask)
 {
 	int cc;
@@ -334,7 +334,7 @@
 	return cc;
 }
 
-extern __inline__ int
+static inline int
 do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb)
 {
 	int cc;
@@ -401,7 +401,7 @@
 	return cc;
 }
 
-extern __inline__ unsigned long
+static inline unsigned long
 do_clear_global_summary(void)
 {
 
diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c
index 04c2ef7..4010f2b 100644
--- a/drivers/s390/crypto/z90main.c
+++ b/drivers/s390/crypto/z90main.c
@@ -37,7 +37,6 @@
 #include <linux/kobject_uevent.h>
 #include <linux/proc_fs.h>
 #include <linux/syscalls.h>
-#include <linux/version.h>
 #include "z90crypt.h"
 #include "z90common.h"
 
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 1a1c3de..6b63d21 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -88,7 +88,6 @@
 #include <linux/tcp.h>
 #include <linux/timer.h>
 #include <linux/types.h>
-#include <linux/version.h>
 
 #include "cu3088.h"
 #include "claw.h"
diff --git a/drivers/s390/net/fsm.h b/drivers/s390/net/fsm.h
index 1b8a7e7..5b98253 100644
--- a/drivers/s390/net/fsm.h
+++ b/drivers/s390/net/fsm.h
@@ -140,7 +140,7 @@
  *              1  if current state or event is out of range
  *              !0 if state and event in range, but no action defined.
  */
-extern __inline__ int
+static inline int
 fsm_event(fsm_instance *fi, int event, void *arg)
 {
 	fsm_function_t r;
@@ -188,7 +188,7 @@
  * @param fi    Pointer to FSM
  * @param state The new state for this FSM.
  */
-extern __inline__ void
+static inline void
 fsm_newstate(fsm_instance *fi, int newstate)
 {
 	atomic_set(&fi->state,newstate);
@@ -208,7 +208,7 @@
  *
  * @return The current state of the FSM.
  */
-extern __inline__ int
+static inline int
 fsm_getstate(fsm_instance *fi)
 {
 	return atomic_read(&fi->state);
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 1c8ad2f..da8c515 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -8,7 +8,7 @@
  *    Author(s): Original Code written by
  *			  DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
  *		 Rewritten by
- *			  Frank Pavlic (pavlic@de.ibm.com) and
+ *			  Frank Pavlic (fpavlic@de.ibm.com) and
  *		 	  Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
  *    $Revision: 1.99 $	 $Date: 2005/05/11 08:10:17 $
@@ -2342,6 +2342,6 @@
 module_init(lcs_init_module);
 module_exit(lcs_cleanup_module);
 
-MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>");
+MODULE_AUTHOR("Frank Pavlic <fpavlic@de.ibm.com>");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 38a2441..d238c7e 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -8,6 +8,7 @@
 #include <linux/trdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/if_vlan.h>
+#include <linux/ctype.h>
 
 #include <net/ipv6.h>
 #include <linux/in6.h>
@@ -24,7 +25,7 @@
 
 #include "qeth_mpc.h"
 
-#define VERSION_QETH_H 		"$Revision: 1.142 $"
+#define VERSION_QETH_H 		"$Revision: 1.152 $"
 
 #ifdef CONFIG_QETH_IPV6
 #define QETH_VERSION_IPV6 	":IPv6"
@@ -718,8 +719,6 @@
 	atomic_t refcnt;
 };
 
-#define QETH_BROADCAST_WITH_ECHO    1
-#define QETH_BROADCAST_WITHOUT_ECHO 2
 
 struct qeth_card_blkt {
 	int time_total;
@@ -727,8 +726,10 @@
 	int inter_packet_jumbo;
 };
 
-
-
+#define QETH_BROADCAST_WITH_ECHO    0x01
+#define QETH_BROADCAST_WITHOUT_ECHO 0x02
+#define QETH_LAYER2_MAC_READ	    0x01
+#define QETH_LAYER2_MAC_REGISTERED  0x02
 struct qeth_card_info {
 	unsigned short unit_addr2;
 	unsigned short cula;
@@ -736,7 +737,7 @@
 	__u16 func_level;
 	char mcl_level[QETH_MCL_LENGTH + 1];
 	int guestlan;
-	int layer2_mac_registered;
+	int mac_bits;
 	int portname_required;
 	int portno;
 	char portname[9];
@@ -749,6 +750,7 @@
 	int unique_id;
 	struct qeth_card_blkt blkt;
 	__u32 csum_mask;
+	enum qeth_ipa_promisc_modes promisc_mode;
 };
 
 struct qeth_card_options {
@@ -775,6 +777,7 @@
 enum qeth_threads {
 	QETH_SET_IP_THREAD  = 1,
 	QETH_RECOVER_THREAD = 2,
+	QETH_SET_PROMISC_MODE_THREAD = 4,
 };
 
 struct qeth_osn_info {
@@ -1074,6 +1077,26 @@
 	}
 }
 
+static inline int
+qeth_isdigit(char * buf)
+{
+	while (*buf) {
+		if (!isdigit(*buf++))
+			return 0;
+	}
+	return 1;
+}
+
+static inline int
+qeth_isxdigit(char * buf)
+{
+	while (*buf) {
+		if (!isxdigit(*buf++))
+			return 0;
+	}
+	return 1;
+}
+
 static inline void
 qeth_ipaddr4_to_string(const __u8 *addr, char *buf)
 {
@@ -1090,18 +1113,27 @@
 	int i;
 
 	start = buf;
-	for (i = 0; i < 3; i++) {
-		if (!(end = strchr(start, '.')))
+	for (i = 0; i < 4; i++) {
+		if (i == 3) {
+			end = strchr(start,0xa);
+			if (end)
+				len = end - start;
+			else		
+				len = strlen(start);
+		}
+		else {
+			end = strchr(start, '.');
+			len = end - start;
+		}
+		if ((len <= 0) || (len > 3))
 			return -EINVAL;
-		len = end - start;
 		memset(abuf, 0, 4);
 		strncpy(abuf, start, len);
+		if (!qeth_isdigit(abuf))
+			return -EINVAL;
 		addr[i] = simple_strtoul(abuf, &tmp, 10);
 		start = end + 1;
 	}
-	memset(abuf, 0, 4);
-	strcpy(abuf, start);
-	addr[3] = simple_strtoul(abuf, &tmp, 10);
 	return 0;
 }
 
@@ -1128,18 +1160,27 @@
 
 	tmp_addr = (u16 *)addr;
 	start = buf;
-	for (i = 0; i < 7; i++) {
-		if (!(end = strchr(start, ':')))
+	for (i = 0; i < 8; i++) {
+		if (i == 7) {
+			end = strchr(start,0xa);
+			if (end)
+				len = end - start;
+			else
+				len = strlen(start);
+		}
+		else {
+			end = strchr(start, ':');
+			len = end - start;
+		}
+		if ((len <= 0) || (len > 4))
 			return -EINVAL;
-		len = end - start;
 		memset(abuf, 0, 5);
 		strncpy(abuf, start, len);
+		if (!qeth_isxdigit(abuf))
+			return -EINVAL;
 		tmp_addr[i] = simple_strtoul(abuf, &tmp, 16);
 		start = end + 1;
 	}
-	memset(abuf, 0, 5);
-	strcpy(abuf, start);
-	tmp_addr[7] = simple_strtoul(abuf, &tmp, 16);
 	return 0;
 }
 
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 692003c..99cceb2 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth_main.c ($Revision: 1.224 $)
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.242 $)
  *
  * Linux on zSeries OSA Express and HiperSockets support
  *
@@ -9,10 +9,10 @@
  *    Author(s): Original Code written by
  *			  Utz Bacher (utz.bacher@de.ibm.com)
  *		 Rewritten by
- *			  Frank Pavlic (pavlic@de.ibm.com) and
+ *			  Frank Pavlic (fpavlic@de.ibm.com) and
  *		 	  Thomas Spatzier <tspat@de.ibm.com>
  *
- *    $Revision: 1.224 $	 $Date: 2005/05/04 20:19:18 $
+ *    $Revision: 1.242 $	 $Date: 2005/05/04 20:19:18 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -72,7 +72,7 @@
 #include "qeth_eddp.h"
 #include "qeth_tso.h"
 
-#define VERSION_QETH_C "$Revision: 1.224 $"
+#define VERSION_QETH_C "$Revision: 1.242 $"
 static const char *version = "qeth S/390 OSA-Express driver";
 
 /**
@@ -160,6 +160,9 @@
 qeth_set_multicast_list(struct net_device *);
 
 static void
+qeth_setadp_promisc_mode(struct qeth_card *);
+
+static void
 qeth_notify_processes(void)
 {
 	/*notify all  registered processes */
@@ -602,11 +605,20 @@
 	int found = 0;
 
 	list_for_each_entry(addr, &card->ip_list, entry) {
+		if (card->options.layer2) {
+			if ((addr->type == todo->type) &&
+			    (memcmp(&addr->mac, &todo->mac, 
+				    OSA_ADDR_LEN) == 0)) {
+				found = 1;
+				break;
+			}
+			continue;
+		} 
 		if ((addr->proto     == QETH_PROT_IPV4)  &&
 		    (todo->proto     == QETH_PROT_IPV4)  &&
 		    (addr->type      == todo->type)      &&
 		    (addr->u.a4.addr == todo->u.a4.addr) &&
-		    (addr->u.a4.mask == todo->u.a4.mask)   ){
+		    (addr->u.a4.mask == todo->u.a4.mask)) {
 			found = 1;
 			break;
 		}
@@ -615,12 +627,12 @@
 		    (addr->type        == todo->type)         &&
 		    (addr->u.a6.pfxlen == todo->u.a6.pfxlen)  &&
 		    (memcmp(&addr->u.a6.addr, &todo->u.a6.addr,
-			    sizeof(struct in6_addr)) == 0))     {
+			    sizeof(struct in6_addr)) == 0)) {
 			found = 1;
 			break;
 		}
 	}
-	if (found){
+	if (found) {
 		addr->users += todo->users;
 		if (addr->users <= 0){
 			*__addr = addr;
@@ -632,7 +644,7 @@
 			return 0;
 		}
 	}
-	if (todo->users > 0){
+	if (todo->users > 0) {
 		/* for VIPA and RXIP limit refcount to 1 */
 		if (todo->type != QETH_IP_TYPE_NORMAL)
 			todo->users = 1;
@@ -682,12 +694,22 @@
 		if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) &&
 		    (tmp->type == QETH_IP_TYPE_DEL_ALL_MC))
 			return 0;
+		if (card->options.layer2) {
+			if ((tmp->type	== addr->type)	&&
+			    (tmp->is_multicast == addr->is_multicast) &&
+			    (memcmp(&tmp->mac, &addr->mac, 
+				    OSA_ADDR_LEN) == 0)) {
+				found = 1;
+				break;
+			}
+			continue;
+		} 	 
 		if ((tmp->proto        == QETH_PROT_IPV4)     &&
 		    (addr->proto       == QETH_PROT_IPV4)     &&
 		    (tmp->type         == addr->type)         &&
 		    (tmp->is_multicast == addr->is_multicast) &&
 		    (tmp->u.a4.addr    == addr->u.a4.addr)    &&
-		    (tmp->u.a4.mask    == addr->u.a4.mask)      ){
+		    (tmp->u.a4.mask    == addr->u.a4.mask)) {
 			found = 1;
 			break;
 		}
@@ -697,7 +719,7 @@
 		    (tmp->is_multicast == addr->is_multicast)  &&
 		    (tmp->u.a6.pfxlen  == addr->u.a6.pfxlen)   &&
 		    (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr,
-			    sizeof(struct in6_addr)) == 0)        ){
+			    sizeof(struct in6_addr)) == 0)) {
 			found = 1;
 			break;
 		}
@@ -707,7 +729,7 @@
 			tmp->users += addr->users;
 		else
 			tmp->users += add? 1:-1;
-		if (tmp->users == 0){
+		if (tmp->users == 0) {
 			list_del(&tmp->entry);
 			kfree(tmp);
 		}
@@ -738,12 +760,15 @@
 	unsigned long flags;
 	int rc = 0;
 
-	QETH_DBF_TEXT(trace,4,"delip");
-	if (addr->proto == QETH_PROT_IPV4)
-		QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
+	QETH_DBF_TEXT(trace, 4, "delip");
+
+	if (card->options.layer2)
+		QETH_DBF_HEX(trace, 4, &addr->mac, 6);
+	else if (addr->proto == QETH_PROT_IPV4)
+		QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4);
 	else {
-		QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8);
-		QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8);
+		QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8);
+		QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8);
 	}
 	spin_lock_irqsave(&card->ip_lock, flags);
 	rc = __qeth_insert_ip_todo(card, addr, 0);
@@ -757,12 +782,14 @@
 	unsigned long flags;
 	int rc = 0;
 
-	QETH_DBF_TEXT(trace,4,"addip");
-	if (addr->proto == QETH_PROT_IPV4)
-		QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
+	QETH_DBF_TEXT(trace, 4, "addip");
+	if (card->options.layer2)
+		QETH_DBF_HEX(trace, 4, &addr->mac, 6);
+	else if (addr->proto == QETH_PROT_IPV4)
+		QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4);
 	else {
-		QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8);
-		QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8);
+		QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8);
+		QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8);
 	}
 	spin_lock_irqsave(&card->ip_lock, flags);
 	rc = __qeth_insert_ip_todo(card, addr, 1);
@@ -775,7 +802,7 @@
 {
 	struct qeth_ipaddr *addr, *tmp;
 	int rc;
-
+again:
 	list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) {
 		if (addr->is_multicast) {
 			spin_unlock_irqrestore(&card->ip_lock, *flags);
@@ -784,6 +811,7 @@
 			if (!rc) {
 				list_del(&addr->entry);
 				kfree(addr);
+				goto again;
 			}
 		}
 	}
@@ -851,6 +879,7 @@
 
 static void qeth_delete_mc_addresses(struct qeth_card *);
 static void qeth_add_multicast_ipv4(struct qeth_card *);
+static void qeth_layer2_add_multicast(struct qeth_card *);
 #ifdef CONFIG_QETH_IPV6
 static void qeth_add_multicast_ipv6(struct qeth_card *);
 #endif
@@ -939,6 +968,24 @@
 	return 0;
 }
 
+/*
+ * Drive the SET_PROMISC_MODE thread
+ */
+static int
+qeth_set_promisc_mode(void *ptr)
+{
+	struct qeth_card *card = (struct qeth_card *) ptr;
+
+	daemonize("qeth_setprm");
+	QETH_DBF_TEXT(trace,4,"setprm1");
+	if (!qeth_do_run_thread(card, QETH_SET_PROMISC_MODE_THREAD))
+		return 0;
+	QETH_DBF_TEXT(trace,4,"setprm2");
+	qeth_setadp_promisc_mode(card);
+	qeth_clear_thread_running_bit(card, QETH_SET_PROMISC_MODE_THREAD);
+	return 0;
+}
+
 static int
 qeth_recover(void *ptr)
 {
@@ -1005,6 +1052,8 @@
 
 	if (qeth_do_start_thread(card, QETH_SET_IP_THREAD))
 		kernel_thread(qeth_register_ip_addresses, (void *)card,SIGCHLD);
+	if (qeth_do_start_thread(card, QETH_SET_PROMISC_MODE_THREAD))
+		kernel_thread(qeth_set_promisc_mode, (void *)card, SIGCHLD);
 	if (qeth_do_start_thread(card, QETH_RECOVER_THREAD))
 		kernel_thread(qeth_recover, (void *) card, SIGCHLD);
 }
@@ -3749,7 +3798,7 @@
 
 	if ( (card->info.type != QETH_CARD_TYPE_OSN) &&
 	     (card->options.layer2) &&
-	     (!card->info.layer2_mac_registered)) {
+	     (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))) {
 		QETH_DBF_TEXT(trace,4,"nomacadr");
 		return -EPERM;
 	}
@@ -4311,6 +4360,8 @@
 out:
 	if (flush_count)
 		qeth_flush_buffers(queue, 0, start_index, flush_count);
+	else if (!atomic_read(&queue->set_pci_flags_count))
+		atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH);
 	/*
 	 * queue->state will go from LOCKED -> UNLOCKED or from
 	 * LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us
@@ -4975,6 +5026,10 @@
 			    unsigned long);
 
 static int
+qeth_default_setadapterparms_cb(struct qeth_card *card,
+                                struct qeth_reply *reply,
+                                unsigned long data);
+static int
 qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *,
 		      __u16, long,
 		      int (*reply_cb)
@@ -5301,8 +5356,7 @@
 	struct qeth_ipaddr *addr;
 
 	QETH_DBF_TEXT(trace, 4, "frvaddr4");
-	if (!card->vlangrp)
-		return;
+
 	rcu_read_lock();
 	in_dev = __in_dev_get_rcu(card->vlangrp->vlan_devices[vid]);
 	if (!in_dev)
@@ -5330,8 +5384,7 @@
 	struct qeth_ipaddr *addr;
 
 	QETH_DBF_TEXT(trace, 4, "frvaddr6");
-	if (!card->vlangrp)
-		return;
+
 	in6_dev = in6_dev_get(card->vlangrp->vlan_devices[vid]);
 	if (!in6_dev)
 		return;
@@ -5351,10 +5404,38 @@
 }
 
 static void
+qeth_free_vlan_addresses(struct qeth_card *card, unsigned short vid)
+{
+	if (card->options.layer2 || !card->vlangrp)
+		return;
+	qeth_free_vlan_addresses4(card, vid);
+	qeth_free_vlan_addresses6(card, vid);
+}
+
+static int
+qeth_layer2_send_setdelvlan_cb(struct qeth_card *card,
+                               struct qeth_reply *reply,
+                               unsigned long data)
+{
+        struct qeth_ipa_cmd *cmd;
+
+        QETH_DBF_TEXT(trace, 2, "L2sdvcb");
+        cmd = (struct qeth_ipa_cmd *) data;
+        if (cmd->hdr.return_code) {
+		PRINT_ERR("Error in processing VLAN %i on %s: 0x%x. "
+			  "Continuing\n",cmd->data.setdelvlan.vlan_id, 
+			  QETH_CARD_IFNAME(card), cmd->hdr.return_code);
+		QETH_DBF_TEXT_(trace, 2, "L2VL%4x", cmd->hdr.command);
+		QETH_DBF_TEXT_(trace, 2, "L2%s", CARD_BUS_ID(card));
+		QETH_DBF_TEXT_(trace, 2, "err%d", cmd->hdr.return_code);
+	}
+        return 0;
+}
+
+static int
 qeth_layer2_send_setdelvlan(struct qeth_card *card, __u16 i,
 			    enum qeth_ipa_cmds ipacmd)
 {
- 	int rc;
 	struct qeth_ipa_cmd *cmd;
 	struct qeth_cmd_buffer *iob;
 
@@ -5362,15 +5443,8 @@
 	iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
 	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
         cmd->data.setdelvlan.vlan_id = i;
-
-	rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
-        if (rc) {
-                PRINT_ERR("Error in processing VLAN %i on %s: 0x%x. "
-			  "Continuing\n",i, QETH_CARD_IFNAME(card), rc);
-		QETH_DBF_TEXT_(trace, 2, "L2VL%4x", ipacmd);
-		QETH_DBF_TEXT_(trace, 2, "L2%s", CARD_BUS_ID(card));
-		QETH_DBF_TEXT_(trace, 2, "err%d", rc);
-        }
+	return qeth_send_ipa_cmd(card, iob, 
+				 qeth_layer2_send_setdelvlan_cb, NULL);
 }
 
 static void
@@ -5420,8 +5494,7 @@
 	qeth_free_vlan_skbs(card, vid);
 	spin_lock_irqsave(&card->vlanlock, flags);
 	/* unregister IP addresses of vlan device */
-	qeth_free_vlan_addresses4(card, vid);
-	qeth_free_vlan_addresses6(card, vid);
+	qeth_free_vlan_addresses(card, vid);
 	if (card->vlangrp)
 		card->vlangrp->vlan_devices[vid] = NULL;
 	spin_unlock_irqrestore(&card->vlanlock, flags);
@@ -5430,6 +5503,59 @@
 	qeth_set_multicast_list(card->dev);
 }
 #endif
+/**
+ * Examine hardware response to SET_PROMISC_MODE
+ */
+static int
+qeth_setadp_promisc_mode_cb(struct qeth_card *card, 
+			    struct qeth_reply *reply,
+			    unsigned long data)
+{
+	struct qeth_ipa_cmd *cmd;
+	struct qeth_ipacmd_setadpparms *setparms;
+
+	QETH_DBF_TEXT(trace,4,"prmadpcb");
+
+	cmd = (struct qeth_ipa_cmd *) data;
+	setparms = &(cmd->data.setadapterparms);
+	
+        qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
+	if (cmd->hdr.return_code) { 
+		QETH_DBF_TEXT_(trace,4,"prmrc%2.2x",cmd->hdr.return_code);	
+		setparms->data.mode = SET_PROMISC_MODE_OFF;
+	}
+	card->info.promisc_mode = setparms->data.mode;
+	return 0;
+}
+/*
+ * Set promiscuous mode (on or off) (SET_PROMISC_MODE command)
+ */
+static void
+qeth_setadp_promisc_mode(struct qeth_card *card)
+{
+	enum qeth_ipa_promisc_modes mode;
+	struct net_device *dev = card->dev;
+	struct qeth_cmd_buffer *iob;
+	struct qeth_ipa_cmd *cmd;
+
+	QETH_DBF_TEXT(trace, 4, "setprom");
+
+	if (((dev->flags & IFF_PROMISC) &&
+	     (card->info.promisc_mode == SET_PROMISC_MODE_ON)) ||
+	    (!(dev->flags & IFF_PROMISC) &&
+	     (card->info.promisc_mode == SET_PROMISC_MODE_OFF)))
+		return;
+	mode = SET_PROMISC_MODE_OFF;
+	if (dev->flags & IFF_PROMISC)
+		mode = SET_PROMISC_MODE_ON;
+	QETH_DBF_TEXT_(trace, 4, "mode:%x", mode);
+
+	iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_PROMISC_MODE,
+			sizeof(struct qeth_ipacmd_setadpparms));
+	cmd = (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
+	cmd->data.setadapterparms.data.mode = mode;
+	qeth_send_ipa_cmd(card, iob, qeth_setadp_promisc_mode_cb, NULL);
+}
 
 /**
  * set multicast address on card
@@ -5444,12 +5570,22 @@
 	 
 	QETH_DBF_TEXT(trace,3,"setmulti");
 	qeth_delete_mc_addresses(card);
+	if (card->options.layer2) {
+		qeth_layer2_add_multicast(card);
+		goto out;
+	}
 	qeth_add_multicast_ipv4(card);
 #ifdef CONFIG_QETH_IPV6
 	qeth_add_multicast_ipv6(card);
 #endif
+out:
  	if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
 		schedule_work(&card->kernel_thread_starter);
+	if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
+		return;
+	if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0)
+		schedule_work(&card->kernel_thread_starter);
+
 }
 
 static int
@@ -5657,6 +5793,24 @@
 	in_dev_put(in4_dev);
 }
 
+static void
+qeth_layer2_add_multicast(struct qeth_card *card)
+{
+	struct qeth_ipaddr *ipm;
+	struct dev_mc_list *dm;
+
+	QETH_DBF_TEXT(trace,4,"L2addmc");
+	for (dm = card->dev->mc_list; dm; dm = dm->next) {
+		ipm = qeth_get_addr_buffer(QETH_PROT_IPV4);
+		if (!ipm)
+			continue;
+		memcpy(ipm->mac,dm->dmi_addr,MAX_ADDR_LEN);
+		ipm->is_multicast = 1;
+		if (!qeth_add_ip(card, ipm))
+			kfree(ipm);
+	}
+}
+
 #ifdef CONFIG_QETH_IPV6
 static inline void
 qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
@@ -5825,10 +5979,10 @@
 		PRINT_WARN("Error in registering MAC address on " \
 			   "device %s: x%x\n", CARD_BUS_ID(card),
 			   cmd->hdr.return_code);
-		card->info.layer2_mac_registered = 0;
+		card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
 		cmd->hdr.return_code = -EIO;
 	} else {
-		card->info.layer2_mac_registered = 1;
+		card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
 		memcpy(card->dev->dev_addr,cmd->data.setdelmac.mac,
 		       OSA_ADDR_LEN);
 		PRINT_INFO("MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
@@ -5866,7 +6020,7 @@
 		cmd->hdr.return_code = -EIO;
 		return 0;
 	}
-	card->info.layer2_mac_registered = 0;
+	card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
 
 	return 0;
 }
@@ -5874,7 +6028,7 @@
 qeth_layer2_send_delmac(struct qeth_card *card, __u8 *mac)
 {
 	QETH_DBF_TEXT(trace, 2, "L2Delmac");
-	if (!card->info.layer2_mac_registered)
+	if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
 		return 0;
 	return qeth_layer2_send_setdelmac(card, mac, IPA_CMD_DELVMAC,
 					  qeth_layer2_send_delmac_cb);
@@ -5896,7 +6050,7 @@
 	card = (struct qeth_card *) dev->priv;
 
 	if (!card->options.layer2) {
-		PRINT_WARN("Setting MAC address on %s is not supported"
+		PRINT_WARN("Setting MAC address on %s is not supported "
 			   "in Layer 3 mode.\n", dev->name);
 		QETH_DBF_TEXT(trace, 3, "setmcLY3");
 		return -EOPNOTSUPP;
@@ -6441,6 +6595,8 @@
 	return 0;
 }
 
+
+
 static int
 qeth_query_setadapterparms_cb(struct qeth_card *card, struct qeth_reply *reply,
 			      unsigned long data)
@@ -6481,8 +6637,13 @@
 	QETH_DBF_TEXT(trace,4,"chgmaccb");
 
 	cmd = (struct qeth_ipa_cmd *) data;
-	memcpy(card->dev->dev_addr,
-	       &cmd->data.setadapterparms.data.change_addr.addr,OSA_ADDR_LEN);
+	if (!card->options.layer2 || card->info.guestlan ||
+	    !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {	
+		memcpy(card->dev->dev_addr,
+		       &cmd->data.setadapterparms.data.change_addr.addr,
+		       OSA_ADDR_LEN);
+		card->info.mac_bits |= QETH_LAYER2_MAC_READ;
+	}
 	qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
 	return 0;
 }
@@ -6602,6 +6763,12 @@
         QETH_DBF_TEXT(setup, 2, "doL2init");
         QETH_DBF_TEXT_(setup, 2, "doL2%s", CARD_BUS_ID(card));
 
+	rc = qeth_query_setadapterparms(card);
+	if (rc) {
+		PRINT_WARN("could not query adapter parameters on device %s: "
+			   "x%x\n", CARD_BUS_ID(card), rc);
+	}
+
 	rc = qeth_setadpparms_change_macaddr(card);
 	if (rc) {
 		PRINT_WARN("couldn't get MAC address on "
@@ -8548,7 +8715,7 @@
 EXPORT_SYMBOL(qeth_osn_assist);
 module_init(qeth_init);
 module_exit(qeth_exit);
-MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>");
+MODULE_AUTHOR("Frank Pavlic <fpavlic@de.ibm.com>");
 MODULE_DESCRIPTION("Linux on zSeries OSA Express and HiperSockets support\n" \
 		                      "Copyright 2000,2003 IBM Corporation\n");
 
diff --git a/drivers/s390/net/qeth_mpc.c b/drivers/s390/net/qeth_mpc.c
index 30e053d..f0a080a 100644
--- a/drivers/s390/net/qeth_mpc.c
+++ b/drivers/s390/net/qeth_mpc.c
@@ -4,7 +4,7 @@
  * Linux on zSeries OSA Express and HiperSockets support
  *
  * Copyright 2000,2003 IBM Corporation
- * Author(s): Frank Pavlic <pavlic@de.ibm.com>
+ * Author(s): Frank Pavlic <fpavlic@de.ibm.com>
  * 	      Thomas Spatzier <tspat@de.ibm.com>
  *
  */
diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h
index 7edc5f1..5f71486 100644
--- a/drivers/s390/net/qeth_mpc.h
+++ b/drivers/s390/net/qeth_mpc.h
@@ -6,7 +6,7 @@
  * Copyright 2000,2003 IBM Corporation
  * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
  *            Thomas Spatzier <tspat@de.ibm.com>
- *            Frank Pavlic <pavlic@de.ibm.com>
+ *            Frank Pavlic <fpavlic@de.ibm.com>
  *
  */
 #ifndef __QETH_MPC_H__
@@ -14,7 +14,7 @@
 
 #include <asm/qeth.h>
 
-#define VERSION_QETH_MPC_H "$Revision: 1.43 $"
+#define VERSION_QETH_MPC_H "$Revision: 1.44 $"
 
 extern const char *VERSION_QETH_MPC_C;
 
@@ -217,7 +217,7 @@
 	IPA_SETADP_SEND_OSA_MESSAGE 		= 0x0100,
 	IPA_SETADP_SET_SNMP_CONTROL 		= 0x0200,
 	IPA_SETADP_READ_SNMP_PARMS 		= 0x0400,
-	IPA_SETADP_WRITE_SNMP_PARMS 		= 0x0800,
+	IPA_SETADP_SET_PROMISC_MODE		= 0x0800,
 	IPA_SETADP_QUERY_CARD_INFO 		= 0x1000,
 };
 enum qeth_ipa_mac_ops {
@@ -232,9 +232,12 @@
 	CHANGE_ADDR_ADD_ADDR 		= 1,
 	CHANGE_ADDR_DEL_ADDR 		= 2,
 	CHANGE_ADDR_FLUSH_ADDR_TABLE 	= 4,
-
-
 };
+enum qeth_ipa_promisc_modes {
+	SET_PROMISC_MODE_OFF		= 0,
+	SET_PROMISC_MODE_ON		= 1,
+};
+
 /* (SET)DELIP(M) IPA stuff ***************************************************/
 struct qeth_ipacmd_setdelip4 {
 	__u8   ip_addr[4];
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index f91a02d..ddd6019 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.55 $)
+ * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.58 $)
  *
  * Linux on zSeries OSA Express and HiperSockets support
  * This file contains code related to sysfs.
@@ -8,7 +8,7 @@
  * Copyright 2000,2003 IBM Corporation
  *
  * Author(s): Thomas Spatzier <tspat@de.ibm.com>
- * 	      Frank Pavlic <pavlic@de.ibm.com>
+ * 	      Frank Pavlic <fpavlic@de.ibm.com>
  *
  */
 #include <linux/list.h>
@@ -20,7 +20,7 @@
 #include "qeth_mpc.h"
 #include "qeth_fs.h"
 
-const char *VERSION_QETH_SYS_C = "$Revision: 1.55 $";
+const char *VERSION_QETH_SYS_C = "$Revision: 1.58 $";
 
 /*****************************************************************************/
 /*                                                                           */
@@ -1117,7 +1117,7 @@
 	start = buf;
 	/* get address string */
 	end = strchr(start, '/');
-	if (!end){
+	if (!end || (end-start >= 49)){
 		PRINT_WARN("Invalid format for ipato_addx/delx. "
 			   "Use <ip addr>/<mask bits>\n");
 		return -EINVAL;
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
index ad33e6f..e245af3 100644
--- a/drivers/s390/net/qeth_tso.h
+++ b/drivers/s390/net/qeth_tso.h
@@ -5,7 +5,7 @@
  *
  * Copyright 2004 IBM Corporation
  *
- *    Author(s): Frank Pavlic <pavlic@de.ibm.com>
+ *    Author(s): Frank Pavlic <fpavlic@de.ibm.com>
  *
  *    $Revision: 1.7 $	 $Date: 2005/05/04 20:19:18 $
  *
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h
index 4eaa701..d9ea7ed 100644
--- a/drivers/s390/s390mach.h
+++ b/drivers/s390/s390mach.h
@@ -88,7 +88,7 @@
 #define CRW_ERC_PERRI    0x07 /* perm. error, facility init */
 #define CRW_ERC_PMOD     0x08 /* installed parameters modified */
 
-extern __inline__ int stcrw(struct crw *pcrw )
+static inline int stcrw(struct crw *pcrw )
 {
         int ccode;
 
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index 071ae24..fd2cc77 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -407,7 +407,7 @@
 	case WIOCGSTAT:
 		lock_kernel();
 		rval = wd_ioctl(file->f_dentry->d_inode, file, cmd, arg);
-		lock_kernel();
+		unlock_kernel();
 		break;
 	/* everything else is handled by the generic compat layer */
 	default:
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index 39f5421..c3a51d1 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -119,7 +119,7 @@
 {
 	__u8 regs = readb(d7s_regs);
 	__u8 ireg = 0;
-	int error = 0
+	int error = 0;
 
 	if (D7S_MINOR != iminor(file->f_dentry->d_inode))
 		return -ENODEV;
@@ -161,7 +161,7 @@
 		writeb(regs, d7s_regs);
 		break;
 	};
-	lock_kernel();
+	unlock_kernel();
 
 	return error;
 }
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 5028ac2..383a95f 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -596,6 +596,8 @@
 		lock_kernel();
 		break;
 	}
+
+	return rval;
 }
 
 static int openprom_open(struct inode * inode, struct file * file)
@@ -623,6 +625,7 @@
 	.owner =	THIS_MODULE,
 	.llseek =	no_llseek,
 	.ioctl =	openprom_ioctl,
+	.compat_ioctl =	openprom_compat_ioctl,
 	.open =		openprom_open,
 	.release =	openprom_release,
 };
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
index 9b988ba..5774bdd 100644
--- a/drivers/sbus/char/rtc.c
+++ b/drivers/sbus/char/rtc.c
@@ -210,6 +210,27 @@
 	}
 }
 
+static long rtc_compat_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	int rval = -ENOIOCTLCMD;
+
+	switch (cmd) {
+	/*
+	 * These two are specific to this driver, the generic rtc ioctls
+	 * are hanlded elsewhere.
+	 */
+	case RTCGET:
+	case RTCSET:
+		lock_kernel();
+		rval = rtc_ioctl(file->f_dentry->d_inode, file, cmd, arg);
+		unlock_kernel();
+		break;
+	}
+
+	return rval;
+}
+
 static int rtc_open(struct inode *inode, struct file *file)
 {
 	int ret;
@@ -237,6 +258,7 @@
 	.owner =	THIS_MODULE,
 	.llseek =	no_llseek,
 	.ioctl =	rtc_ioctl,
+	.compat_ioctl =	rtc_compat_ioctl,
 	.open =		rtc_open,
 	.release =	rtc_release,
 };
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 98bad77..4f81fc3 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -54,7 +54,6 @@
 #ifndef _3W_XXXX_H
 #define _3W_XXXX_H
 
-#include <linux/version.h>
 #include <linux/types.h>
 
 /* AEN strings */
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index 7a33c70..9cb5dd4 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -343,7 +343,7 @@
 /* Size of event list (per host adapter) */
 static int track_events = 0;
 static struct Scsi_Host *first_host = NULL;	/* Head of list of NCR boards */
-static Scsi_Host_Template *the_template = NULL;	
+static struct scsi_host_template *the_template = NULL;
 
 /* NCR53c710 script handling code */
 
@@ -1103,7 +1103,7 @@
 }
 
 /* 
- * Function : int ncr53c7xx_init(Scsi_Host_Template *tpnt, int board, int chip,
+ * Function : int ncr53c7xx_init(struct scsi_host_template *tpnt, int board, int chip,
  *	unsigned long base, int io_port, int irq, int dma, long long options,
  *	int clock);
  *
@@ -1118,7 +1118,7 @@
  */
 
 int 
-ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
+ncr53c7xx_init (struct scsi_host_template *tpnt, int board, int chip,
     unsigned long base, int io_port, int irq, int dma, 
     long long options, int clock)
 {
diff --git a/drivers/scsi/53c7xx.h b/drivers/scsi/53c7xx.h
index d9098bd..218f3b9 100644
--- a/drivers/scsi/53c7xx.h
+++ b/drivers/scsi/53c7xx.h
@@ -1600,7 +1600,7 @@
 /* Paranoid people could use panic() here. */
 #define FATAL(host) shutdown((host));
 
-extern int ncr53c7xx_init(Scsi_Host_Template *tpnt, int board, int chip,
+extern int ncr53c7xx_init(struct scsi_host_template *tpnt, int board, int chip,
 			  unsigned long base, int io_port, int irq, int dma,
 			  long long options, int clock);
 
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index afeca32..84c42c4 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1295,27 +1295,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called qlogicfas.
 
-config SCSI_QLOGIC_ISP
-	tristate "Qlogic ISP SCSI support (old driver)"
-	depends on PCI && SCSI && BROKEN
-	---help---
-	  This driver works for all QLogic PCI SCSI host adapters (IQ-PCI,
-	  IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card.  (This latter
-	  card is supported by the "AM53/79C974 PCI SCSI" driver.)
-
-	  If you say Y here, make sure to choose "BIOS" at the question "PCI
-	  access mode".
-
-	  Please read the file <file:Documentation/scsi/qlogicisp.txt>.  You
-	  should also read the SCSI-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called qlogicisp.
-
-	  These days the hardware is also supported by the more modern qla1280
-	  driver.  In doubt use that one instead of qlogicisp.
-
 config SCSI_QLOGIC_FC
 	tristate "Qlogic ISP FC SCSI support"
 	depends on PCI && SCSI
@@ -1342,14 +1321,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called qla1280.
 
-config SCSI_QLOGIC_1280_1040
-	bool "Qlogic QLA 1020/1040 SCSI support"
-	depends on SCSI_QLOGIC_1280 && SCSI_QLOGIC_ISP!=y
-	help
-	  Say Y here if you have a QLogic ISP1020/1040 SCSI host adapter and
-	  do not want to use the old driver.  This option enables support in
-	  the qla1280 driver for those host adapters.
-
 config SCSI_QLOGICPTI
 	tristate "PTI Qlogic, ISP Driver"
 	depends on SBUS && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index b88b8c4..f062ea0 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -78,7 +78,6 @@
 obj-$(CONFIG_SCSI_SYM53C416)	+= sym53c416.o
 obj-$(CONFIG_SCSI_QLOGIC_FAS)	+= qlogicfas408.o	qlogicfas.o
 obj-$(CONFIG_PCMCIA_QLOGIC)	+= qlogicfas408.o
-obj-$(CONFIG_SCSI_QLOGIC_ISP)	+= qlogicisp.o 
 obj-$(CONFIG_SCSI_QLOGIC_FC)	+= qlogicfc.o 
 obj-$(CONFIG_SCSI_QLOGIC_1280)	+= qla1280.o 
 obj-$(CONFIG_SCSI_QLA2XXX)	+= qla2xxx/
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 26146a4..640590b 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -529,7 +529,7 @@
 /* Allocate structure and insert basic data such as SCSI chip frequency
  * data and a pointer to the device
  */
-struct NCR_ESP* esp_allocate(Scsi_Host_Template *tpnt, void *esp_dev)
+struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev)
 {
 	struct NCR_ESP *esp, *elink;
 	struct Scsi_Host *esp_host;
@@ -1006,7 +1006,7 @@
 	struct ESP_regs *eregs = esp->eregs;
 	struct esp_device *esp_dev;
 	Scsi_Cmnd *SCptr;
-	Scsi_Device *SDptr;
+	struct scsi_device *SDptr;
 	volatile unchar *cmdp = esp->esp_command;
 	unsigned char the_esp_command;
 	int lun, target;
@@ -1687,7 +1687,7 @@
 static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs,
 			       Scsi_Cmnd *sp)
 {
-	Scsi_Device *dp = sp->device;
+	struct scsi_device *dp = sp->device;
 	struct esp_device *esp_dev = dp->hostdata;
 
 	if(esp->prev_soff  != esp_dev->sync_max_offset ||
@@ -3605,7 +3605,7 @@
 }
 #endif
 
-int esp_slave_alloc(Scsi_Device *SDptr)
+int esp_slave_alloc(struct scsi_device *SDptr)
 {
 	struct esp_device *esp_dev =
 		kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
@@ -3617,7 +3617,7 @@
 	return 0;
 }
 
-void esp_slave_destroy(Scsi_Device *SDptr)
+void esp_slave_destroy(struct scsi_device *SDptr)
 {
 	struct NCR_ESP *esp = (struct NCR_ESP *) SDptr->host->hostdata;
 
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index 06e7edf..65a9b37 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -653,7 +653,7 @@
 
 /* External functions */
 extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs);
-extern struct NCR_ESP *esp_allocate(Scsi_Host_Template *, void *);
+extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *);
 extern void esp_deallocate(struct NCR_ESP *);
 extern void esp_release(void);
 extern void esp_initialize(struct NCR_ESP *);
@@ -664,6 +664,6 @@
 extern int esp_reset(Scsi_Cmnd *);
 extern int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length,
 			 int inout);
-extern int esp_slave_alloc(Scsi_Device *);
-extern void esp_slave_destroy(Scsi_Device *);
+extern int esp_slave_alloc(struct scsi_device *);
+extern void esp_slave_destroy(struct scsi_device *);
 #endif /* !(NCR53C9X_H) */
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 1353769..ae37d3a 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -447,7 +447,7 @@
 }
 #endif				/* USE_PIO */
 
-static int __init NCR53c406a_detect(Scsi_Host_Template * tpnt)
+static int __init NCR53c406a_detect(struct scsi_host_template * tpnt)
 {
 	int present = 0;
 	struct Scsi_Host *shpnt = NULL;
@@ -1057,7 +1057,7 @@
  * Use SG_NONE if DMA mode is enabled!
  */
 
-static Scsi_Host_Template driver_template = 
+static struct scsi_host_template driver_template =
 {
      .proc_name         	= "NCR53c406a"		/* proc_name */,        
      .name              	= "NCR53c406a"		/* name */,             
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index f7a1751..54996ea 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -2,7 +2,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 
@@ -173,7 +172,7 @@
     }
 }
 
-int __init a2091_detect(Scsi_Host_Template *tpnt)
+int __init a2091_detect(struct scsi_host_template *tpnt)
 {
     static unsigned char called = 0;
     struct Scsi_Host *instance;
@@ -234,7 +233,7 @@
 
 #define HOSTS_C
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "A2901",
 	.name			= "Commodore A2091/A590 SCSI",
 	.detect			= a2091_detect,
diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h
index 5499397..22d6a13 100644
--- a/drivers/scsi/a2091.h
+++ b/drivers/scsi/a2091.h
@@ -11,7 +11,7 @@
 
 #include <linux/types.h>
 
-int a2091_detect(Scsi_Host_Template *);
+int a2091_detect(struct scsi_host_template *);
 int a2091_release(struct Scsi_Host *);
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 306caf5..f425d42 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -168,7 +168,7 @@
     }
 }
 
-int __init a3000_detect(Scsi_Host_Template *tpnt)
+int __init a3000_detect(struct scsi_host_template *tpnt)
 {
     wd33c93_regs regs;
 
@@ -221,7 +221,7 @@
 
 #define HOSTS_C
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "A3000",
 	.name			= "Amiga 3000 built-in SCSI",
 	.detect			= a3000_detect,
diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h
index b1eda73..5535a65 100644
--- a/drivers/scsi/a3000.h
+++ b/drivers/scsi/a3000.h
@@ -11,7 +11,7 @@
 
 #include <linux/types.h>
 
-int a3000_detect(Scsi_Host_Template *);
+int a3000_detect(struct scsi_host_template *);
 int a3000_release(struct Scsi_Host *);
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 2a128a1..7139659 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -1579,18 +1579,10 @@
 			break;
 	{
 		u64 capacity;
-		char cp[12];
-		unsigned int offset = 0;
+		char cp[13];
 
 		dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n"));
 		capacity = fsa_dev_ptr[cid].size - 1;
-		if (scsicmd->cmnd[13] > 12) {
-			offset = scsicmd->cmnd[13] - 12;
-			if (offset > sizeof(cp))
-				break;
-			memset(cp, 0, offset);
-			aac_internal_transfer(scsicmd, cp, 0, offset);
-		}
 		cp[0] = (capacity >> 56) & 0xff;
 		cp[1] = (capacity >> 48) & 0xff;
 		cp[2] = (capacity >> 40) & 0xff;
@@ -1603,7 +1595,18 @@
 		cp[9] = 0;
 		cp[10] = 2;
 		cp[11] = 0;
-		aac_internal_transfer(scsicmd, cp, offset, sizeof(cp));
+		cp[12] = 0;
+		aac_internal_transfer(scsicmd, cp, 0,
+		  min((unsigned int)scsicmd->cmnd[13], sizeof(cp)));
+		if (sizeof(cp) < scsicmd->cmnd[13]) {
+			unsigned int len, offset = sizeof(cp);
+
+			memset(cp, 0, offset);
+			do {
+				len = min(scsicmd->cmnd[13]-offset, sizeof(cp));
+				aac_internal_transfer(scsicmd, cp, offset, len);
+			} while ((offset += len) < scsicmd->cmnd[13]);
+		}
 
 		/* Do not cache partition table for arrays */
 		scsicmd->device->removable = 1;
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 723c0ce..38d6d00 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -820,7 +820,7 @@
 				break;
 
 			/*
-			 *	Find the Scsi_Device associated with the SCSI
+			 *	Find the scsi_device associated with the SCSI
 			 * address. Make sure we have the right array, and if
 			 * so set the flag to initiate a new re-config once we
 			 * see an AifEnConfigChange AIF come through.
@@ -987,7 +987,7 @@
 
 
 	/*
-	 *	Find the Scsi_Device associated with the SCSI address,
+	 *	Find the scsi_device associated with the SCSI address,
 	 * and mark it as changed, invalidating the cache. This deals
 	 * with changes to existing device IDs.
 	 */
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index f4cfb8f..28b9305 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -114,7 +114,7 @@
           #include "advansys.h"
           #endif
 
-        and after "static Scsi_Host_Template builtin_scsi_hosts[] =":
+        and after "static struct scsi_host_template builtin_scsi_hosts[] =":
 
           #ifdef CONFIG_SCSI_ADVANSYS
           ADVANSYS,
@@ -160,7 +160,7 @@
            --- Driver Structures
            --- Driver Data
            --- Driver Function Prototypes
-           --- Linux 'Scsi_Host_Template' and advansys_setup() Functions
+           --- Linux 'struct scsi_host_template' and advansys_setup() Functions
            --- Loadable Driver Support
            --- Miscellaneous Driver Functions
            --- Functions Required by the Asc Library
@@ -4068,7 +4068,7 @@
 
 
 /*
- * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions
+ * --- Linux 'struct scsi_host_template' and advansys_setup() Functions
  */
 
 #ifdef CONFIG_PROC_FS
diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
index 3f4bde0..8ee7fb1 100644
--- a/drivers/scsi/advansys.h
+++ b/drivers/scsi/advansys.h
@@ -19,7 +19,7 @@
 #define _ADVANSYS_H
 
 /*
- * Scsi_Host_Template function prototypes.
+ * struct scsi_host_template function prototypes.
  */
 int advansys_detect(struct scsi_host_template *);
 int advansys_release(struct Scsi_Host *);
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 9b7caf5..9df23b6 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -424,7 +424,7 @@
 
 static int registered_count=0;
 static struct Scsi_Host *aha152x_host[2];
-static Scsi_Host_Template aha152x_driver_template;
+static struct scsi_host_template aha152x_driver_template;
 
 /*
  * internal states of the host
@@ -3464,7 +3464,7 @@
 	return thislength < length ? thislength : length;
 }
 
-static Scsi_Host_Template aha152x_driver_template = {
+static struct scsi_host_template aha152x_driver_template = {
 	.module				= THIS_MODULE,
 	.name				= AHA152X_REVID,
 	.proc_name			= "aha152x",
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 1b1adfb..51bad7a 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -1021,7 +1021,7 @@
 #endif
 
 /* return non-zero on detection */
-static int __init aha1542_detect(Scsi_Host_Template * tpnt)
+static int __init aha1542_detect(struct scsi_host_template * tpnt)
 {
 	unsigned char dma_chan;
 	unsigned char irq_level;
@@ -1789,7 +1789,7 @@
 MODULE_LICENSE("GPL");
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "aha1542",
 	.name			= "Adaptec 1542",
 	.detect			= aha1542_detect,
diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
index 3821ee1..1db5385 100644
--- a/drivers/scsi/aha1542.h
+++ b/drivers/scsi/aha1542.h
@@ -131,7 +131,7 @@
 				/* REQUEST SENSE */
 };
 
-static int aha1542_detect(Scsi_Host_Template *);
+static int aha1542_detect(struct scsi_host_template *);
 static int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
 static int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 8f85dcc..4b8c6a5 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -570,7 +570,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template aha1740_template = {
+static struct scsi_host_template aha1740_template = {
 	.module           = THIS_MODULE,
 	.proc_name        = "aha1740",
 	.proc_info        = aha1740_proc_info,
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 4612312..57ef7ae 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -42,8 +42,8 @@
 #include <linux/sched.h>
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
 #include <linux/libata.h>
 #include <asm/io.h>
 
@@ -196,7 +196,7 @@
 static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
 static void ahci_remove_one (struct pci_dev *pdev);
 
-static Scsi_Host_Template ahci_sht = {
+static struct scsi_host_template ahci_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
@@ -255,7 +255,7 @@
 	},
 };
 
-static struct pci_device_id ahci_pci_tbl[] = {
+static const struct pci_device_id ahci_pci_tbl[] = {
 	{ PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_ahci }, /* ICH6 */
 	{ PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index cfb46c2..31e9f40 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -436,29 +436,20 @@
 {
 	struct	 ahd_softc *ahd;
 	struct	 ahd_linux_device *dev = scsi_transport_device_data(cmd->device);
+	int rtn = SCSI_MLQUEUE_HOST_BUSY;
+	unsigned long flags;
 
 	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
 
-	/*
-	 * Close the race of a command that was in the process of
-	 * being queued to us just as our simq was frozen.  Let
-	 * DV commands through so long as we are only frozen to
-	 * perform DV.
-	 */
-	if (ahd->platform_data->qfrozen != 0) {
-		printf("%s: queue frozen\n", ahd_name(ahd));
+	ahd_lock(ahd, &flags);
+	if (ahd->platform_data->qfrozen == 0) {
+		cmd->scsi_done = scsi_done;
+		cmd->result = CAM_REQ_INPROG << 16;
+		rtn = ahd_linux_run_command(ahd, dev, cmd);
 
-		return SCSI_MLQUEUE_HOST_BUSY;
 	}
-
-	/*
-	 * Save the callback on completion function.
-	 */
-	cmd->scsi_done = scsi_done;
-
-	cmd->result = CAM_REQ_INPROG << 16;
-
-	return ahd_linux_run_command(ahd, dev, cmd);
+	ahd_unlock(ahd, &flags);
+	return rtn;
 }
 
 static inline struct scsi_target **
@@ -1081,7 +1072,6 @@
 
 	*((struct ahd_softc **)host->hostdata) = ahd;
 	ahd_lock(ahd, &s);
-	scsi_assign_lock(host, &ahd->platform_data->spin_lock);
 	ahd->platform_data->host = host;
 	host->can_queue = AHD_MAX_QUEUE;
 	host->cmd_per_lun = 2;
@@ -2062,6 +2052,7 @@
 	int    wait;
 	int    disconnected;
 	ahd_mode_state saved_modes;
+	unsigned long flags;
 
 	pending_scb = NULL;
 	paused = FALSE;
@@ -2077,7 +2068,7 @@
 		printf(" 0x%x", cmd->cmnd[cdb_byte]);
 	printf("\n");
 
-	spin_lock_irq(&ahd->platform_data->spin_lock);
+	ahd_lock(ahd, &flags);
 
 	/*
 	 * First determine if we currently own this command.
@@ -2291,7 +2282,8 @@
 		int ret;
 
 		ahd->platform_data->flags |= AHD_SCB_UP_EH_SEM;
-		spin_unlock_irq(&ahd->platform_data->spin_lock);
+		ahd_unlock(ahd, &flags);
+
 		init_timer(&timer);
 		timer.data = (u_long)ahd;
 		timer.expires = jiffies + (5 * HZ);
@@ -2305,9 +2297,8 @@
 			printf("Timer Expired\n");
 			retval = FAILED;
 		}
-		spin_lock_irq(&ahd->platform_data->spin_lock);
 	}
-	spin_unlock_irq(&ahd->platform_data->spin_lock);
+		ahd_unlock(ahd, &flags);
 	return (retval);
 }
 
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 052c661..bc44222 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -49,7 +49,6 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
-#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 1861407..7fc6454 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -476,26 +476,20 @@
 {
 	struct	 ahc_softc *ahc;
 	struct	 ahc_linux_device *dev = scsi_transport_device_data(cmd->device);
+	int rtn = SCSI_MLQUEUE_HOST_BUSY;
+	unsigned long flags;
 
 	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
 
-	/*
-	 * Save the callback on completion function.
-	 */
-	cmd->scsi_done = scsi_done;
+	ahc_lock(ahc, &flags);
+	if (ahc->platform_data->qfrozen == 0) {
+		cmd->scsi_done = scsi_done;
+		cmd->result = CAM_REQ_INPROG << 16;
+		rtn = ahc_linux_run_command(ahc, dev, cmd);
+	}
+	ahc_unlock(ahc, &flags);
 
-	/*
-	 * Close the race of a command that was in the process of
-	 * being queued to us just as our simq was frozen.  Let
-	 * DV commands through so long as we are only frozen to
-	 * perform DV.
-	 */
-	if (ahc->platform_data->qfrozen != 0)
-		return SCSI_MLQUEUE_HOST_BUSY;
-
-	cmd->result = CAM_REQ_INPROG << 16;
-
-	return ahc_linux_run_command(ahc, dev, cmd);
+	return rtn;
 }
 
 static inline struct scsi_target **
@@ -1079,7 +1073,6 @@
 
 	*((struct ahc_softc **)host->hostdata) = ahc;
 	ahc_lock(ahc, &s);
-	scsi_assign_lock(host, &ahc->platform_data->spin_lock);
 	ahc->platform_data->host = host;
 	host->can_queue = AHC_MAX_QUEUE;
 	host->cmd_per_lun = 2;
@@ -2111,6 +2104,7 @@
 	int    paused;
 	int    wait;
 	int    disconnected;
+	unsigned long flags;
 
 	pending_scb = NULL;
 	paused = FALSE;
@@ -2125,7 +2119,7 @@
 		printf(" 0x%x", cmd->cmnd[cdb_byte]);
 	printf("\n");
 
-	spin_lock_irq(&ahc->platform_data->spin_lock);
+	ahc_lock(ahc, &flags);
 
 	/*
 	 * First determine if we currently own this command.
@@ -2357,7 +2351,8 @@
 		int ret;
 
 		ahc->platform_data->flags |= AHC_UP_EH_SEMAPHORE;
-		spin_unlock_irq(&ahc->platform_data->spin_lock);
+		ahc_unlock(ahc, &flags);
+
 		init_timer(&timer);
 		timer.data = (u_long)ahc;
 		timer.expires = jiffies + (5 * HZ);
@@ -2371,10 +2366,8 @@
 			printf("Timer Expired\n");
 			retval = FAILED;
 		}
-		spin_lock_irq(&ahc->platform_data->spin_lock);
-	}
-
-	spin_unlock_irq(&ahc->platform_data->spin_lock);
+	} else
+		ahc_unlock(ahc, &flags);
 	return (retval);
 }
 
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index be9edbe..f2a9544 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -66,7 +66,6 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
-#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 880e2d9..33d56c3 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -6514,7 +6514,7 @@
 static void
 aic7xxx_init_transinfo(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
 {
-  Scsi_Device *sdpnt = aic_dev->SDptr;
+  struct scsi_device *sdpnt = aic_dev->SDptr;
   unsigned char tindex;
 
   tindex = sdpnt->id | (sdpnt->channel << 3);
@@ -6581,7 +6581,7 @@
  *   Set up the initial aic_dev struct pointers
  *-F*************************************************************************/
 static int
-aic7xxx_slave_alloc(Scsi_Device *SDptr)
+aic7xxx_slave_alloc(struct scsi_device *SDptr)
 {
   struct aic7xxx_host *p = (struct aic7xxx_host *)SDptr->host->hostdata;
   struct aic_dev_data *aic_dev;
@@ -6644,7 +6644,7 @@
  *   queueing to be [en|dis]abled for a specific adapter.
  *-F*************************************************************************/
 static void
-aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
+aic7xxx_device_queue_depth(struct aic7xxx_host *p, struct scsi_device *device)
 {
   int tag_enabled = FALSE;
   struct aic_dev_data *aic_dev = device->hostdata;
@@ -6734,7 +6734,7 @@
  *   prepare for this device to go away
  *-F*************************************************************************/
 static void
-aic7xxx_slave_destroy(Scsi_Device *SDptr)
+aic7xxx_slave_destroy(struct scsi_device *SDptr)
 {
   struct aic_dev_data *aic_dev = SDptr->hostdata;
 
@@ -6754,7 +6754,7 @@
  *   depths, allocate command structs, etc.
  *-F*************************************************************************/
 static int
-aic7xxx_slave_configure(Scsi_Device *SDptr)
+aic7xxx_slave_configure(struct scsi_device *SDptr)
 {
   struct aic7xxx_host *p = (struct aic7xxx_host *) SDptr->host->hostdata;
   struct aic_dev_data *aic_dev;
@@ -7865,7 +7865,7 @@
  *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
  *-F*************************************************************************/
 static int
-aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
+aic7xxx_register(struct scsi_host_template *template, struct aic7xxx_host *p,
   int reset_delay)
 {
   int i, result;
@@ -8412,7 +8412,7 @@
  *   and a pointer to a aic7xxx_host struct upon success.
  *-F*************************************************************************/
 static struct aic7xxx_host *
-aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
+aic7xxx_alloc(struct scsi_host_template *sht, struct aic7xxx_host *temp)
 {
   struct aic7xxx_host *p = NULL;
   struct Scsi_Host *host;
@@ -8991,7 +8991,7 @@
  *       mid-level SCSI code is overhauled.
  *-F*************************************************************************/
 static int
-aic7xxx_detect(Scsi_Host_Template *template)
+aic7xxx_detect(struct scsi_host_template *template)
 {
   struct aic7xxx_host *temp_p = NULL;
   struct aic7xxx_host *current_p = NULL;
@@ -11161,7 +11161,7 @@
 MODULE_VERSION(AIC7XXX_H_VERSION);
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_info		= aic7xxx_proc_info,
 	.detect			= aic7xxx_detect,
 	.release		= aic7xxx_release,
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
index 5f13546..c0844fa 100644
--- a/drivers/scsi/amiga7xx.c
+++ b/drivers/scsi/amiga7xx.c
@@ -11,7 +11,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/zorro.h>
 #include <linux/stat.h>
@@ -30,7 +29,7 @@
 #include "amiga7xx.h"
 
 
-static int amiga7xx_register_one(Scsi_Host_Template *tpnt,
+static int amiga7xx_register_one(struct scsi_host_template *tpnt,
 				 unsigned long address)
 {
     long long options;
@@ -66,7 +65,7 @@
     { 0 }
 };
 
-static int __init amiga7xx_zorro_detect(Scsi_Host_Template *tpnt)
+static int __init amiga7xx_zorro_detect(struct scsi_host_template *tpnt)
 {
     int num = 0, i;
     struct zorro_dev *z = NULL;
@@ -90,7 +89,7 @@
 #endif /* CONFIG_ZORRO */
 
 
-int __init amiga7xx_detect(Scsi_Host_Template *tpnt)
+int __init amiga7xx_detect(struct scsi_host_template *tpnt)
 {
     static unsigned char called = 0;
     int num = 0;
@@ -123,7 +122,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name			= "Amiga NCR53c710 SCSI",
 	.detect			= amiga7xx_detect,
 	.release		= amiga7xx_release,
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
index 8cc54a5..1b63759 100644
--- a/drivers/scsi/amiga7xx.h
+++ b/drivers/scsi/amiga7xx.h
@@ -2,7 +2,7 @@
 
 #include <linux/types.h>
 
-int amiga7xx_detect(Scsi_Host_Template *);
+int amiga7xx_detect(struct scsi_host_template *);
 const char *NCR53c7x0_info(void);
 int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int NCR53c7xx_abort(Scsi_Cmnd *);
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index be2caec..b7b20c6 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -896,7 +896,7 @@
  * Notes    : this will only be one SG entry or less
  */
 static
-void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length)
+void acornscsi_data_updateptr(AS_Host *host, struct scsi_pointer *SCp, unsigned int length)
 {
     SCp->ptr += length;
     SCp->this_residual -= length;
@@ -2862,7 +2862,7 @@
 			int length, int inout)
 {
     int pos, begin = 0, devidx;
-    Scsi_Device *scd;
+    struct scsi_device *scd;
     AS_Host *host;
     char *p = buffer;
 
@@ -2971,7 +2971,7 @@
     return pos;
 }
 
-static Scsi_Host_Template acornscsi_template = {
+static struct scsi_host_template acornscsi_template = {
 	.module			= THIS_MODULE,
 	.proc_info		= acornscsi_proc_info,
 	.name			= "AcornSCSI",
diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h
index 03881f0..2142290 100644
--- a/drivers/scsi/arm/acornscsi.h
+++ b/drivers/scsi/arm/acornscsi.h
@@ -292,7 +292,7 @@
 	    unsigned char	tag;		/* reconnected tag			*/
 	} reconnected;
 
-	Scsi_Pointer	SCp;			/* current commands data pointer	*/
+	struct scsi_pointer	SCp;			/* current commands data pointer	*/
 
 	MsgQueue_t	msgs;
 
diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
index 29811f5..804125e 100644
--- a/drivers/scsi/arm/arxescsi.c
+++ b/drivers/scsi/arm/arxescsi.c
@@ -65,7 +65,7 @@
  * Returns : 0 if we should not set CMD_WITHDMA for transfer info command
  */
 static fasdmatype_t
-arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+arxescsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
 		       fasdmadir_t direction, fasdmatype_t min_type)
 {
 	/*
@@ -111,7 +111,7 @@
  *	     transfer  - minimum number of bytes we expect to transfer
  */
 static void
-arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+arxescsi_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp,
 		    fasdmadir_t direction, int transfer)
 {
 	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
@@ -197,7 +197,7 @@
  * Params  : host  - host
  *	     SCpnt - command
  */
-static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+static void arxescsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp)
 {
 	/*
 	 * no DMA to stop
@@ -261,7 +261,7 @@
 	return pos;
 }
 
-static Scsi_Host_Template arxescsi_template = {
+static struct scsi_host_template arxescsi_template = {
 	.proc_info			= arxescsi_proc_info,
 	.name				= "ARXE SCSI card",
 	.info				= arxescsi_info,
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index 26498553..81e266b 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -238,7 +238,7 @@
 
 #include "../NCR5380.c"
 
-static Scsi_Host_Template cumanascsi_template = {
+static struct scsi_host_template cumanascsi_template = {
 	.module			= THIS_MODULE,
 	.name			= "Cumana 16-bit SCSI",
 	.info			= cumanascsi_info,
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index 0ef0644..3a7a46b 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -157,7 +157,7 @@
  * Returns  : type of transfer to be performed
  */
 static fasdmatype_t
-cumanascsi_2_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+cumanascsi_2_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
 		       fasdmadir_t direction, fasdmatype_t min_type)
 {
 	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
@@ -209,7 +209,7 @@
  *	      transfer  - minimum number of bytes we expect to transfer
  */
 static void
-cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+cumanascsi_2_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp,
 			fasdmadir_t direction, int transfer)
 {
 	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
@@ -283,7 +283,7 @@
  *	      SCpnt - command
  */
 static void
-cumanascsi_2_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+cumanascsi_2_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp)
 {
 	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
 	if (info->info.scsi.dma != NO_DMA) {
@@ -381,7 +381,7 @@
 	return pos;
 }
 
-static Scsi_Host_Template cumanascsi2_template = {
+static struct scsi_host_template cumanascsi2_template = {
 	.module				= THIS_MODULE,
 	.proc_info			= cumanascsi_2_proc_info,
 	.name				= "Cumana SCSI II",
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c
index f8a7fdd..6adcccb 100644
--- a/drivers/scsi/arm/ecoscsi.c
+++ b/drivers/scsi/arm/ecoscsi.c
@@ -155,7 +155,7 @@
 
 #include "../NCR5380.c"
 
-static Scsi_Host_Template ecoscsi_template =  {
+static struct scsi_host_template ecoscsi_template =  {
 	.module		= THIS_MODULE,
 	.name		= "Serial Port EcoSCSI NCR5380",
 	.proc_name	= "ecoscsi",
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
index ce711f1..4d1e8f5 100644
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -158,7 +158,7 @@
  * Returns  : type of transfer to be performed
  */
 static fasdmatype_t
-eesoxscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+eesoxscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
 		       fasdmadir_t direction, fasdmatype_t min_type)
 {
 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
@@ -353,7 +353,7 @@
 }
 
 static void
-eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+eesoxscsi_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp,
 		     fasdmadir_t dir, int transfer_size)
 {
 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
@@ -370,7 +370,7 @@
  *	      SCpnt - command
  */
 static void
-eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+eesoxscsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp)
 {
 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
 	if (info->info.scsi.dma != NO_DMA)
@@ -499,7 +499,7 @@
 static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
 		   eesoxscsi_show_term, eesoxscsi_store_term);
 
-static Scsi_Host_Template eesox_template = {
+static struct scsi_host_template eesox_template = {
 	.module				= THIS_MODULE,
 	.proc_info			= eesoxscsi_proc_info,
 	.name				= "EESOX SCSI",
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 4772fb3..3e1053f 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -173,7 +173,7 @@
 		fas216_readb(info, REG_CTCH));
 }
 
-static void print_SCp(Scsi_Pointer *SCp, const char *prefix, const char *suffix)
+static void print_SCp(struct scsi_pointer *SCp, const char *prefix, const char *suffix)
 {
 	printk("%sptr %p this_residual 0x%x buffer %p buffers_residual 0x%x%s",
 		prefix, SCp->ptr, SCp->this_residual, SCp->buffer,
@@ -628,7 +628,7 @@
  */
 static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
 {
-	Scsi_Pointer *SCp = &info->scsi.SCp;
+	struct scsi_pointer *SCp = &info->scsi.SCp;
 
 	fas216_checkmagic(info);
 
@@ -668,7 +668,7 @@
  */
 static void fas216_pio(FAS216_Info *info, fasdmadir_t direction)
 {
-	Scsi_Pointer *SCp = &info->scsi.SCp;
+	struct scsi_pointer *SCp = &info->scsi.SCp;
 
 	fas216_checkmagic(info);
 
@@ -2559,7 +2559,7 @@
 {
 	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
 	unsigned long flags;
-	Scsi_Device *SDpnt;
+	struct scsi_device *SDpnt;
 
 	fas216_checkmagic(info);
 	fas216_log(info, LOG_ERROR, "resetting bus");
@@ -3000,7 +3000,7 @@
 int fas216_print_devices(FAS216_Info *info, char *buffer)
 {
 	struct fas216_device *dev;
-	Scsi_Device *scd;
+	struct scsi_device *scd;
 	char *p = buffer;
 
 	p += sprintf(p, "Device/Lun TaggedQ       Parity   Sync\n");
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
index 60a2a12..540914d 100644
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -243,7 +243,7 @@
 		unsigned int	irq;			/* interrupt				*/
 		int		dma;			/* dma channel				*/
 
-		Scsi_Pointer	SCp;			/* current commands data pointer	*/
+		struct scsi_pointer	SCp;			/* current commands data pointer	*/
 
 		MsgQueue_t	msgs;			/* message queue for connected device	*/
 
@@ -304,9 +304,9 @@
 	/* dma */
 	struct {
 		fasdmatype_t	transfer_type;		/* current type of DMA transfer		*/
-		fasdmatype_t	(*setup) (struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, fasdmatype_t min_dma);
-		void		(*pseudo)(struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, int transfer);
-		void		(*stop)  (struct Scsi_Host *host, Scsi_Pointer *SCp);
+		fasdmatype_t	(*setup) (struct Scsi_Host *host, struct scsi_pointer *SCp, fasdmadir_t direction, fasdmatype_t min_dma);
+		void		(*pseudo)(struct Scsi_Host *host, struct scsi_pointer *SCp, fasdmadir_t direction, int transfer);
+		void		(*stop)  (struct Scsi_Host *host, struct scsi_pointer *SCp);
 	} dma;
 
 	/* miscellaneous */
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index de24bb9..d806b02 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -111,7 +111,7 @@
 
 #include "../NCR5380.c"
 
-static Scsi_Host_Template oakscsi_template = {
+static struct scsi_host_template oakscsi_template = {
 	.module			= THIS_MODULE,
 	.proc_info		= oakscsi_proc_info,
 	.name			= "Oak 16-bit SCSI",
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index abda216..3333d7b 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -132,7 +132,7 @@
  * Returns  : type of transfer to be performed
  */
 static fasdmatype_t
-powertecscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+powertecscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
 		       fasdmadir_t direction, fasdmatype_t min_type)
 {
 	struct powertec_info *info = (struct powertec_info *)host->hostdata;
@@ -174,7 +174,7 @@
  *	      SCpnt - command
  */
 static void
-powertecscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+powertecscsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp)
 {
 	struct powertec_info *info = (struct powertec_info *)host->hostdata;
 	if (info->info.scsi.dma != NO_DMA)
@@ -293,7 +293,7 @@
 static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
 		   powertecscsi_show_term, powertecscsi_store_term);
 
-static Scsi_Host_Template powertecscsi_template = {
+static struct scsi_host_template powertecscsi_template = {
 	.module				= THIS_MODULE,
 	.proc_info			= powertecscsi_proc_info,
 	.name				= "PowerTec SCSI",
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index 1993764..6dd544a 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -18,7 +18,7 @@
  * The scatter-gather list handling.  This contains all
  * the yucky stuff that needs to be fixed properly.
  */
-static inline int copy_SCp_to_sg(struct scatterlist *sg, Scsi_Pointer *SCp, int max)
+static inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max)
 {
 	int bufs = SCp->buffers_residual;
 
@@ -32,7 +32,7 @@
 	return bufs + 1;
 }
 
-static inline int next_SCp(Scsi_Pointer *SCp)
+static inline int next_SCp(struct scsi_pointer *SCp)
 {
 	int ret = SCp->buffers_residual;
 	if (ret) {
@@ -49,7 +49,7 @@
 	return ret;
 }
 
-static inline unsigned char get_next_SCp_byte(Scsi_Pointer *SCp)
+static inline unsigned char get_next_SCp_byte(struct scsi_pointer *SCp)
 {
 	char c = *SCp->ptr;
 
@@ -59,7 +59,7 @@
 	return c;
 }
 
-static inline void put_next_SCp_byte(Scsi_Pointer *SCp, unsigned char c)
+static inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c)
 {
 	*SCp->ptr = c;
 	SCp->ptr += 1;
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 7f8aa1b..855428f 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -46,7 +46,6 @@
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
@@ -96,7 +95,7 @@
 
 static unsigned int in_module_init = 1;
 
-static struct pci_device_id piix_pci_tbl[] = {
+static const struct pci_device_id piix_pci_tbl[] = {
 #ifdef ATA_ENABLE_PATA
 	{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata },
 	{ 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
@@ -128,7 +127,7 @@
 	.remove			= ata_pci_remove_one,
 };
 
-static Scsi_Host_Template piix_sht = {
+static struct scsi_host_template piix_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 2c12be7..2ae31ce 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -255,7 +255,7 @@
  */
 
 static struct Scsi_Host *first_instance = NULL;
-static Scsi_Host_Template *the_template = NULL;
+static struct scsi_host_template *the_template = NULL;
 
 /* Macros ease life... :-) */
 #define	SETUP_HOSTDATA(in)				\
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index af8adb6..f4c1ca7 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -600,7 +600,7 @@
 #endif
 
 
-int atari_scsi_detect (Scsi_Host_Template *host)
+int atari_scsi_detect (struct scsi_host_template *host)
 {
 	static int called = 0;
 	struct Scsi_Host *instance;
@@ -1141,7 +1141,7 @@
 
 #include "atari_NCR5380.c"
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_info		= atari_scsi_proc_info,
 	.name			= "Atari native SCSI",
 	.detect			= atari_scsi_detect,
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
index cc12569..f917bdd 100644
--- a/drivers/scsi/atari_scsi.h
+++ b/drivers/scsi/atari_scsi.h
@@ -18,7 +18,7 @@
 /* (I_HAVE_OVERRUNS stuff removed) */
 
 #ifndef ASM
-int atari_scsi_detect (Scsi_Host_Template *);
+int atari_scsi_detect (struct scsi_host_template *);
 const char *atari_scsi_info (struct Scsi_Host *);
 int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
 #ifdef MODULE
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
index 4cd9fcf..763e409 100644
--- a/drivers/scsi/blz1230.c
+++ b/drivers/scsi/blz1230.c
@@ -94,7 +94,7 @@
 				 */
 
 /***************************************************************** Detection */
-int __init blz1230_esp_detect(Scsi_Host_Template *tpnt)
+int __init blz1230_esp_detect(struct scsi_host_template *tpnt)
 {
 	struct NCR_ESP *esp;
 	struct zorro_dev *z = NULL;
@@ -328,7 +328,7 @@
 }
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "esp-blz1230",
 	.proc_info		= esp_proc_info,
 	.name			= "Blizzard1230 SCSI IV",
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
index c5221d0..d72d05f 100644
--- a/drivers/scsi/blz2060.c
+++ b/drivers/scsi/blz2060.c
@@ -90,7 +90,7 @@
 				 */
 
 /***************************************************************** Detection */
-int __init blz2060_esp_detect(Scsi_Host_Template *tpnt)
+int __init blz2060_esp_detect(struct scsi_host_template *tpnt)
 {
 	struct NCR_ESP *esp;
 	struct zorro_dev *z = NULL;
@@ -282,7 +282,7 @@
 }
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "esp-blz2060",
 	.proc_info		= esp_proc_info,
 	.name			= "Blizzard2060 SCSI",
diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c
index 29c7ed3..2958b8c 100644
--- a/drivers/scsi/bvme6000.c
+++ b/drivers/scsi/bvme6000.c
@@ -7,7 +7,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/zorro.h>
 
 #include <asm/setup.h>
@@ -24,7 +23,7 @@
 #include<linux/stat.h>
 
 
-int bvme6000_scsi_detect(Scsi_Host_Template *tpnt)
+int bvme6000_scsi_detect(struct scsi_host_template *tpnt)
 {
     static unsigned char called = 0;
     int clock;
@@ -60,7 +59,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name			= "BVME6000 NCR53c710 SCSI",
 	.detect			= bvme6000_scsi_detect,
 	.release		= bvme6000_scsi_release,
diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h
index 49b6bbb..7c9c036 100644
--- a/drivers/scsi/bvme6000.h
+++ b/drivers/scsi/bvme6000.h
@@ -3,7 +3,7 @@
 
 #include <linux/types.h>
 
-int bvme6000_scsi_detect(Scsi_Host_Template *);
+int bvme6000_scsi_detect(struct scsi_host_template *);
 const char *NCR53c7x0_info(void);
 int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int NCR53c7xx_abort(Scsi_Cmnd *);
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
index bdbca85d..f9b940e 100644
--- a/drivers/scsi/cyberstorm.c
+++ b/drivers/scsi/cyberstorm.c
@@ -104,7 +104,7 @@
 				 */
 
 /***************************************************************** Detection */
-int __init cyber_esp_detect(Scsi_Host_Template *tpnt)
+int __init cyber_esp_detect(struct scsi_host_template *tpnt)
 {
 	struct NCR_ESP *esp;
 	struct zorro_dev *z = NULL;
@@ -353,7 +353,7 @@
 }
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "esp-cyberstorm",
 	.proc_info		= esp_proc_info,
 	.name			= "CyberStorm SCSI",
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
index 845d925..a3caabf 100644
--- a/drivers/scsi/cyberstormII.c
+++ b/drivers/scsi/cyberstormII.c
@@ -81,7 +81,7 @@
 				 */
 
 /***************************************************************** Detection */
-int __init cyberII_esp_detect(Scsi_Host_Template *tpnt)
+int __init cyberII_esp_detect(struct scsi_host_template *tpnt)
 {
 	struct NCR_ESP *esp;
 	struct zorro_dev *z = NULL;
@@ -290,7 +290,7 @@
 }
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "esp-cyberstormII",
 	.proc_info		= esp_proc_info,
 	.name			= "CyberStorm Mk II SCSI",
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index 256d6ba..a35ee43 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -133,7 +133,7 @@
 #include "scsi_module.c"
 
 /***************************************************************** Detection */
-static int dec_esp_detect(Scsi_Host_Template * tpnt)
+static int dec_esp_detect(struct scsi_host_template * tpnt)
 {
 	struct NCR_ESP *esp;
 	struct ConfigDev *esp_dev;
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index 489194a..2ad2a89 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -44,7 +44,7 @@
 
 
 /*
- * Scsi_Host_Template (see hosts.h) 
+ * struct scsi_host_template (see hosts.h)
  */
 
 #define DPT_DRIVER_NAME	"Adaptec I2O RAID"
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 897743b..310d2f4 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -199,7 +199,7 @@
 #endif
 
 /* 
- * Function : int dtc_detect(Scsi_Host_Template * tpnt)
+ * Function : int dtc_detect(struct scsi_host_template * tpnt)
  *
  * Purpose : detects and initializes DTC 3180/3280 controllers
  *	that were autoprobed, overridden on the LILO command line, 
@@ -211,7 +211,7 @@
  *
 */
 
-static int __init dtc_detect(Scsi_Host_Template * tpnt)
+static int __init dtc_detect(struct scsi_host_template * tpnt)
 {
 	static int current_override = 0, current_base = 0;
 	struct Scsi_Host *instance;
@@ -471,7 +471,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name				= "DTC 3180/3280 ",
 	.detect				= dtc_detect,
 	.release			= dtc_release,
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
index 277cd01..0b205f8 100644
--- a/drivers/scsi/dtc.h
+++ b/drivers/scsi/dtc.h
@@ -35,7 +35,7 @@
 static int dtc_abort(Scsi_Cmnd *);
 static int dtc_biosparam(struct scsi_device *, struct block_device *,
 		         sector_t, int*);
-static int dtc_detect(Scsi_Host_Template *);
+static int dtc_detect(struct scsi_host_template *);
 static int dtc_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int dtc_bus_reset(Scsi_Cmnd *);
 
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
index ae47612..ccee68b 100644
--- a/drivers/scsi/fastlane.c
+++ b/drivers/scsi/fastlane.c
@@ -125,7 +125,7 @@
 }
 
 /***************************************************************** Detection */
-int __init fastlane_esp_detect(Scsi_Host_Template *tpnt)
+int __init fastlane_esp_detect(struct scsi_host_template *tpnt)
 {
 	struct NCR_ESP *esp;
 	struct zorro_dev *z = NULL;
@@ -398,7 +398,7 @@
 }
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "esp-fastlane",
 	.proc_info		= esp_proc_info,
 	.name			= "Fastlane SCSI",
diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
index a6f120d..0341654 100644
--- a/drivers/scsi/fcal.c
+++ b/drivers/scsi/fcal.c
@@ -70,7 +70,7 @@
 
 static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
 
-int fcal_slave_configure(Scsi_Device *device)
+int fcal_slave_configure(struct scsi_device *device)
 {
 	int depth_to_use;
 	
@@ -89,7 +89,7 @@
 
 /* Detect all FC Arbitrated Loops attached to the machine.
    fc4 module has done all the work for us... */
-int __init fcal_detect(Scsi_Host_Template *tpnt)
+int __init fcal_detect(struct scsi_host_template *tpnt)
 {
 	int nfcals = 0;
 	fc_channel *fc;
@@ -244,7 +244,7 @@
 			SPRINTF ("  [AL-PA: %02x, Port WWN: %08x%08x, Node WWN: %08x%08x] Not responded to PRLI\n",
 				 alpa, u1[0], u1[1], u2[0], u2[1]);
 		} else {
-			Scsi_Device *scd;
+			struct scsi_device *scd;
 			shost_for_each_device(scd, host)
 				if (scd->id == target) {
 					SPRINTF ("  [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x]  ",
@@ -297,7 +297,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name			= "Fibre Channel Arbitrated Loop",
 	.detect			= fcal_detect,
 	.release		= fcal_release,	
diff --git a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h
index 21aa32e..7ff2c349 100644
--- a/drivers/scsi/fcal.h
+++ b/drivers/scsi/fcal.h
@@ -20,8 +20,8 @@
    for a particular channel */
 #define FCAL_CAN_QUEUE		512
 
-int fcal_detect(Scsi_Host_Template *);
+int fcal_detect(struct scsi_host_template *);
 int fcal_release(struct Scsi_Host *);
-int fcal_slave_configure(Scsi_Device *);
+int fcal_slave_configure(struct scsi_device *);
 
 #endif /* !(_FCAL_H) */
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index 6d44602..cca485a 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -343,7 +343,7 @@
 		outb(0x01 | PARITY_MASK, TMC_Cntl_port);
 }
 
-static int fd_mcs_detect(Scsi_Host_Template * tpnt)
+static int fd_mcs_detect(struct scsi_host_template * tpnt)
 {
 	int loop;
 	struct Scsi_Host *shpnt;
@@ -1343,7 +1343,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name			= "fd_mcs",
 	.proc_info			= fd_mcs_proc_info,
 	.detect				= fd_mcs_detect,
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index a3aa729..45756fa 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -285,7 +285,7 @@
  *	Locks: none
  */
 
-int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt)
+int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
 {
 	static int current_override = 0;
 	int count, i;
@@ -798,7 +798,7 @@
 	Scsi_Cmnd *ptr;
 	struct NCR5380_hostdata *hostdata;
 #ifdef NCR5380_STATS
-	Scsi_Device *dev;
+	struct scsi_device *dev;
 	extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 #endif
 
@@ -899,7 +899,7 @@
 #undef PRINTP
 #undef ANDP
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_info      	= generic_NCR5380_proc_info,
 	.name           	= "Generic NCR5380/NCR53C400 Scsi Driver",
 	.detect         	= generic_NCR5380_detect,
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index c8adc5a..656fbe2 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -45,7 +45,7 @@
 
 #ifndef ASM
 static int generic_NCR5380_abort(Scsi_Cmnd *);
-static int generic_NCR5380_detect(Scsi_Host_Template *);
+static int generic_NCR5380_detect(struct scsi_host_template *);
 static int generic_NCR5380_release_resources(struct Scsi_Host *);
 static int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int generic_NCR5380_bus_reset(Scsi_Cmnd *);
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index af68230..a6deb01 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -94,7 +94,7 @@
  * Bugfix free_irq()
  *
  * Revision 1.56  2001/08/09 11:19:39  achim
- * Scsi_Host_Template changes
+ * struct scsi_host_template changes
  *
  * Revision 1.55  2001/08/09 10:11:28  achim
  * Command HOST_UNFREEZE_IO before cache service init.
@@ -4153,7 +4153,7 @@
     return 1;
 }
 
-static int __init gdth_detect(Scsi_Host_Template *shtp)
+static int __init gdth_detect(struct scsi_host_template *shtp)
 {
     struct Scsi_Host *shp;
     gdth_pci_str pcistr[MAXHA];
@@ -5562,7 +5562,7 @@
 #else
     Scsi_Cmnd       *scp;
 #endif
-    Scsi_Device     *sdev;
+    struct scsi_device     *sdev;
     char            cmnd[MAX_COMMAND_SIZE];   
     memset(cmnd, 0xff, MAX_COMMAND_SIZE);
 
@@ -5624,10 +5624,10 @@
     gdth_cmd_str    gdtcmd;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     Scsi_Request    *srp;
-    Scsi_Device     *sdev;
+    struct scsi_device     *sdev;
 #else
     Scsi_Cmnd       *scp;
-    Scsi_Device     *sdev;
+    struct scsi_device     *sdev;
 #endif
     char            cmnd[MAX_COMMAND_SIZE];   
 #endif
@@ -5683,7 +5683,7 @@
     return NOTIFY_OK;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
         .proc_name              = "gdth", 
         .proc_info              = gdth_proc_info,
         .name                   = "GDT SCSI Disk Array Controller",
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index c0f1e34..cc4882f 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -944,9 +944,9 @@
     ulong               dma32_cnt, dma64_cnt;   /* statistics: DMA buffer */
 #endif
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-    Scsi_Device         *sdev;
+    struct scsi_device         *sdev;
 #else
-    Scsi_Device         sdev;
+    struct scsi_device         sdev;
 #endif
 } gdth_ha_str;
 
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 1bd02f8..5e8657f 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -54,10 +54,10 @@
     int             ret_val = -EINVAL;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     Scsi_Request    *scp;
-    Scsi_Device     *sdev;
+    struct scsi_device     *sdev;
 #else
     Scsi_Cmnd       *scp;
-    Scsi_Device     *sdev;
+    struct scsi_device     *sdev;
 #endif
     TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
 
@@ -232,10 +232,10 @@
     gdth_evt_str *estr;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
     Scsi_Request *scp;
-    Scsi_Device *sdev; 
+    struct scsi_device *sdev;
 #else
     Scsi_Cmnd *scp;
-    Scsi_Device *sdev;
+    struct scsi_device *sdev;
 #endif
     char hrec[161];
     struct timeval tv;
@@ -275,7 +275,7 @@
     scp->cmd_len = 12;
     scp->use_sg = 0;
 #else
-    memset(&sdev,0,sizeof(Scsi_Device));
+    memset(&sdev,0,sizeof(struct scsi_device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
     sdev.host = scp.host = host;
     sdev.id = scp.target = sdev.host->this_id;
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index d12342f..5b15449 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -2,7 +2,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 
@@ -170,7 +169,7 @@
 
 #define CHECK_WD33C93
 
-int __init gvp11_detect(Scsi_Host_Template *tpnt)
+int __init gvp11_detect(struct scsi_host_template *tpnt)
 {
     static unsigned char called = 0;
     struct Scsi_Host *instance;
@@ -362,7 +361,7 @@
 
 #include "gvp11.h"
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "GVP11",
 	.name			= "GVP Series II SCSI",
 	.detect			= gvp11_detect,
diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h
index 5148d9f..575d219d 100644
--- a/drivers/scsi/gvp11.h
+++ b/drivers/scsi/gvp11.h
@@ -11,7 +11,7 @@
 
 #include <linux/types.h>
 
-int gvp11_detect(Scsi_Host_Template *);
+int gvp11_detect(struct scsi_host_template *);
 int gvp11_release(struct Scsi_Host *);
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 887a5c3..b60c1b9 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -18,12 +18,6 @@
  */
 
 #include <linux/config.h>
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
-#error "This driver works only with kernel 2.5.45 or higher!"
-#endif
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -498,7 +492,7 @@
 static int probe_display(int);
 static int probe_bus_mode(int);
 static int device_exists(int, int, int *, int *);
-static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, int, int, int, char *);
+static struct Scsi_Host *ibmmca_register(struct scsi_host_template *, int, int, int, char *);
 static int option_setup(char *);
 /* local functions needed for proc_info */
 static int ldn_access_load(int, int);
@@ -1489,7 +1483,7 @@
 	return len;
 }
 
-int ibmmca_detect(Scsi_Host_Template * scsi_template)
+int ibmmca_detect(struct scsi_host_template * scsi_template)
 {
 	struct Scsi_Host *shpnt;
 	int port, id, i, j, k, list_size, slot;
@@ -1742,7 +1736,7 @@
 	return found;		/* return the number of found SCSI hosts. Should be 1 or 0. */
 }
 
-static struct Scsi_Host *ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id, int adaptertype, char *hostname)
+static struct Scsi_Host *ibmmca_register(struct scsi_host_template * scsi_template, int port, int id, int adaptertype, char *hostname)
 {
 	struct Scsi_Host *shpnt;
 	int i, j;
@@ -2500,7 +2494,7 @@
 
 __setup("ibmmcascsi=", option_setup);
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
           .proc_name      = "ibmmca",
 	  .proc_info	  = ibmmca_proc_info,
           .name           = "IBM SCSI-Subsystem",
diff --git a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h
index 6d68f60..017ee2f 100644
--- a/drivers/scsi/ibmmca.h
+++ b/drivers/scsi/ibmmca.h
@@ -11,7 +11,7 @@
 /* Common forward declarations for all Linux-versions: */
 
 /* Interfaces to the midlevel Linux SCSI driver */
-static int ibmmca_detect (Scsi_Host_Template *);
+static int ibmmca_detect (struct scsi_host_template *);
 static int ibmmca_release (struct Scsi_Host *);
 static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 static int ibmmca_abort (Scsi_Cmnd *);
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index c888af4..e1960d6 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -395,6 +395,7 @@
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
 	struct Scsi_Host *host;
 	u8 *scsi_buf;
+	int errors = rq->errors;
 	unsigned long flags;
 
 	if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) {
@@ -421,11 +422,11 @@
 			printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n",
 					drive->name, pc->scsi_cmd->serial_number);
 		pc->scsi_cmd->result = DID_TIME_OUT << 16;
-	} else if (rq->errors >= ERROR_MAX) {
+	} else if (errors >= ERROR_MAX) {
 		pc->scsi_cmd->result = DID_ERROR << 16;
 		if (log)
 			printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-	} else if (rq->errors) {
+	} else if (errors) {
 		if (log)
 			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
 		if (!idescsi_check_condition(drive, rq))
@@ -881,7 +882,7 @@
 	struct gendisk *disk = cmd->request->rq_disk;
 
 	if (disk) {
-		struct Scsi_Device_Template **p = disk->private_data;
+		struct struct scsi_device_Template **p = disk->private_data;
 		if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0)
 			return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 	}
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index fe387b5..34daa3e 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -1899,7 +1899,7 @@
 };
 
 
-static int __init in2000_detect(Scsi_Host_Template * tpnt)
+static int __init in2000_detect(struct scsi_host_template * tpnt)
 {
 	struct Scsi_Host *instance;
 	struct IN2000_hostdata *hostdata;
@@ -2305,7 +2305,7 @@
 MODULE_LICENSE("GPL");
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name       		= "in2000",
 	.proc_info       		= in2000_proc_info,
 	.name            		= "Always IN2000",
diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
index a240b52..0fb8b06 100644
--- a/drivers/scsi/in2000.h
+++ b/drivers/scsi/in2000.h
@@ -395,7 +395,7 @@
 # define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(host->host_lock, \
 							   flags)
 
-static int in2000_detect(Scsi_Host_Template *) in2000__INIT;
+static int in2000_detect(struct scsi_host_template *) in2000__INIT;
 static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int in2000_abort(Scsi_Cmnd *);
 static void in2000_setup(char *, int *) in2000__INIT;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index e0039df..fa2cb358 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -91,11 +91,14 @@
 static int ipr_testmode = 0;
 static unsigned int ipr_fastfail = 0;
 static unsigned int ipr_transop_timeout = IPR_OPERATIONAL_TIMEOUT;
+static unsigned int ipr_enable_cache = 1;
+static unsigned int ipr_debug = 0;
+static int ipr_auto_create = 1;
 static DEFINE_SPINLOCK(ipr_driver_lock);
 
 /* This table describes the differences between DMA controller chips */
 static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
-	{ /* Gemstone and Citrine */
+	{ /* Gemstone, Citrine, and Obsidian */
 		.mailbox = 0x0042C,
 		.cache_line_size = 0x20,
 		{
@@ -130,6 +133,8 @@
 static const struct ipr_chip_t ipr_chip[] = {
 	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, &ipr_chip_cfg[0] },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] }
 };
@@ -150,6 +155,12 @@
 MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries");
 module_param_named(transop_timeout, ipr_transop_timeout, int, 0);
 MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)");
+module_param_named(enable_cache, ipr_enable_cache, int, 0);
+MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)");
+module_param_named(debug, ipr_debug, int, 0);
+MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
+module_param_named(auto_create, ipr_auto_create, int, 0);
+MODULE_PARM_DESC(auto_create, "Auto-create single device RAID 0 arrays when initialized (default: 1)");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(IPR_DRIVER_VERSION);
 
@@ -285,12 +296,18 @@
 	"3110: Device bus error, message or command phase"},
 	{0x04670400, 0, 1,
 	"9091: Incorrect hardware configuration change has been detected"},
+	{0x04678000, 0, 1,
+	"9073: Invalid multi-adapter configuration"},
 	{0x046E0000, 0, 1,
 	"FFF4: Command to logical unit failed"},
 	{0x05240000, 1, 0,
 	"Illegal request, invalid request type or request packet"},
 	{0x05250000, 0, 0,
 	"Illegal request, invalid resource handle"},
+	{0x05258000, 0, 0,
+	"Illegal request, commands not allowed to this device"},
+	{0x05258100, 0, 0,
+	"Illegal request, command not allowed to a secondary adapter"},
 	{0x05260000, 0, 0,
 	"Illegal request, invalid field in parameter list"},
 	{0x05260100, 0, 0,
@@ -299,6 +316,8 @@
 	"Illegal request, parameter value invalid"},
 	{0x052C0000, 0, 0,
 	"Illegal request, command sequence error"},
+	{0x052C8000, 1, 0,
+	"Illegal request, dual adapter support not enabled"},
 	{0x06040500, 0, 1,
 	"9031: Array protection temporarily suspended, protection resuming"},
 	{0x06040600, 0, 1,
@@ -315,18 +334,26 @@
 	"3029: A device replacement has occurred"},
 	{0x064C8000, 0, 1,
 	"9051: IOA cache data exists for a missing or failed device"},
+	{0x064C8100, 0, 1,
+	"9055: Auxiliary cache IOA contains cache data needed by the primary IOA"},
 	{0x06670100, 0, 1,
 	"9025: Disk unit is not supported at its physical location"},
 	{0x06670600, 0, 1,
 	"3020: IOA detected a SCSI bus configuration error"},
 	{0x06678000, 0, 1,
 	"3150: SCSI bus configuration error"},
+	{0x06678100, 0, 1,
+	"9074: Asymmetric advanced function disk configuration"},
 	{0x06690200, 0, 1,
 	"9041: Array protection temporarily suspended"},
 	{0x06698200, 0, 1,
 	"9042: Corrupt array parity detected on specified device"},
 	{0x066B0200, 0, 1,
 	"9030: Array no longer protected due to missing or failed disk unit"},
+	{0x066B8000, 0, 1,
+	"9071: Link operational transition"},
+	{0x066B8100, 0, 1,
+	"9072: Link not operational transition"},
 	{0x066B8200, 0, 1,
 	"9032: Array exposed but still protected"},
 	{0x07270000, 0, 0,
@@ -789,7 +816,7 @@
  **/
 static void ipr_init_res_entry(struct ipr_resource_entry *res)
 {
-	res->needs_sync_complete = 1;
+	res->needs_sync_complete = 0;
 	res->in_erp = 0;
 	res->add_to_ml = 0;
 	res->del_from_ml = 0;
@@ -889,29 +916,74 @@
 
 /**
  * ipr_log_vpd - Log the passed VPD to the error log.
- * @vpids:			vendor/product id struct
- * @serial_num:		serial number string
+ * @vpd:		vendor/product id/sn struct
  *
  * Return value:
  * 	none
  **/
-static void ipr_log_vpd(struct ipr_std_inq_vpids *vpids, u8 *serial_num)
+static void ipr_log_vpd(struct ipr_vpd *vpd)
 {
 	char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN
 		    + IPR_SERIAL_NUM_LEN];
 
-	memcpy(buffer, vpids->vendor_id, IPR_VENDOR_ID_LEN);
-	memcpy(buffer + IPR_VENDOR_ID_LEN, vpids->product_id,
+	memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN);
+	memcpy(buffer + IPR_VENDOR_ID_LEN, vpd->vpids.product_id,
 	       IPR_PROD_ID_LEN);
 	buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN] = '\0';
 	ipr_err("Vendor/Product ID: %s\n", buffer);
 
-	memcpy(buffer, serial_num, IPR_SERIAL_NUM_LEN);
+	memcpy(buffer, vpd->sn, IPR_SERIAL_NUM_LEN);
 	buffer[IPR_SERIAL_NUM_LEN] = '\0';
 	ipr_err("    Serial Number: %s\n", buffer);
 }
 
 /**
+ * ipr_log_ext_vpd - Log the passed extended VPD to the error log.
+ * @vpd:		vendor/product id/sn/wwn struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_ext_vpd(struct ipr_ext_vpd *vpd)
+{
+	ipr_log_vpd(&vpd->vpd);
+	ipr_err("    WWN: %08X%08X\n", be32_to_cpu(vpd->wwid[0]),
+		be32_to_cpu(vpd->wwid[1]));
+}
+
+/**
+ * ipr_log_enhanced_cache_error - Log a cache error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_enhanced_cache_error(struct ipr_ioa_cfg *ioa_cfg,
+					 struct ipr_hostrcb *hostrcb)
+{
+	struct ipr_hostrcb_type_12_error *error =
+		&hostrcb->hcam.u.error.u.type_12_error;
+
+	ipr_err("-----Current Configuration-----\n");
+	ipr_err("Cache Directory Card Information:\n");
+	ipr_log_ext_vpd(&error->ioa_vpd);
+	ipr_err("Adapter Card Information:\n");
+	ipr_log_ext_vpd(&error->cfc_vpd);
+
+	ipr_err("-----Expected Configuration-----\n");
+	ipr_err("Cache Directory Card Information:\n");
+	ipr_log_ext_vpd(&error->ioa_last_attached_to_cfc_vpd);
+	ipr_err("Adapter Card Information:\n");
+	ipr_log_ext_vpd(&error->cfc_last_attached_to_ioa_vpd);
+
+	ipr_err("Additional IOA Data: %08X %08X %08X\n",
+		     be32_to_cpu(error->ioa_data[0]),
+		     be32_to_cpu(error->ioa_data[1]),
+		     be32_to_cpu(error->ioa_data[2]));
+}
+
+/**
  * ipr_log_cache_error - Log a cache error.
  * @ioa_cfg:	ioa config struct
  * @hostrcb:	hostrcb struct
@@ -927,17 +999,15 @@
 
 	ipr_err("-----Current Configuration-----\n");
 	ipr_err("Cache Directory Card Information:\n");
-	ipr_log_vpd(&error->ioa_vpids, error->ioa_sn);
+	ipr_log_vpd(&error->ioa_vpd);
 	ipr_err("Adapter Card Information:\n");
-	ipr_log_vpd(&error->cfc_vpids, error->cfc_sn);
+	ipr_log_vpd(&error->cfc_vpd);
 
 	ipr_err("-----Expected Configuration-----\n");
 	ipr_err("Cache Directory Card Information:\n");
-	ipr_log_vpd(&error->ioa_last_attached_to_cfc_vpids,
-		    error->ioa_last_attached_to_cfc_sn);
+	ipr_log_vpd(&error->ioa_last_attached_to_cfc_vpd);
 	ipr_err("Adapter Card Information:\n");
-	ipr_log_vpd(&error->cfc_last_attached_to_ioa_vpids,
-		    error->cfc_last_attached_to_ioa_sn);
+	ipr_log_vpd(&error->cfc_last_attached_to_ioa_vpd);
 
 	ipr_err("Additional IOA Data: %08X %08X %08X\n",
 		     be32_to_cpu(error->ioa_data[0]),
@@ -946,6 +1016,46 @@
 }
 
 /**
+ * ipr_log_enhanced_config_error - Log a configuration error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_enhanced_config_error(struct ipr_ioa_cfg *ioa_cfg,
+					  struct ipr_hostrcb *hostrcb)
+{
+	int errors_logged, i;
+	struct ipr_hostrcb_device_data_entry_enhanced *dev_entry;
+	struct ipr_hostrcb_type_13_error *error;
+
+	error = &hostrcb->hcam.u.error.u.type_13_error;
+	errors_logged = be32_to_cpu(error->errors_logged);
+
+	ipr_err("Device Errors Detected/Logged: %d/%d\n",
+		be32_to_cpu(error->errors_detected), errors_logged);
+
+	dev_entry = error->dev;
+
+	for (i = 0; i < errors_logged; i++, dev_entry++) {
+		ipr_err_separator;
+
+		ipr_phys_res_err(ioa_cfg, dev_entry->dev_res_addr, "Device %d", i + 1);
+		ipr_log_ext_vpd(&dev_entry->vpd);
+
+		ipr_err("-----New Device Information-----\n");
+		ipr_log_ext_vpd(&dev_entry->new_vpd);
+
+		ipr_err("Cache Directory Card Information:\n");
+		ipr_log_ext_vpd(&dev_entry->ioa_last_with_dev_vpd);
+
+		ipr_err("Adapter Card Information:\n");
+		ipr_log_ext_vpd(&dev_entry->cfc_last_with_dev_vpd);
+	}
+}
+
+/**
  * ipr_log_config_error - Log a configuration error.
  * @ioa_cfg:	ioa config struct
  * @hostrcb:	hostrcb struct
@@ -966,30 +1076,22 @@
 	ipr_err("Device Errors Detected/Logged: %d/%d\n",
 		be32_to_cpu(error->errors_detected), errors_logged);
 
-	dev_entry = error->dev_entry;
+	dev_entry = error->dev;
 
 	for (i = 0; i < errors_logged; i++, dev_entry++) {
 		ipr_err_separator;
 
-		if (dev_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) {
-			ipr_err("Device %d: missing\n", i + 1);
-		} else {
-			ipr_err("Device %d: %d:%d:%d:%d\n", i + 1,
-				ioa_cfg->host->host_no, dev_entry->dev_res_addr.bus,
-				dev_entry->dev_res_addr.target, dev_entry->dev_res_addr.lun);
-		}
-		ipr_log_vpd(&dev_entry->dev_vpids, dev_entry->dev_sn);
+		ipr_phys_res_err(ioa_cfg, dev_entry->dev_res_addr, "Device %d", i + 1);
+		ipr_log_vpd(&dev_entry->vpd);
 
 		ipr_err("-----New Device Information-----\n");
-		ipr_log_vpd(&dev_entry->new_dev_vpids, dev_entry->new_dev_sn);
+		ipr_log_vpd(&dev_entry->new_vpd);
 
 		ipr_err("Cache Directory Card Information:\n");
-		ipr_log_vpd(&dev_entry->ioa_last_with_dev_vpids,
-			    dev_entry->ioa_last_with_dev_sn);
+		ipr_log_vpd(&dev_entry->ioa_last_with_dev_vpd);
 
 		ipr_err("Adapter Card Information:\n");
-		ipr_log_vpd(&dev_entry->cfc_last_with_dev_vpids,
-			    dev_entry->cfc_last_with_dev_sn);
+		ipr_log_vpd(&dev_entry->cfc_last_with_dev_vpd);
 
 		ipr_err("Additional IOA Data: %08X %08X %08X %08X %08X\n",
 			be32_to_cpu(dev_entry->ioa_data[0]),
@@ -1001,6 +1103,57 @@
 }
 
 /**
+ * ipr_log_enhanced_array_error - Log an array configuration error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_enhanced_array_error(struct ipr_ioa_cfg *ioa_cfg,
+					 struct ipr_hostrcb *hostrcb)
+{
+	int i, num_entries;
+	struct ipr_hostrcb_type_14_error *error;
+	struct ipr_hostrcb_array_data_entry_enhanced *array_entry;
+	const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' };
+
+	error = &hostrcb->hcam.u.error.u.type_14_error;
+
+	ipr_err_separator;
+
+	ipr_err("RAID %s Array Configuration: %d:%d:%d:%d\n",
+		error->protection_level,
+		ioa_cfg->host->host_no,
+		error->last_func_vset_res_addr.bus,
+		error->last_func_vset_res_addr.target,
+		error->last_func_vset_res_addr.lun);
+
+	ipr_err_separator;
+
+	array_entry = error->array_member;
+	num_entries = min_t(u32, be32_to_cpu(error->num_entries),
+			    sizeof(error->array_member));
+
+	for (i = 0; i < num_entries; i++, array_entry++) {
+		if (!memcmp(array_entry->vpd.vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN))
+			continue;
+
+		if (be32_to_cpu(error->exposed_mode_adn) == i)
+			ipr_err("Exposed Array Member %d:\n", i);
+		else
+			ipr_err("Array Member %d:\n", i);
+
+		ipr_log_ext_vpd(&array_entry->vpd);
+		ipr_phys_res_err(ioa_cfg, array_entry->dev_res_addr, "Current Location");
+		ipr_phys_res_err(ioa_cfg, array_entry->expected_dev_res_addr,
+				 "Expected Location");
+
+		ipr_err_separator;
+	}
+}
+
+/**
  * ipr_log_array_error - Log an array configuration error.
  * @ioa_cfg:	ioa config struct
  * @hostrcb:	hostrcb struct
@@ -1032,36 +1185,19 @@
 	array_entry = error->array_member;
 
 	for (i = 0; i < 18; i++) {
-		if (!memcmp(array_entry->serial_num, zero_sn, IPR_SERIAL_NUM_LEN))
+		if (!memcmp(array_entry->vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN))
 			continue;
 
-		if (be32_to_cpu(error->exposed_mode_adn) == i) {
+		if (be32_to_cpu(error->exposed_mode_adn) == i)
 			ipr_err("Exposed Array Member %d:\n", i);
-		} else {
+		else
 			ipr_err("Array Member %d:\n", i);
-		}
 
-		ipr_log_vpd(&array_entry->vpids, array_entry->serial_num);
+		ipr_log_vpd(&array_entry->vpd);
 
-		if (array_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) {
-			ipr_err("Current Location: unknown\n");
-		} else {
-			ipr_err("Current Location: %d:%d:%d:%d\n",
-				ioa_cfg->host->host_no,
-				array_entry->dev_res_addr.bus,
-				array_entry->dev_res_addr.target,
-				array_entry->dev_res_addr.lun);
-		}
-
-		if (array_entry->expected_dev_res_addr.bus >= IPR_MAX_NUM_BUSES) {
-			ipr_err("Expected Location: unknown\n");
-		} else {
-			ipr_err("Expected Location: %d:%d:%d:%d\n",
-				ioa_cfg->host->host_no,
-				array_entry->expected_dev_res_addr.bus,
-				array_entry->expected_dev_res_addr.target,
-				array_entry->expected_dev_res_addr.lun);
-		}
+		ipr_phys_res_err(ioa_cfg, array_entry->dev_res_addr, "Current Location");
+		ipr_phys_res_err(ioa_cfg, array_entry->expected_dev_res_addr,
+				 "Expected Location");
 
 		ipr_err_separator;
 
@@ -1073,6 +1209,80 @@
 }
 
 /**
+ * ipr_log_hex_data - Log additional hex IOA error data.
+ * @data:		IOA error data
+ * @len:		data length
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_hex_data(u32 *data, int len)
+{
+	int i;
+
+	if (len == 0)
+		return;
+
+	for (i = 0; i < len / 4; i += 4) {
+		ipr_err("%08X: %08X %08X %08X %08X\n", i*4,
+			be32_to_cpu(data[i]),
+			be32_to_cpu(data[i+1]),
+			be32_to_cpu(data[i+2]),
+			be32_to_cpu(data[i+3]));
+	}
+}
+
+/**
+ * ipr_log_enhanced_dual_ioa_error - Log an enhanced dual adapter error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
+					    struct ipr_hostrcb *hostrcb)
+{
+	struct ipr_hostrcb_type_17_error *error;
+
+	error = &hostrcb->hcam.u.error.u.type_17_error;
+	error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+
+	ipr_err("%s\n", error->failure_reason);
+	ipr_err("Remote Adapter VPD:\n");
+	ipr_log_ext_vpd(&error->vpd);
+	ipr_log_hex_data(error->data,
+			 be32_to_cpu(hostrcb->hcam.length) -
+			 (offsetof(struct ipr_hostrcb_error, u) +
+			  offsetof(struct ipr_hostrcb_type_17_error, data)));
+}
+
+/**
+ * ipr_log_dual_ioa_error - Log a dual adapter error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
+				   struct ipr_hostrcb *hostrcb)
+{
+	struct ipr_hostrcb_type_07_error *error;
+
+	error = &hostrcb->hcam.u.error.u.type_07_error;
+	error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+
+	ipr_err("%s\n", error->failure_reason);
+	ipr_err("Remote Adapter VPD:\n");
+	ipr_log_vpd(&error->vpd);
+	ipr_log_hex_data(error->data,
+			 be32_to_cpu(hostrcb->hcam.length) -
+			 (offsetof(struct ipr_hostrcb_error, u) +
+			  offsetof(struct ipr_hostrcb_type_07_error, data)));
+}
+
+/**
  * ipr_log_generic_error - Log an adapter error.
  * @ioa_cfg:	ioa config struct
  * @hostrcb:	hostrcb struct
@@ -1083,22 +1293,8 @@
 static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg,
 				  struct ipr_hostrcb *hostrcb)
 {
-	int i;
-	int ioa_data_len = be32_to_cpu(hostrcb->hcam.length);
-
-	if (ioa_data_len == 0)
-		return;
-
-	ipr_err("IOA Error Data:\n");
-	ipr_err("Offset    0 1 2 3  4 5 6 7  8 9 A B  C D E F\n");
-
-	for (i = 0; i < ioa_data_len / 4; i += 4) {
-		ipr_err("%08X: %08X %08X %08X %08X\n", i*4,
-			be32_to_cpu(hostrcb->hcam.u.raw.data[i]),
-			be32_to_cpu(hostrcb->hcam.u.raw.data[i+1]),
-			be32_to_cpu(hostrcb->hcam.u.raw.data[i+2]),
-			be32_to_cpu(hostrcb->hcam.u.raw.data[i+3]));
-	}
+	ipr_log_hex_data(hostrcb->hcam.u.raw.data,
+			 be32_to_cpu(hostrcb->hcam.length));
 }
 
 /**
@@ -1172,11 +1368,10 @@
 
 	if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
 		return;
+	if (be32_to_cpu(hostrcb->hcam.length) > sizeof(hostrcb->hcam.u.raw))
+		hostrcb->hcam.length = cpu_to_be32(sizeof(hostrcb->hcam.u.raw));
 
 	switch (hostrcb->hcam.overlay_id) {
-	case IPR_HOST_RCB_OVERLAY_ID_1:
-		ipr_log_generic_error(ioa_cfg, hostrcb);
-		break;
 	case IPR_HOST_RCB_OVERLAY_ID_2:
 		ipr_log_cache_error(ioa_cfg, hostrcb);
 		break;
@@ -1187,13 +1382,26 @@
 	case IPR_HOST_RCB_OVERLAY_ID_6:
 		ipr_log_array_error(ioa_cfg, hostrcb);
 		break;
-	case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:
-		ipr_log_generic_error(ioa_cfg, hostrcb);
+	case IPR_HOST_RCB_OVERLAY_ID_7:
+		ipr_log_dual_ioa_error(ioa_cfg, hostrcb);
 		break;
+	case IPR_HOST_RCB_OVERLAY_ID_12:
+		ipr_log_enhanced_cache_error(ioa_cfg, hostrcb);
+		break;
+	case IPR_HOST_RCB_OVERLAY_ID_13:
+		ipr_log_enhanced_config_error(ioa_cfg, hostrcb);
+		break;
+	case IPR_HOST_RCB_OVERLAY_ID_14:
+	case IPR_HOST_RCB_OVERLAY_ID_16:
+		ipr_log_enhanced_array_error(ioa_cfg, hostrcb);
+		break;
+	case IPR_HOST_RCB_OVERLAY_ID_17:
+		ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb);
+		break;
+	case IPR_HOST_RCB_OVERLAY_ID_1:
+	case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:
 	default:
-		dev_err(&ioa_cfg->pdev->dev,
-			"Unknown error received. Overlay ID: %d\n",
-			hostrcb->hcam.overlay_id);
+		ipr_log_generic_error(ioa_cfg, hostrcb);
 		break;
 	}
 }
@@ -1972,6 +2180,103 @@
 };
 #endif
 
+static const struct {
+	enum ipr_cache_state state;
+	char *name;
+} cache_state [] = {
+	{ CACHE_NONE, "none" },
+	{ CACHE_DISABLED, "disabled" },
+	{ CACHE_ENABLED, "enabled" }
+};
+
+/**
+ * ipr_show_write_caching - Show the write caching attribute
+ * @class_dev:	class device struct
+ * @buf:		buffer
+ *
+ * Return value:
+ *	number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_write_caching(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags = 0;
+	int i, len = 0;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	for (i = 0; i < ARRAY_SIZE(cache_state); i++) {
+		if (cache_state[i].state == ioa_cfg->cache_state) {
+			len = snprintf(buf, PAGE_SIZE, "%s\n", cache_state[i].name);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return len;
+}
+
+
+/**
+ * ipr_store_write_caching - Enable/disable adapter write cache
+ * @class_dev:	class_device struct
+ * @buf:		buffer
+ * @count:		buffer size
+ *
+ * This function will enable/disable adapter write cache.
+ *
+ * Return value:
+ * 	count on success / other on failure
+ **/
+static ssize_t ipr_store_write_caching(struct class_device *class_dev,
+					const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags = 0;
+	enum ipr_cache_state new_state = CACHE_INVALID;
+	int i;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (ioa_cfg->cache_state == CACHE_NONE)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(cache_state); i++) {
+		if (!strncmp(cache_state[i].name, buf, strlen(cache_state[i].name))) {
+			new_state = cache_state[i].state;
+			break;
+		}
+	}
+
+	if (new_state != CACHE_DISABLED && new_state != CACHE_ENABLED)
+		return -EINVAL;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	if (ioa_cfg->cache_state == new_state) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return count;
+	}
+
+	ioa_cfg->cache_state = new_state;
+	dev_info(&ioa_cfg->pdev->dev, "%s adapter write cache.\n",
+		 new_state == CACHE_ENABLED ? "Enabling" : "Disabling");
+	if (!ioa_cfg->in_reset_reload)
+		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+
+	return count;
+}
+
+static struct class_device_attribute ipr_ioa_cache_attr = {
+	.attr = {
+		.name =		"write_cache",
+		.mode =		S_IRUGO | S_IWUSR,
+	},
+	.show = ipr_show_write_caching,
+	.store = ipr_store_write_caching
+};
+
 /**
  * ipr_show_fw_version - Show the firmware version
  * @class_dev:	class device struct
@@ -2112,6 +2417,74 @@
 };
 
 /**
+ * ipr_show_adapter_state - Show the adapter's state
+ * @class_dev:	class device struct
+ * @buf:		buffer
+ *
+ * Return value:
+ * 	number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_adapter_state(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags = 0;
+	int len;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	if (ioa_cfg->ioa_is_dead)
+		len = snprintf(buf, PAGE_SIZE, "offline\n");
+	else
+		len = snprintf(buf, PAGE_SIZE, "online\n");
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return len;
+}
+
+/**
+ * ipr_store_adapter_state - Change adapter state
+ * @class_dev:	class_device struct
+ * @buf:		buffer
+ * @count:		buffer size
+ *
+ * This function will change the adapter's state.
+ *
+ * Return value:
+ * 	count on success / other on failure
+ **/
+static ssize_t ipr_store_adapter_state(struct class_device *class_dev,
+				       const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags;
+	int result = count;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	if (ioa_cfg->ioa_is_dead && !strncmp(buf, "online", 6)) {
+		ioa_cfg->ioa_is_dead = 0;
+		ioa_cfg->reset_retries = 0;
+		ioa_cfg->in_ioa_bringdown = 0;
+		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+	}
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+
+	return result;
+}
+
+static struct class_device_attribute ipr_ioa_state_attr = {
+	.attr = {
+		.name =		"state",
+		.mode =		S_IRUGO | S_IWUSR,
+	},
+	.show = ipr_show_adapter_state,
+	.store = ipr_store_adapter_state
+};
+
+/**
  * ipr_store_reset_adapter - Reset the adapter
  * @class_dev:	class_device struct
  * @buf:		buffer
@@ -2183,7 +2556,7 @@
 		num_elem = buf_len / bsize_elem;
 
 	/* Allocate a scatter/gather list for the DMA */
-	sglist = kmalloc(sizeof(struct ipr_sglist) +
+	sglist = kzalloc(sizeof(struct ipr_sglist) +
 			 (sizeof(struct scatterlist) * (num_elem - 1)),
 			 GFP_KERNEL);
 
@@ -2192,9 +2565,6 @@
 		return NULL;
 	}
 
-	memset(sglist, 0, sizeof(struct ipr_sglist) +
-	       (sizeof(struct scatterlist) * (num_elem - 1)));
-
 	scatterlist = sglist->scatterlist;
 
 	sglist->order = order;
@@ -2289,31 +2659,24 @@
 }
 
 /**
- * ipr_map_ucode_buffer - Map a microcode download buffer
+ * ipr_build_ucode_ioadl - Build a microcode download IOADL
  * @ipr_cmd:	ipr command struct
  * @sglist:		scatter/gather list
- * @len:		total length of download buffer
  *
- * Maps a microcode download scatter/gather list for DMA and
- * builds the IOADL.
+ * Builds a microcode download IOA data list (IOADL).
  *
- * Return value:
- * 	0 on success / -EIO on failure
  **/
-static int ipr_map_ucode_buffer(struct ipr_cmnd *ipr_cmd,
-				struct ipr_sglist *sglist, int len)
+static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd,
+				  struct ipr_sglist *sglist)
 {
-	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
 	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
 	struct scatterlist *scatterlist = sglist->scatterlist;
 	int i;
 
-	ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev, scatterlist,
-					 sglist->num_sg, DMA_TO_DEVICE);
-
+	ipr_cmd->dma_use_sg = sglist->num_dma_sg;
 	ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
-	ioarcb->write_data_transfer_length = cpu_to_be32(len);
+	ioarcb->write_data_transfer_length = cpu_to_be32(sglist->buffer_len);
 	ioarcb->write_ioadl_len =
 		cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
 
@@ -2324,15 +2687,52 @@
 			cpu_to_be32(sg_dma_address(&scatterlist[i]));
 	}
 
-	if (likely(ipr_cmd->dma_use_sg)) {
-		ioadl[i-1].flags_and_data_len |=
-			cpu_to_be32(IPR_IOADL_FLAGS_LAST);
-	}
-	else {
-		dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+	ioadl[i-1].flags_and_data_len |=
+		cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+}
+
+/**
+ * ipr_update_ioa_ucode - Update IOA's microcode
+ * @ioa_cfg:	ioa config struct
+ * @sglist:		scatter/gather list
+ *
+ * Initiate an adapter reset to update the IOA's microcode
+ *
+ * Return value:
+ * 	0 on success / -EIO on failure
+ **/
+static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg,
+				struct ipr_sglist *sglist)
+{
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	if (ioa_cfg->ucode_sglist) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		dev_err(&ioa_cfg->pdev->dev,
+			"Microcode download already in progress\n");
 		return -EIO;
 	}
 
+	sglist->num_dma_sg = pci_map_sg(ioa_cfg->pdev, sglist->scatterlist,
+					sglist->num_sg, DMA_TO_DEVICE);
+
+	if (!sglist->num_dma_sg) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		dev_err(&ioa_cfg->pdev->dev,
+			"Failed to map microcode download buffer!\n");
+		return -EIO;
+	}
+
+	ioa_cfg->ucode_sglist = sglist;
+	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	ioa_cfg->ucode_sglist = NULL;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 	return 0;
 }
 
@@ -2355,7 +2755,6 @@
 	struct ipr_ucode_image_header *image_hdr;
 	const struct firmware *fw_entry;
 	struct ipr_sglist *sglist;
-	unsigned long lock_flags;
 	char fname[100];
 	char *src;
 	int len, result, dnld_size;
@@ -2396,35 +2795,17 @@
 	if (result) {
 		dev_err(&ioa_cfg->pdev->dev,
 			"Microcode buffer copy to DMA buffer failed\n");
-		ipr_free_ucode_buffer(sglist);
-		release_firmware(fw_entry);
-		return result;
+		goto out;
 	}
 
-	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	result = ipr_update_ioa_ucode(ioa_cfg, sglist);
 
-	if (ioa_cfg->ucode_sglist) {
-		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-		dev_err(&ioa_cfg->pdev->dev,
-			"Microcode download already in progress\n");
-		ipr_free_ucode_buffer(sglist);
-		release_firmware(fw_entry);
-		return -EIO;
-	}
-
-	ioa_cfg->ucode_sglist = sglist;
-	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
-	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
-
-	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-	ioa_cfg->ucode_sglist = NULL;
-	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-
+	if (!result)
+		result = count;
+out:
 	ipr_free_ucode_buffer(sglist);
 	release_firmware(fw_entry);
-
-	return count;
+	return result;
 }
 
 static struct class_device_attribute ipr_update_fw_attr = {
@@ -2439,8 +2820,10 @@
 	&ipr_fw_version_attr,
 	&ipr_log_level_attr,
 	&ipr_diagnostics_attr,
+	&ipr_ioa_state_attr,
 	&ipr_ioa_reset_attr,
 	&ipr_update_fw_attr,
+	&ipr_ioa_cache_attr,
 	NULL,
 };
 
@@ -2548,14 +2931,13 @@
 	unsigned long lock_flags = 0;
 
 	ENTER;
-	dump = kmalloc(sizeof(struct ipr_dump), GFP_KERNEL);
+	dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL);
 
 	if (!dump) {
 		ipr_err("Dump memory allocation failed\n");
 		return -ENOMEM;
 	}
 
-	memset(dump, 0, sizeof(struct ipr_dump));
 	kref_init(&dump->kref);
 	dump->ioa_cfg = ioa_cfg;
 
@@ -2824,8 +3206,10 @@
 	if (res) {
 		if (ipr_is_af_dasd_device(res))
 			sdev->type = TYPE_RAID;
-		if (ipr_is_af_dasd_device(res) || ipr_is_ioa_resource(res))
+		if (ipr_is_af_dasd_device(res) || ipr_is_ioa_resource(res)) {
 			sdev->scsi_level = 4;
+			sdev->no_uld_attach = 1;
+		}
 		if (ipr_is_vset_device(res)) {
 			sdev->timeout = IPR_VSET_RW_TIMEOUT;
 			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
@@ -2848,13 +3232,14 @@
  * handling new commands.
  *
  * Return value:
- * 	0 on success
+ * 	0 on success / -ENXIO if device does not exist
  **/
 static int ipr_slave_alloc(struct scsi_device *sdev)
 {
 	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
 	struct ipr_resource_entry *res;
 	unsigned long lock_flags;
+	int rc = -ENXIO;
 
 	sdev->hostdata = NULL;
 
@@ -2868,14 +3253,16 @@
 			res->add_to_ml = 0;
 			res->in_erp = 0;
 			sdev->hostdata = res;
-			res->needs_sync_complete = 1;
+			if (!ipr_is_naca_model(res))
+				res->needs_sync_complete = 1;
+			rc = 0;
 			break;
 		}
 	}
 
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 
-	return 0;
+	return rc;
 }
 
 /**
@@ -2939,7 +3326,7 @@
 	ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
 	res = scsi_cmd->device->hostdata;
 
-	if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res)))
+	if (!res)
 		return FAILED;
 
 	/*
@@ -3131,7 +3518,8 @@
 	}
 
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
-	res->needs_sync_complete = 1;
+	if (!ipr_is_naca_model(res))
+		res->needs_sync_complete = 1;
 
 	LEAVE;
 	return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS);
@@ -3435,7 +3823,8 @@
 	}
 
 	if (res) {
-		res->needs_sync_complete = 1;
+		if (!ipr_is_naca_model(res))
+			res->needs_sync_complete = 1;
 		res->in_erp = 0;
 	}
 	ipr_unmap_sglist(ioa_cfg, ipr_cmd);
@@ -3705,6 +4094,30 @@
 }
 
 /**
+ * ipr_get_autosense - Copy autosense data to sense buffer
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function copies the autosense buffer to the buffer
+ * in the scsi_cmd, if there is autosense available.
+ *
+ * Return value:
+ *	1 if autosense was available / 0 if not
+ **/
+static int ipr_get_autosense(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+
+	if ((be32_to_cpu(ioasa->ioasc_specific) &
+	     (IPR_ADDITIONAL_STATUS_FMT | IPR_AUTOSENSE_VALID)) == 0)
+		return 0;
+
+	memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data,
+	       min_t(u16, be16_to_cpu(ioasa->auto_sense.auto_sense_len),
+		   SCSI_SENSE_BUFFERSIZE));
+	return 1;
+}
+
+/**
  * ipr_erp_start - Process an error response for a SCSI op
  * @ioa_cfg:	ioa config struct
  * @ipr_cmd:	ipr command struct
@@ -3734,14 +4147,19 @@
 
 	switch (ioasc & IPR_IOASC_IOASC_MASK) {
 	case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST:
-		scsi_cmd->result |= (DID_IMM_RETRY << 16);
+		if (ipr_is_naca_model(res))
+			scsi_cmd->result |= (DID_ABORT << 16);
+		else
+			scsi_cmd->result |= (DID_IMM_RETRY << 16);
 		break;
 	case IPR_IOASC_IR_RESOURCE_HANDLE:
+	case IPR_IOASC_IR_NO_CMDS_TO_2ND_IOA:
 		scsi_cmd->result |= (DID_NO_CONNECT << 16);
 		break;
 	case IPR_IOASC_HW_SEL_TIMEOUT:
 		scsi_cmd->result |= (DID_NO_CONNECT << 16);
-		res->needs_sync_complete = 1;
+		if (!ipr_is_naca_model(res))
+			res->needs_sync_complete = 1;
 		break;
 	case IPR_IOASC_SYNC_REQUIRED:
 		if (!res->in_erp)
@@ -3749,6 +4167,7 @@
 		scsi_cmd->result |= (DID_IMM_RETRY << 16);
 		break;
 	case IPR_IOASC_MED_DO_NOT_REALLOC: /* prevent retries */
+	case IPR_IOASA_IR_DUAL_IOA_DISABLED:
 		scsi_cmd->result |= (DID_PASSTHROUGH << 16);
 		break;
 	case IPR_IOASC_BUS_WAS_RESET:
@@ -3760,21 +4179,27 @@
 		if (!res->resetting_device)
 			scsi_report_bus_reset(ioa_cfg->host, scsi_cmd->device->channel);
 		scsi_cmd->result |= (DID_ERROR << 16);
-		res->needs_sync_complete = 1;
+		if (!ipr_is_naca_model(res))
+			res->needs_sync_complete = 1;
 		break;
 	case IPR_IOASC_HW_DEV_BUS_STATUS:
 		scsi_cmd->result |= IPR_IOASC_SENSE_STATUS(ioasc);
 		if (IPR_IOASC_SENSE_STATUS(ioasc) == SAM_STAT_CHECK_CONDITION) {
-			ipr_erp_cancel_all(ipr_cmd);
-			return;
+			if (!ipr_get_autosense(ipr_cmd)) {
+				if (!ipr_is_naca_model(res)) {
+					ipr_erp_cancel_all(ipr_cmd);
+					return;
+				}
+			}
 		}
-		res->needs_sync_complete = 1;
+		if (!ipr_is_naca_model(res))
+			res->needs_sync_complete = 1;
 		break;
 	case IPR_IOASC_NR_INIT_CMD_REQUIRED:
 		break;
 	default:
 		scsi_cmd->result |= (DID_ERROR << 16);
-		if (!ipr_is_vset_device(res))
+		if (!ipr_is_vset_device(res) && !ipr_is_naca_model(res))
 			res->needs_sync_complete = 1;
 		break;
 	}
@@ -4073,6 +4498,7 @@
 	ioa_cfg->in_reset_reload = 0;
 	ioa_cfg->allow_cmds = 1;
 	ioa_cfg->reset_cmd = NULL;
+	ioa_cfg->doorbell |= IPR_RUNTIME_RESET;
 
 	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
 		if (ioa_cfg->allow_ml_add_del && (res->add_to_ml || res->del_from_ml)) {
@@ -4146,7 +4572,7 @@
 	ipr_cmd->job_step = ipr_ioa_reset_done;
 
 	list_for_each_entry_continue(res, &ioa_cfg->used_res_q, queue) {
-		if (!ipr_is_af_dasd_device(res))
+		if (!IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data))
 			continue;
 
 		ipr_cmd->u.res = res;
@@ -4179,6 +4605,36 @@
 }
 
 /**
+ * ipr_setup_write_cache - Disable write cache if needed
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function sets up adapters write cache to desired setting
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_setup_write_cache(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	ipr_cmd->job_step = ipr_set_supported_devs;
+	ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next,
+				    struct ipr_resource_entry, queue);
+
+	if (ioa_cfg->cache_state != CACHE_DISABLED)
+		return IPR_RC_JOB_CONTINUE;
+
+	ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
+	ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+	ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN;
+	ipr_cmd->ioarcb.cmd_pkt.cdb[1] = IPR_SHUTDOWN_PREPARE_FOR_NORMAL;
+
+	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
  * ipr_get_mode_page - Locate specified mode page
  * @mode_pages:	mode page buffer
  * @page_code:	page code to find
@@ -4389,10 +4845,7 @@
 			      ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages),
 			      length);
 
-	ipr_cmd->job_step = ipr_set_supported_devs;
-	ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next,
-				    struct ipr_resource_entry, queue);
-
+	ipr_cmd->job_step = ipr_setup_write_cache;
 	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
 
 	LEAVE;
@@ -4431,6 +4884,51 @@
 }
 
 /**
+ * ipr_reset_cmd_failed - Handle failure of IOA reset command
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function handles the failure of an IOA bringup command.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_cmd_failed(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	dev_err(&ioa_cfg->pdev->dev,
+		"0x%02X failed with IOASC: 0x%08X\n",
+		ipr_cmd->ioarcb.cmd_pkt.cdb[0], ioasc);
+
+	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_mode_sense_failed - Handle failure of IOAFP mode sense
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function handles the failure of a Mode Sense to the IOAFP.
+ * Some adapters do not handle all mode pages.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_mode_sense_failed(struct ipr_cmnd *ipr_cmd)
+{
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) {
+		ipr_cmd->job_step = ipr_setup_write_cache;
+		return IPR_RC_JOB_CONTINUE;
+	}
+
+	return ipr_reset_cmd_failed(ipr_cmd);
+}
+
+/**
  * ipr_ioafp_mode_sense_page28 - Issue Mode Sense Page 28 to IOA
  * @ipr_cmd:	ipr command struct
  *
@@ -4451,6 +4949,7 @@
 			     sizeof(struct ipr_mode_pages));
 
 	ipr_cmd->job_step = ipr_ioafp_mode_select_page28;
+	ipr_cmd->job_step_failed = ipr_reset_mode_sense_failed;
 
 	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
 
@@ -4612,6 +5111,27 @@
 }
 
 /**
+ * ipr_inquiry_page_supported - Is the given inquiry page supported
+ * @page0:		inquiry page 0 buffer
+ * @page:		page code.
+ *
+ * This function determines if the specified inquiry page is supported.
+ *
+ * Return value:
+ *	1 if page is supported / 0 if not
+ **/
+static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page)
+{
+	int i;
+
+	for (i = 0; i < min_t(u8, page0->len, IPR_INQUIRY_PAGE0_ENTRIES); i++)
+		if (page0->page[i] == page)
+			return 1;
+
+	return 0;
+}
+
+/**
  * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter.
  * @ipr_cmd:	ipr command struct
  *
@@ -4624,6 +5144,36 @@
 static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd)
 {
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data;
+
+	ENTER;
+
+	if (!ipr_inquiry_page_supported(page0, 1))
+		ioa_cfg->cache_state = CACHE_NONE;
+
+	ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+
+	ipr_ioafp_inquiry(ipr_cmd, 1, 3,
+			  ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data),
+			  sizeof(struct ipr_inquiry_page3));
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_ioafp_page0_inquiry - Send a Page 0 Inquiry to the adapter.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function sends a Page 0 inquiry to the adapter
+ * to retrieve supported inquiry pages.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_page0_inquiry(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 	char type[5];
 
 	ENTER;
@@ -4633,11 +5183,11 @@
 	type[4] = '\0';
 	ioa_cfg->type = simple_strtoul((char *)type, NULL, 16);
 
-	ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+	ipr_cmd->job_step = ipr_ioafp_page3_inquiry;
 
-	ipr_ioafp_inquiry(ipr_cmd, 1, 3,
-			  ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data),
-			  sizeof(struct ipr_inquiry_page3));
+	ipr_ioafp_inquiry(ipr_cmd, 1, 0,
+			  ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page0_data),
+			  sizeof(struct ipr_inquiry_page0));
 
 	LEAVE;
 	return IPR_RC_JOB_RETURN;
@@ -4657,7 +5207,7 @@
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 
 	ENTER;
-	ipr_cmd->job_step = ipr_ioafp_page3_inquiry;
+	ipr_cmd->job_step = ipr_ioafp_page0_inquiry;
 
 	ipr_ioafp_inquiry(ipr_cmd, 0, 0,
 			  ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, ioa_vpd),
@@ -4815,7 +5365,7 @@
 	}
 
 	/* Enable destructive diagnostics on IOA */
-	writel(IPR_DOORBELL, ioa_cfg->regs.set_uproc_interrupt_reg);
+	writel(ioa_cfg->doorbell, ioa_cfg->regs.set_uproc_interrupt_reg);
 
 	writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg);
 	int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
@@ -5147,12 +5697,7 @@
 	ipr_cmd->ioarcb.cmd_pkt.cdb[7] = (sglist->buffer_len & 0x00ff00) >> 8;
 	ipr_cmd->ioarcb.cmd_pkt.cdb[8] = sglist->buffer_len & 0x0000ff;
 
-	if (ipr_map_ucode_buffer(ipr_cmd, sglist, sglist->buffer_len)) {
-		dev_err(&ioa_cfg->pdev->dev,
-			"Failed to map microcode download buffer\n");
-		return IPR_RC_JOB_CONTINUE;
-	}
-
+	ipr_build_ucode_ioadl(ipr_cmd, sglist);
 	ipr_cmd->job_step = ipr_reset_ucode_download_done;
 
 	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout,
@@ -5217,7 +5762,6 @@
 static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd)
 {
 	u32 rc, ioasc;
-	unsigned long scratch = ipr_cmd->u.scratch;
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 
 	do {
@@ -5233,17 +5777,13 @@
 		}
 
 		if (IPR_IOASC_SENSE_KEY(ioasc)) {
-			dev_err(&ioa_cfg->pdev->dev,
-				"0x%02X failed with IOASC: 0x%08X\n",
-				ipr_cmd->ioarcb.cmd_pkt.cdb[0], ioasc);
-
-			ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
-			list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
-			return;
+			rc = ipr_cmd->job_step_failed(ipr_cmd);
+			if (rc == IPR_RC_JOB_RETURN)
+				return;
 		}
 
 		ipr_reinit_ipr_cmnd(ipr_cmd);
-		ipr_cmd->u.scratch = scratch;
+		ipr_cmd->job_step_failed = ipr_reset_cmd_failed;
 		rc = ipr_cmd->job_step(ipr_cmd);
 	} while(rc == IPR_RC_JOB_CONTINUE);
 }
@@ -5517,15 +6057,12 @@
 	int i, rc = -ENOMEM;
 
 	ENTER;
-	ioa_cfg->res_entries = kmalloc(sizeof(struct ipr_resource_entry) *
+	ioa_cfg->res_entries = kzalloc(sizeof(struct ipr_resource_entry) *
 				       IPR_MAX_PHYSICAL_DEVS, GFP_KERNEL);
 
 	if (!ioa_cfg->res_entries)
 		goto out;
 
-	memset(ioa_cfg->res_entries, 0,
-	       sizeof(struct ipr_resource_entry) * IPR_MAX_PHYSICAL_DEVS);
-
 	for (i = 0; i < IPR_MAX_PHYSICAL_DEVS; i++)
 		list_add_tail(&ioa_cfg->res_entries[i].queue, &ioa_cfg->free_res_q);
 
@@ -5566,15 +6103,12 @@
 		list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q);
 	}
 
-	ioa_cfg->trace = kmalloc(sizeof(struct ipr_trace_entry) *
+	ioa_cfg->trace = kzalloc(sizeof(struct ipr_trace_entry) *
 				 IPR_NUM_TRACE_ENTRIES, GFP_KERNEL);
 
 	if (!ioa_cfg->trace)
 		goto out_free_hostrcb_dma;
 
-	memset(ioa_cfg->trace, 0,
-	       sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES);
-
 	rc = 0;
 out:
 	LEAVE;
@@ -5642,6 +6176,9 @@
 	ioa_cfg->host = host;
 	ioa_cfg->pdev = pdev;
 	ioa_cfg->log_level = ipr_log_level;
+	ioa_cfg->doorbell = IPR_DOORBELL;
+	if (!ipr_auto_create)
+		ioa_cfg->doorbell |= IPR_RUNTIME_RESET;
 	sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER);
 	sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL);
 	sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL);
@@ -5660,6 +6197,10 @@
 	INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread, ioa_cfg);
 	init_waitqueue_head(&ioa_cfg->reset_wait_q);
 	ioa_cfg->sdt_state = INACTIVE;
+	if (ipr_enable_cache)
+		ioa_cfg->cache_state = CACHE_ENABLED;
+	else
+		ioa_cfg->cache_state = CACHE_DISABLED;
 
 	ipr_initialize_bus_attr(ioa_cfg);
 
@@ -6008,6 +6549,7 @@
 	ipr_scan_vsets(ioa_cfg);
 	scsi_add_device(ioa_cfg->host, IPR_IOA_BUS, IPR_IOA_TARGET, IPR_IOA_LUN);
 	ioa_cfg->allow_ml_add_del = 1;
+	ioa_cfg->host->max_channel = IPR_VSET_BUS;
 	schedule_work(&ioa_cfg->work_q);
 	return 0;
 }
@@ -6055,12 +6597,30 @@
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A,
 	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B,
+		0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B,
+	      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_572A,
+	      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_572B,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780,
 		0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E,
 		0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F,
+		0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, ipr_pci_table);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 8cf9671..6bec673 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -36,23 +36,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.0.14"
-#define IPR_DRIVER_DATE "(May 2, 2005)"
-
-/*
- * IPR_DBG_TRACE: Setting this to 1 will turn on some general function tracing
- *			resulting in a bunch of extra debugging printks to the console
- *
- * IPR_DEBUG:	Setting this to 1 will turn on some error path tracing.
- *			Enables the ipr_trace macro.
- */
-#ifdef IPR_DEBUG_ALL
-#define IPR_DEBUG				1
-#define IPR_DBG_TRACE			1
-#else
-#define IPR_DEBUG				0
-#define IPR_DBG_TRACE			0
-#endif
+#define IPR_DRIVER_VERSION "2.1.0"
+#define IPR_DRIVER_DATE "(October 31, 2005)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -76,6 +61,10 @@
 #define IPR_SUBS_DEV_ID_571A	0x02C0
 #define IPR_SUBS_DEV_ID_571B	0x02BE
 #define IPR_SUBS_DEV_ID_571E  0x02BF
+#define IPR_SUBS_DEV_ID_571F	0x02D5
+#define IPR_SUBS_DEV_ID_572A	0x02C1
+#define IPR_SUBS_DEV_ID_572B	0x02C2
+#define IPR_SUBS_DEV_ID_575B	0x030D
 
 #define IPR_NAME				"ipr"
 
@@ -95,7 +84,10 @@
 #define IPR_IOASC_HW_DEV_BUS_STATUS			0x04448500
 #define	IPR_IOASC_IOASC_MASK			0xFFFFFF00
 #define	IPR_IOASC_SCSI_STATUS_MASK		0x000000FF
+#define IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT	0x05240000
 #define IPR_IOASC_IR_RESOURCE_HANDLE		0x05250000
+#define IPR_IOASC_IR_NO_CMDS_TO_2ND_IOA		0x05258100
+#define IPR_IOASA_IR_DUAL_IOA_DISABLED		0x052C8000
 #define IPR_IOASC_BUS_WAS_RESET			0x06290000
 #define IPR_IOASC_BUS_WAS_RESET_BY_OTHER		0x06298000
 #define IPR_IOASC_ABORTED_CMD_TERM_BY_HOST	0x0B5A0000
@@ -107,14 +99,14 @@
 #define IPR_NUM_LOG_HCAMS				2
 #define IPR_NUM_CFG_CHG_HCAMS				2
 #define IPR_NUM_HCAMS	(IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS)
-#define IPR_MAX_NUM_TARGETS_PER_BUS			0x10
+#define IPR_MAX_NUM_TARGETS_PER_BUS			256
 #define IPR_MAX_NUM_LUNS_PER_TARGET			256
 #define IPR_MAX_NUM_VSET_LUNS_PER_TARGET	8
 #define IPR_VSET_BUS					0xff
 #define IPR_IOA_BUS						0xff
 #define IPR_IOA_TARGET					0xff
 #define IPR_IOA_LUN						0xff
-#define IPR_MAX_NUM_BUSES				4
+#define IPR_MAX_NUM_BUSES				8
 #define IPR_MAX_BUS_TO_SCAN				IPR_MAX_NUM_BUSES
 
 #define IPR_NUM_RESET_RELOAD_RETRIES		3
@@ -205,6 +197,7 @@
 #define IPR_SDT_FMT2_EXP_ROM_SEL			0x8
 #define IPR_FMT2_SDT_READY_TO_USE			0xC4D4E3F2
 #define IPR_DOORBELL					0x82800000
+#define IPR_RUNTIME_RESET				0x40000000
 
 #define IPR_PCII_IOA_TRANS_TO_OPER			(0x80000000 >> 0)
 #define IPR_PCII_IOARCB_XFER_FAILED			(0x80000000 >> 3)
@@ -261,6 +254,16 @@
 	u8 product_id[IPR_PROD_ID_LEN];
 }__attribute__((packed));
 
+struct ipr_vpd {
+	struct ipr_std_inq_vpids vpids;
+	u8 sn[IPR_SERIAL_NUM_LEN];
+}__attribute__((packed));
+
+struct ipr_ext_vpd {
+	struct ipr_vpd vpd;
+	__be32 wwid[2];
+}__attribute__((packed));
+
 struct ipr_std_inq_data {
 	u8 peri_qual_dev_type;
 #define IPR_STD_INQ_PERI_QUAL(peri) ((peri) >> 5)
@@ -304,6 +307,10 @@
 #define IPR_SUBTYPE_GENERIC_SCSI	1
 #define IPR_SUBTYPE_VOLUME_SET		2
 
+#define IPR_QUEUEING_MODEL(res)	((((res)->cfgte.flags) & 0x70) >> 4)
+#define IPR_QUEUE_FROZEN_MODEL	0
+#define IPR_QUEUE_NACA_MODEL		1
+
 	struct ipr_res_addr res_addr;
 	__be32 res_handle;
 	__be32 reserved4[2];
@@ -410,23 +417,26 @@
 struct ipr_ioasa_vset {
 	__be32 failing_lba_hi;
 	__be32 failing_lba_lo;
-	__be32 ioa_data[22];
+	__be32 reserved;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioasa_af_dasd {
 	__be32 failing_lba;
+	__be32 reserved[2];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioasa_gpdd {
 	u8 end_state;
 	u8 bus_phase;
 	__be16 reserved;
-	__be32 ioa_data[23];
+	__be32 ioa_data[2];
 }__attribute__((packed, aligned (4)));
 
-struct ipr_ioasa_raw {
-	__be32 ioa_data[24];
-}__attribute__((packed, aligned (4)));
+struct ipr_auto_sense {
+	__be16 auto_sense_len;
+	__be16 ioa_data_len;
+	__be32 data[SCSI_SENSE_BUFFERSIZE/sizeof(__be32)];
+};
 
 struct ipr_ioasa {
 	__be32 ioasc;
@@ -453,6 +463,8 @@
 	__be32 fd_res_handle;
 
 	__be32 ioasc_specific;	/* status code specific field */
+#define IPR_ADDITIONAL_STATUS_FMT		0x80000000
+#define IPR_AUTOSENSE_VALID			0x40000000
 #define IPR_IOASC_SPECIFIC_MASK		0x00ffffff
 #define IPR_FIELD_POINTER_VALID		(0x80000000 >> 8)
 #define IPR_FIELD_POINTER_MASK		0x0000ffff
@@ -461,8 +473,9 @@
 		struct ipr_ioasa_vset vset;
 		struct ipr_ioasa_af_dasd dasd;
 		struct ipr_ioasa_gpdd gpdd;
-		struct ipr_ioasa_raw raw;
 	} u;
+
+	struct ipr_auto_sense auto_sense;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_mode_parm_hdr {
@@ -536,28 +549,49 @@
 	u8 patch_number[4];
 }__attribute__((packed));
 
+#define IPR_INQUIRY_PAGE0_ENTRIES 20
+struct ipr_inquiry_page0 {
+	u8 peri_qual_dev_type;
+	u8 page_code;
+	u8 reserved1;
+	u8 len;
+	u8 page[IPR_INQUIRY_PAGE0_ENTRIES];
+}__attribute__((packed));
+
 struct ipr_hostrcb_device_data_entry {
-	struct ipr_std_inq_vpids dev_vpids;
-	u8 dev_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_vpd vpd;
 	struct ipr_res_addr dev_res_addr;
-	struct ipr_std_inq_vpids new_dev_vpids;
-	u8 new_dev_sn[IPR_SERIAL_NUM_LEN];
-	struct ipr_std_inq_vpids ioa_last_with_dev_vpids;
-	u8 ioa_last_with_dev_sn[IPR_SERIAL_NUM_LEN];
-	struct ipr_std_inq_vpids cfc_last_with_dev_vpids;
-	u8 cfc_last_with_dev_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_vpd new_vpd;
+	struct ipr_vpd ioa_last_with_dev_vpd;
+	struct ipr_vpd cfc_last_with_dev_vpd;
 	__be32 ioa_data[5];
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb_device_data_entry_enhanced {
+	struct ipr_ext_vpd vpd;
+	u8 ccin[4];
+	struct ipr_res_addr dev_res_addr;
+	struct ipr_ext_vpd new_vpd;
+	u8 new_ccin[4];
+	struct ipr_ext_vpd ioa_last_with_dev_vpd;
+	struct ipr_ext_vpd cfc_last_with_dev_vpd;
+}__attribute__((packed, aligned (4)));
+
 struct ipr_hostrcb_array_data_entry {
-	struct ipr_std_inq_vpids vpids;
-	u8 serial_num[IPR_SERIAL_NUM_LEN];
+	struct ipr_vpd vpd;
+	struct ipr_res_addr expected_dev_res_addr;
+	struct ipr_res_addr dev_res_addr;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_array_data_entry_enhanced {
+	struct ipr_ext_vpd vpd;
+	u8 ccin[4];
 	struct ipr_res_addr expected_dev_res_addr;
 	struct ipr_res_addr dev_res_addr;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_ff_error {
-	__be32 ioa_data[246];
+	__be32 ioa_data[502];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_01_error {
@@ -568,47 +602,75 @@
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_02_error {
-	struct ipr_std_inq_vpids ioa_vpids;
-	u8 ioa_sn[IPR_SERIAL_NUM_LEN];
-	struct ipr_std_inq_vpids cfc_vpids;
-	u8 cfc_sn[IPR_SERIAL_NUM_LEN];
-	struct ipr_std_inq_vpids ioa_last_attached_to_cfc_vpids;
-	u8 ioa_last_attached_to_cfc_sn[IPR_SERIAL_NUM_LEN];
-	struct ipr_std_inq_vpids cfc_last_attached_to_ioa_vpids;
-	u8 cfc_last_attached_to_ioa_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_vpd ioa_vpd;
+	struct ipr_vpd cfc_vpd;
+	struct ipr_vpd ioa_last_attached_to_cfc_vpd;
+	struct ipr_vpd cfc_last_attached_to_ioa_vpd;
 	__be32 ioa_data[3];
-	u8 reserved[844];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_12_error {
+	struct ipr_ext_vpd ioa_vpd;
+	struct ipr_ext_vpd cfc_vpd;
+	struct ipr_ext_vpd ioa_last_attached_to_cfc_vpd;
+	struct ipr_ext_vpd cfc_last_attached_to_ioa_vpd;
+	__be32 ioa_data[3];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_03_error {
-	struct ipr_std_inq_vpids ioa_vpids;
-	u8 ioa_sn[IPR_SERIAL_NUM_LEN];
-	struct ipr_std_inq_vpids cfc_vpids;
-	u8 cfc_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_vpd ioa_vpd;
+	struct ipr_vpd cfc_vpd;
 	__be32 errors_detected;
 	__be32 errors_logged;
 	u8 ioa_data[12];
-	struct ipr_hostrcb_device_data_entry dev_entry[3];
-	u8 reserved[444];
+	struct ipr_hostrcb_device_data_entry dev[3];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_13_error {
+	struct ipr_ext_vpd ioa_vpd;
+	struct ipr_ext_vpd cfc_vpd;
+	__be32 errors_detected;
+	__be32 errors_logged;
+	struct ipr_hostrcb_device_data_entry_enhanced dev[3];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_type_04_error {
-	struct ipr_std_inq_vpids ioa_vpids;
-	u8 ioa_sn[IPR_SERIAL_NUM_LEN];
-	struct ipr_std_inq_vpids cfc_vpids;
-	u8 cfc_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_vpd ioa_vpd;
+	struct ipr_vpd cfc_vpd;
 	u8 ioa_data[12];
 	struct ipr_hostrcb_array_data_entry array_member[10];
 	__be32 exposed_mode_adn;
 	__be32 array_id;
-	struct ipr_std_inq_vpids incomp_dev_vpids;
-	u8 incomp_dev_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_vpd incomp_dev_vpd;
 	__be32 ioa_data2;
 	struct ipr_hostrcb_array_data_entry array_member2[8];
 	struct ipr_res_addr last_func_vset_res_addr;
 	u8 vset_serial_num[IPR_SERIAL_NUM_LEN];
 	u8 protection_level[8];
-	u8 reserved[124];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_14_error {
+	struct ipr_ext_vpd ioa_vpd;
+	struct ipr_ext_vpd cfc_vpd;
+	__be32 exposed_mode_adn;
+	__be32 array_id;
+	struct ipr_res_addr last_func_vset_res_addr;
+	u8 vset_serial_num[IPR_SERIAL_NUM_LEN];
+	u8 protection_level[8];
+	__be32 num_entries;
+	struct ipr_hostrcb_array_data_entry_enhanced array_member[18];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_07_error {
+	u8 failure_reason[64];
+	struct ipr_vpd vpd;
+	u32 data[222];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_17_error {
+	u8 failure_reason[64];
+	struct ipr_ext_vpd vpd;
+	u32 data[476];
 }__attribute__((packed, aligned (4)));
 
 struct ipr_hostrcb_error {
@@ -622,6 +684,11 @@
 		struct ipr_hostrcb_type_02_error type_02_error;
 		struct ipr_hostrcb_type_03_error type_03_error;
 		struct ipr_hostrcb_type_04_error type_04_error;
+		struct ipr_hostrcb_type_07_error type_07_error;
+		struct ipr_hostrcb_type_12_error type_12_error;
+		struct ipr_hostrcb_type_13_error type_13_error;
+		struct ipr_hostrcb_type_14_error type_14_error;
+		struct ipr_hostrcb_type_17_error type_17_error;
 	} u;
 }__attribute__((packed, aligned (4)));
 
@@ -655,6 +722,12 @@
 #define IPR_HOST_RCB_OVERLAY_ID_3				0x03
 #define IPR_HOST_RCB_OVERLAY_ID_4				0x04
 #define IPR_HOST_RCB_OVERLAY_ID_6				0x06
+#define IPR_HOST_RCB_OVERLAY_ID_7				0x07
+#define IPR_HOST_RCB_OVERLAY_ID_12				0x12
+#define IPR_HOST_RCB_OVERLAY_ID_13				0x13
+#define IPR_HOST_RCB_OVERLAY_ID_14				0x14
+#define IPR_HOST_RCB_OVERLAY_ID_16				0x16
+#define IPR_HOST_RCB_OVERLAY_ID_17				0x17
 #define IPR_HOST_RCB_OVERLAY_ID_DEFAULT			0xFF
 
 	u8 reserved1[3];
@@ -743,6 +816,7 @@
 
 struct ipr_misc_cbs {
 	struct ipr_ioa_vpd ioa_vpd;
+	struct ipr_inquiry_page0 page0_data;
 	struct ipr_inquiry_page3 page3_data;
 	struct ipr_mode_pages mode_pages;
 	struct ipr_supported_device supp_dev;
@@ -813,6 +887,7 @@
 struct ipr_sglist {
 	u32 order;
 	u32 num_sg;
+	u32 num_dma_sg;
 	u32 buffer_len;
 	struct scatterlist scatterlist[1];
 };
@@ -825,6 +900,13 @@
 	DUMP_OBTAINED
 };
 
+enum ipr_cache_state {
+	CACHE_NONE,
+	CACHE_DISABLED,
+	CACHE_ENABLED,
+	CACHE_INVALID
+};
+
 /* Per-controller data */
 struct ipr_ioa_cfg {
 	char eye_catcher[8];
@@ -841,6 +923,7 @@
 	u8 allow_cmds:1;
 	u8 allow_ml_add_del:1;
 
+	enum ipr_cache_state cache_state;
 	u16 type; /* CCIN of the card */
 
 	u8 log_level;
@@ -911,6 +994,7 @@
 	u16 reset_retries;
 
 	u32 errors_logged;
+	u32 doorbell;
 
 	struct Scsi_Host *host;
 	struct pci_dev *pdev;
@@ -948,6 +1032,7 @@
 	struct timer_list timer;
 	void (*done) (struct ipr_cmnd *);
 	int (*job_step) (struct ipr_cmnd *);
+	int (*job_step_failed) (struct ipr_cmnd *);
 	u16 cmd_index;
 	u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
 	dma_addr_t sense_buffer_dma;
@@ -1083,11 +1168,7 @@
 /*
  * Macros
  */
-#if IPR_DEBUG
-#define IPR_DBG_CMD(CMD) do { CMD; } while (0)
-#else
-#define IPR_DBG_CMD(CMD)
-#endif
+#define IPR_DBG_CMD(CMD) if (ipr_debug) { CMD; }
 
 #ifdef CONFIG_SCSI_IPR_TRACE
 #define ipr_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr)
@@ -1135,16 +1216,22 @@
 #define ipr_res_dbg(ioa_cfg, res, fmt, ...) \
 	IPR_DBG_CMD(ipr_res_printk(KERN_INFO, ioa_cfg, res, fmt, ##__VA_ARGS__))
 
+#define ipr_phys_res_err(ioa_cfg, res, fmt, ...)			\
+{									\
+	if ((res).bus >= IPR_MAX_NUM_BUSES) {				\
+		ipr_err(fmt": unknown\n", ##__VA_ARGS__);		\
+	} else {							\
+		ipr_err(fmt": %d:%d:%d:%d\n",				\
+			##__VA_ARGS__, (ioa_cfg)->host->host_no,	\
+			(res).bus, (res).target, (res).lun);		\
+	}								\
+}
+
 #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
 	__FILE__, __FUNCTION__, __LINE__)
 
-#if IPR_DBG_TRACE
-#define ENTER printk(KERN_INFO IPR_NAME": Entering %s\n", __FUNCTION__)
-#define LEAVE printk(KERN_INFO IPR_NAME": Leaving %s\n", __FUNCTION__)
-#else
-#define ENTER
-#define LEAVE
-#endif
+#define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __FUNCTION__))
+#define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __FUNCTION__))
 
 #define ipr_err_separator \
 ipr_err("----------------------------------------------------------\n")
@@ -1217,6 +1304,20 @@
 }
 
 /**
+ * ipr_is_naca_model - Determine if a resource is using NACA queueing model
+ * @res:	resource entry struct
+ *
+ * Return value:
+ * 	1 if NACA queueing model / 0 if not NACA queueing model
+ **/
+static inline int ipr_is_naca_model(struct ipr_resource_entry *res)
+{
+	if (ipr_is_gscsi(res) && IPR_QUEUEING_MODEL(res) == IPR_QUEUE_NACA_MODEL)
+		return 1;
+	return 0;
+}
+
+/**
  * ipr_is_device - Determine if resource address is that of a device
  * @res_addr:	resource address struct
  *
@@ -1226,7 +1327,7 @@
 static inline int ipr_is_device(struct ipr_res_addr *res_addr)
 {
 	if ((res_addr->bus < IPR_MAX_NUM_BUSES) &&
-	    (res_addr->target < IPR_MAX_NUM_TARGETS_PER_BUS))
+	    (res_addr->target < (IPR_MAX_NUM_TARGETS_PER_BUS - 1)))
 		return 1;
 
 	return 0;
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index cd9b95d..3882d48 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -139,6 +139,7 @@
 /*          - Remove 3 unused "inline" functions                             */
 /* 7.12.xx  - Use STATIC functions whereever possible                        */
 /*          - Clean up deprecated MODULE_PARM calls                          */
+/* 7.12.05  - Remove Version Matching per IBM request                        */
 /*****************************************************************************/
 
 /*
@@ -210,7 +211,7 @@
  * DRIVER_VER
  */
 #define IPS_VERSION_HIGH        "7.12"
-#define IPS_VERSION_LOW         ".02 "
+#define IPS_VERSION_LOW         ".05 "
 
 #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
 #warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
@@ -247,7 +248,7 @@
 /*
  * Function prototypes
  */
-static int ips_detect(Scsi_Host_Template *);
+static int ips_detect(struct scsi_host_template *);
 static int ips_release(struct Scsi_Host *);
 static int ips_eh_abort(Scsi_Cmnd *);
 static int ips_eh_reset(Scsi_Cmnd *);
@@ -347,8 +348,6 @@
 static int ips_host_info(ips_ha_t *, char *, off_t, int);
 static void copy_mem_info(IPS_INFOSTR *, char *, int);
 static int copy_info(IPS_INFOSTR *, char *, ...);
-static int ips_get_version_info(ips_ha_t * ha, dma_addr_t, int intr);
-static void ips_version_check(ips_ha_t * ha, int intr);
 static int ips_abort_init(ips_ha_t * ha, int index);
 static int ips_init_phase2(int index);
 
@@ -378,7 +377,7 @@
 static dma_addr_t ips_flashbusaddr;
 static long ips_FlashDataInUse;		/* CD Boot - Flash Data In Use Flag */
 static uint32_t MaxLiteCmds = 32;	/* Max Active Cmds for a Lite Adapter */
-static Scsi_Host_Template ips_driver_template = {
+static struct scsi_host_template ips_driver_template = {
 	.detect			= ips_detect,
 	.release		= ips_release,
 	.info			= ips_info,
@@ -406,8 +405,6 @@
 #endif
 };
 
-static IPS_DEFINE_COMPAT_TABLE( Compatable );	/* Version Compatability Table      */
-
 
 /* This table describes all ServeRAID Adapters */
 static struct  pci_device_id  ips_pci_table[] = {
@@ -590,7 +587,7 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_detect(Scsi_Host_Template * SHT)
+ips_detect(struct scsi_host_template * SHT)
 {
 	int i;
 
@@ -1265,9 +1262,9 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs)
+ips_select_queue_depth(struct Scsi_Host *host, struct scsi_device * scsi_devs)
 {
-	Scsi_Device *device;
+	struct scsi_device *device;
 	ips_ha_t *ha;
 	int count = 0;
 	int min;
@@ -1310,7 +1307,7 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_slave_configure(Scsi_Device * SDptr)
+ips_slave_configure(struct scsi_device * SDptr)
 {
 	ips_ha_t *ha;
 	int min;
@@ -5930,7 +5927,7 @@
 	strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4);
 	strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);
 
-	ips_version_check(ha, intr);	/* Check BIOS/FW/Driver Versions */
+	ha->nvram->versioning = 0;	/* Indicate the Driver Does Not Support Versioning */
 
 	/* now update the page */
 	if (!ips_readwrite_page5(ha, TRUE, intr)) {
@@ -6847,135 +6844,6 @@
 		return (0);
 }
 
-/*---------------------------------------------------------------------------*/
-/*   Routine Name: ips_version_check                                         */
-/*                                                                           */
-/*   Dependencies:                                                           */
-/*     Assumes that ips_read_adapter_status() is called first filling in     */
-/*     the data for SubSystem Parameters.                                    */
-/*     Called from ips_write_driver_status() so it also assumes NVRAM Page 5 */
-/*     Data is available.                                                    */
-/*                                                                           */
-/*---------------------------------------------------------------------------*/
-static void
-ips_version_check(ips_ha_t * ha, int intr)
-{
-	IPS_VERSION_DATA *VersionInfo;
-	uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1];
-	uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1];
-	int MatchError;
-	int rc;
-	char BiosString[10];
-	char FirmwareString[10];
-
-	METHOD_TRACE("ips_version_check", 1);
-
-	VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data;
-
-	memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
-	memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
-
-	/* Get the Compatible BIOS Version from NVRAM Page 5 */
-	memcpy(BiosVersion, ha->nvram->BiosCompatibilityID,
-	       IPS_COMPAT_ID_LENGTH);
-
-	rc = IPS_FAILURE;
-	if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {	/* If Versioning is Supported */
-		/* Get the Version Info with a Get Version Command */
-		memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA));
-		rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr);
-		if (rc == IPS_SUCCESS)
-			memcpy(FirmwareVersion, VersionInfo->compatibilityId,
-			       IPS_COMPAT_ID_LENGTH);
-	}
-
-	if (rc != IPS_SUCCESS) {	/* If Data Not Obtainable from a GetVersion Command */
-		/* Get the Firmware Version from Enquiry Data */
-		memcpy(FirmwareVersion, ha->enq->CodeBlkVersion,
-		       IPS_COMPAT_ID_LENGTH);
-	}
-
-	/* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */
-	/* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */
-	/* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */
-	/* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */
-
-	MatchError = 0;
-
-	if (strncmp
-	    (FirmwareVersion, Compatable[ha->nvram->adapter_type],
-	     IPS_COMPAT_ID_LENGTH) != 0)
-		MatchError = 1;
-
-	if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
-		MatchError = 1;
-
-	ha->nvram->versioning = 1;	/* Indicate the Driver Supports Versioning */
-
-	if (MatchError) {
-		ha->nvram->version_mismatch = 1;
-		if (ips_cd_boot == 0) {
-			strncpy(&BiosString[0], ha->nvram->bios_high, 4);
-			strncpy(&BiosString[4], ha->nvram->bios_low, 4);
-			BiosString[8] = 0;
-
-			strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);
-			FirmwareString[8] = 0;
-
-			IPS_PRINTK(KERN_WARNING, ha->pcidev,
-				   "Warning ! ! ! ServeRAID Version Mismatch\n");
-			IPS_PRINTK(KERN_WARNING, ha->pcidev,
-				   "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
-				   BiosString, FirmwareString, IPS_VERSION_HIGH,
-				   IPS_VERSION_LOW);
-			IPS_PRINTK(KERN_WARNING, ha->pcidev,
-				   "These levels should match to avoid possible compatibility problems.\n");
-		}
-	} else {
-		ha->nvram->version_mismatch = 0;
-	}
-
-	return;
-}
-
-/*---------------------------------------------------------------------------*/
-/*   Routine Name: ips_get_version_info                                      */
-/*                                                                           */
-/*   Routine Description:                                                    */
-/*     Issue an internal GETVERSION Command                                  */
-/*                                                                           */
-/*   Return Value:                                                           */
-/*     0 if Successful, else non-zero                                        */
-/*---------------------------------------------------------------------------*/
-static int
-ips_get_version_info(ips_ha_t * ha, dma_addr_t Buffer, int intr)
-{
-	ips_scb_t *scb;
-	int rc;
-
-	METHOD_TRACE("ips_get_version_info", 1);
-
-	scb = &ha->scbs[ha->max_cmds - 1];
-
-	ips_init_scb(ha, scb);
-
-	scb->timeout = ips_cmd_timeout;
-	scb->cdb[0] = IPS_CMD_GET_VERSION_INFO;
-	scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO;
-	scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb);
-	scb->cmd.version_info.reserved = 0;
-	scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA);
-	scb->cmd.version_info.reserved2 = 0;
-	scb->data_len = sizeof (IPS_VERSION_DATA);
-	scb->data_busaddr = Buffer;
-	scb->cmd.version_info.buffer_addr = Buffer;
-	scb->flags = 0;
-
-	/* issue command */
-	rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
-	return (rc);
-}
-
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_abort_init                                             */
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index 505e967..f46c382 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -50,6 +50,7 @@
 #ifndef _IPS_H_
    #define _IPS_H_
 
+#include <linux/version.h>
    #include <asm/uaccess.h>
    #include <asm/io.h>
 
@@ -449,13 +450,13 @@
     */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
    static int ips_proc24_info(char *, char **, off_t, int, int, int);
-   static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
+   static void ips_select_queue_depth(struct Scsi_Host *, struct scsi_device *);
    static int ips_biosparam(Disk *disk, kdev_t dev, int geom[]);
 #else
    static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
    static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
 		sector_t capacity, int geom[]);
-   static int ips_slave_configure(Scsi_Device *SDptr);
+   static int ips_slave_configure(struct scsi_device *SDptr);
 #endif
 
 /*
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index a642f73..23728d1 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -52,7 +52,7 @@
 				 * via PIO.
 				 */
 
-int jazz_esp_detect(Scsi_Host_Template *tpnt);
+int jazz_esp_detect(struct scsi_host_template *tpnt);
 static int jazz_esp_release(struct Scsi_Host *shost)
 {
 	if (shost->irq)
@@ -65,7 +65,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "jazz_esp",
 	.proc_info		= &esp_proc_info,
 	.name			= "ESP 100/100a/200",
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 1c1a7ca..e51d9a8 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -51,8 +51,8 @@
 #include <linux/jiffies.h>
 #include <linux/scatterlist.h>
 #include <scsi/scsi.h>
-#include "scsi.h"
 #include "scsi_priv.h"
+#include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 #include <asm/io.h>
@@ -1144,7 +1144,7 @@
 		 * ATA software reset (SRST, the default) does not appear
 		 * to have this problem.
 		 */
-		if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) {
+		if ((using_edd) && (dev->class == ATA_DEV_ATA)) {
 			u8 err = qc->tf.feature;
 			if (err & ATA_ABORTED) {
 				dev->class = ATA_DEV_ATAPI;
@@ -2713,7 +2713,7 @@
 /**
  *	ata_poll_qc_complete - turn irq back on and finish qc
  *	@qc: Command to complete
- *	@drv_stat: ATA status register content
+ *	@err_mask: ATA status register content
  *
  *	LOCKING:
  *	None.  (grabs host lock)
@@ -2747,7 +2747,6 @@
 	u8 status;
 	unsigned int poll_state = HSM_ST_UNKNOWN;
 	unsigned int reg_state = HSM_ST_UNKNOWN;
-	const unsigned int tmout_state = HSM_ST_TMOUT;
 
 	switch (ap->hsm_task_state) {
 	case HSM_ST:
@@ -2768,7 +2767,7 @@
 	status = ata_chk_status(ap);
 	if (status & ATA_BUSY) {
 		if (time_after(jiffies, ap->pio_task_timeout)) {
-			ap->hsm_task_state = tmout_state;
+			ap->hsm_task_state = HSM_ST_TMOUT;
 			return 0;
 		}
 		ap->hsm_task_state = poll_state;
@@ -3478,7 +3477,7 @@
 /**
  *	ata_qc_complete - Complete an active ATA command
  *	@qc: Command to complete
- *	@drv_stat: ATA Status register contents
+ *	@err_mask: ATA Status register contents
  *
  *	Indicate to the mid and upper layers that an ATA
  *	command has completed, with either an ok or not-ok status.
@@ -4564,6 +4563,7 @@
 
 	probe_ent->irq = pdev->irq;
 	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->private_data = port[0]->private_data;
 
 	if (ports & ATA_PORT_PRIMARY) {
 		probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
@@ -4600,6 +4600,7 @@
 	probe_ent->legacy_mode = 1;
 	probe_ent->n_ports = 1;
 	probe_ent->hard_port_no = port_num;
+	probe_ent->private_data = port->private_data;
 
 	switch(port_num)
 	{
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index eb604b0..261be24 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -37,9 +37,10 @@
 #include <linux/blkdev.h>
 #include <linux/spinlock.h>
 #include <scsi/scsi.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_eh.h>
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_request.h>
 #include <linux/libata.h>
 #include <linux/hdreg.h>
 #include <asm/uaccess.h>
@@ -131,7 +132,7 @@
 
 /**
  *	ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
- *	@dev: Device to whom we are issuing command
+ *	@scsidev: Device to which we are issuing command
  *	@arg: User provided data for issuing command
  *
  *	LOCKING:
@@ -147,7 +148,8 @@
 	u8 scsi_cmd[MAX_COMMAND_SIZE];
 	u8 args[4], *argbuf = NULL;
 	int argsize = 0;
-	struct scsi_request *sreq;
+	struct scsi_sense_hdr sshdr;
+	enum dma_data_direction data_dir;
 
 	if (NULL == (void *)arg)
 		return -EINVAL;
@@ -155,10 +157,6 @@
 	if (copy_from_user(args, arg, sizeof(args)))
 		return -EFAULT;
 
-	sreq = scsi_allocate_request(scsidev, GFP_KERNEL);
-	if (!sreq)
-		return -EINTR;
-
 	memset(scsi_cmd, 0, sizeof(scsi_cmd));
 
 	if (args[3]) {
@@ -172,11 +170,11 @@
 		scsi_cmd[1]  = (4 << 1); /* PIO Data-in */
 		scsi_cmd[2]  = 0x0e;     /* no off.line or cc, read from dev,
 		                            block count in sector count field */
-		sreq->sr_data_direction = DMA_FROM_DEVICE;
+		data_dir = DMA_FROM_DEVICE;
 	} else {
 		scsi_cmd[1]  = (3 << 1); /* Non-data */
 		/* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
-		sreq->sr_data_direction = DMA_NONE;
+		data_dir = DMA_NONE;
 	}
 
 	scsi_cmd[0] = ATA_16;
@@ -194,9 +192,8 @@
 
 	/* Good values for timeout and retries?  Values below
 	   from scsi_ioctl_send_command() for default case... */
-	scsi_wait_req(sreq, scsi_cmd, argbuf, argsize, (10*HZ), 5);
-
-	if (sreq->sr_result) {
+	if (scsi_execute_req(scsidev, scsi_cmd, data_dir, argbuf, argsize,
+			     &sshdr, (10*HZ), 5)) {
 		rc = -EIO;
 		goto error;
 	}
@@ -207,8 +204,6 @@
 	 && copy_to_user((void *)(arg + sizeof(args)), argbuf, argsize))
 		rc = -EFAULT;
 error:
-	scsi_release_request(sreq);
-
 	if (argbuf)
 		kfree(argbuf);
 
@@ -217,7 +212,7 @@
 
 /**
  *	ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl
- *	@dev: Device to whom we are issuing command
+ *	@scsidev: Device to which we are issuing command
  *	@arg: User provided data for issuing command
  *
  *	LOCKING:
@@ -231,7 +226,7 @@
 	int rc = 0;
 	u8 scsi_cmd[MAX_COMMAND_SIZE];
 	u8 args[7];
-	struct scsi_request *sreq;
+	struct scsi_sense_hdr sshdr;
 
 	if (NULL == (void *)arg)
 		return -EINVAL;
@@ -250,26 +245,13 @@
 	scsi_cmd[12] = args[5];
 	scsi_cmd[14] = args[0];
 
-	sreq = scsi_allocate_request(scsidev, GFP_KERNEL);
-	if (!sreq) {
-		rc = -EINTR;
-		goto error;
-	}
-
-	sreq->sr_data_direction = DMA_NONE;
 	/* Good values for timeout and retries?  Values below
-	   from scsi_ioctl_send_command() for default case... */
-	scsi_wait_req(sreq, scsi_cmd, NULL, 0, (10*HZ), 5);
-
-	if (sreq->sr_result) {
+	   from scsi_ioctl_send_command() for default case... */	
+	if (scsi_execute_req(scsidev, scsi_cmd, DMA_NONE, NULL, 0, &sshdr,
+			     (10*HZ), 5))
 		rc = -EIO;
-		goto error;
-	}
 
 	/* Need code to retrieve data from check condition? */
-
-error:
-	scsi_release_request(sreq);
 	return rc;
 }
 
@@ -416,6 +398,7 @@
 
 /**
  *	ata_to_sense_error - convert ATA error to SCSI error
+ *	@id: ATA device number
  *	@drv_stat: value contained in ATA status register
  *	@drv_err: value contained in ATA error register
  *	@sk: the sense key we'll fill out
@@ -1128,6 +1111,8 @@
 		 * length 0 means transfer 0 block of data.
 		 * However, for ATA R/W commands, sector count 0 means
 		 * 256 or 65536 sectors, not 0 sectors as in SCSI.
+		 *
+		 * WARNING: one or two older ATA drives treat 0 as 0...
 		 */
 		goto nothing_to_do;
 
@@ -2231,7 +2216,7 @@
 /**
  *	ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
  *	@qc: command structure to be initialized
- *	@cmd: SCSI command to convert
+ *	@scsicmd: SCSI command to convert
  *
  *	Handles either 12 or 16-byte versions of the CDB.
  *
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index c907238..0749811 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1704,7 +1704,6 @@
 
 static struct pci_driver lpfc_driver = {
 	.name		= LPFC_DRIVER_NAME,
-	.owner		= THIS_MODULE,
 	.id_table	= lpfc_id_table,
 	.probe		= lpfc_pci_probe_one,
 	.remove		= __devexit_p(lpfc_pci_remove_one),
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index c94c8db..e31fadd6 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -300,7 +300,7 @@
  * Model dependent ESP setup
  */
 
-int mac_esp_detect(Scsi_Host_Template * tpnt)
+int mac_esp_detect(struct scsi_host_template * tpnt)
 {
 	int quick = 0;
 	int chipnum, chipspresent = 0;
@@ -730,7 +730,7 @@
 #endif
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "mac_esp",
 	.name			= "Mac 53C9x SCSI",
 	.detect			= mac_esp_detect,
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 92d2c83..777f9bc 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -222,7 +222,7 @@
 #endif
 
 /*
- * Function : int macscsi_detect(Scsi_Host_Template * tpnt)
+ * Function : int macscsi_detect(struct scsi_host_template * tpnt)
  *
  * Purpose : initializes mac NCR5380 driver based on the
  *	command line / compile time port and irq definitions.
@@ -233,7 +233,7 @@
  *
  */
  
-int macscsi_detect(Scsi_Host_Template * tpnt)
+int macscsi_detect(struct scsi_host_template * tpnt)
 {
     static int called = 0;
     int flags = 0;
@@ -581,7 +581,7 @@
 
 #include "NCR5380.c"
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name			= "Mac5380",
 	.proc_info			= macscsi_proc_info,
 	.name				= "Macintosh NCR5380 SCSI",
diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c
index 194c754..998a8bb 100644
--- a/drivers/scsi/mca_53c9x.c
+++ b/drivers/scsi/mca_53c9x.c
@@ -103,7 +103,7 @@
 static struct ESP_regs eregs;
 
 /***************************************************************** Detection */
-static int mca_esp_detect(Scsi_Host_Template *tpnt)
+static int mca_esp_detect(struct scsi_host_template *tpnt)
 {
 	struct NCR_ESP *esp;
 	static int io_port_by_pos[] = MCA_53C9X_IO_PORTS;
@@ -444,7 +444,7 @@
 	outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR);
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "mca_53c9x",
 	.name			= "NCR 53c9x SCSI",
 	.detect			= mca_esp_detect,
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 61a6fd8..dfea346 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -362,6 +362,7 @@
 	adapter_t	*adapter;
 	scb_t	*scb;
 	int	busy=0;
+	unsigned long flags;
 
 	adapter = (adapter_t *)scmd->device->host->hostdata;
 
@@ -377,6 +378,7 @@
 	 * return 0 in that case.
 	 */
 
+	spin_lock_irqsave(&adapter->lock, flags);
 	scb = mega_build_cmd(adapter, scmd, &busy);
 
 	if(scb) {
@@ -393,6 +395,7 @@
 		}
 		return 0;
 	}
+	spin_unlock_irqrestore(&adapter->lock, flags);
 
 	return busy;
 }
@@ -1683,7 +1686,7 @@
 
 	list_for_each(pos, &adapter->completed_list) {
 
-		Scsi_Pointer* spos = (Scsi_Pointer *)pos;
+		struct scsi_pointer* spos = (struct scsi_pointer *)pos;
 
 		cmd = list_entry(spos, Scsi_Cmnd, SCp);
 		cmd->scsi_done(cmd);
@@ -1981,7 +1984,7 @@
 	mc.cmd = MEGA_CLUSTER_CMD;
 	mc.opcode = MEGA_RESET_RESERVATIONS;
 
-	if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) {
+	if( mega_internal_command(adapter, &mc, NULL) != 0 ) {
 		printk(KERN_WARNING
 				"megaraid: reservation reset failed.\n");
 	}
@@ -3011,7 +3014,7 @@
 		mc.cmd = FC_NEW_CONFIG;
 		mc.opcode = OP_DCMD_READ_CONFIG;
 
-		if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) ) {
+		if( mega_internal_command(adapter, &mc, NULL) ) {
 
 			len = sprintf(page, "40LD read config failed.\n");
 
@@ -3029,11 +3032,11 @@
 	else {
 		mc.cmd = NEW_READ_CONFIG_8LD;
 
-		if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) ) {
+		if( mega_internal_command(adapter, &mc, NULL) ) {
 
 			mc.cmd = READ_CONFIG_8LD;
 
-			if( mega_internal_command(adapter, LOCK_INT, &mc,
+			if( mega_internal_command(adapter, &mc,
 						NULL) ){
 
 				len = sprintf(page,
@@ -3632,7 +3635,7 @@
 			/*
 			 * Issue the command
 			 */
-			mega_internal_command(adapter, LOCK_INT, &mc, pthru);
+			mega_internal_command(adapter, &mc, pthru);
 
 			rval = mega_n_to_m((void __user *)arg, &mc);
 
@@ -3715,7 +3718,7 @@
 			/*
 			 * Issue the command
 			 */
-			mega_internal_command(adapter, LOCK_INT, &mc, NULL);
+			mega_internal_command(adapter, &mc, NULL);
 
 			rval = mega_n_to_m((void __user *)arg, &mc);
 
@@ -4234,7 +4237,7 @@
 	mc.opcode = OP_DEL_LOGDRV;
 	mc.subopcode = logdrv;
 
-	rval = mega_internal_command(adapter, LOCK_INT, &mc, NULL);
+	rval = mega_internal_command(adapter, &mc, NULL);
 
 	/* log this event */
 	if(rval) {
@@ -4367,7 +4370,7 @@
 
 	mc.xferaddr = (u32)dma_handle;
 
-	if ( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) {
+	if ( mega_internal_command(adapter, &mc, NULL) != 0 ) {
 		return -1;
 	}
 
@@ -4435,7 +4438,7 @@
 	mc.cmd = MEGA_MBOXCMD_PASSTHRU;
 	mc.xferaddr = (u32)pthru_dma_handle;
 
-	rval = mega_internal_command(adapter, LOCK_INT, &mc, pthru);
+	rval = mega_internal_command(adapter, &mc, pthru);
 
 	pci_free_consistent(pdev, sizeof(mega_passthru), pthru,
 			pthru_dma_handle);
@@ -4449,7 +4452,6 @@
 /**
  * mega_internal_command()
  * @adapter - pointer to our soft state
- * @ls - the scope of the exclusion lock.
  * @mc - the mailbox command
  * @pthru - Passthru structure for DCDB commands
  *
@@ -4463,8 +4465,7 @@
  * Note: parameter 'pthru' is null for non-passthru commands.
  */
 static int
-mega_internal_command(adapter_t *adapter, lockscope_t ls, megacmd_t *mc,
-		mega_passthru *pthru )
+mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
 {
 	Scsi_Cmnd	*scmd;
 	struct	scsi_device *sdev;
@@ -4508,15 +4509,8 @@
 
 	scb->idx = CMDID_INT_CMDS;
 
-	/*
-	 * Get the lock only if the caller has not acquired it already
-	 */
-	if( ls == LOCK_INT ) spin_lock_irqsave(&adapter->lock, flags);
-
 	megaraid_queue(scmd, mega_internal_done);
 
-	if( ls == LOCK_INT ) spin_unlock_irqrestore(&adapter->lock, flags);
-
 	wait_for_completion(&adapter->int_waitq);
 
 	rval = scmd->result;
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 4facf55..6f90780 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -926,13 +926,6 @@
 #define MEGA_SGLIST			0x0002
 
 /*
- * lockscope definitions, callers can specify the lock scope with this data
- * type. LOCK_INT would mean the caller has not acquired the lock before
- * making the call and LOCK_EXT would mean otherwise.
- */
-typedef enum { LOCK_INT, LOCK_EXT } lockscope_t;
-
-/*
  * Parameters for the io-mapped controllers
  */
 
@@ -1062,8 +1055,7 @@
 static int mega_del_logdrv(adapter_t *, int);
 static int mega_do_del_logdrv(adapter_t *, int);
 static void mega_get_max_sgl(adapter_t *);
-static int mega_internal_command(adapter_t *, lockscope_t, megacmd_t *,
-		mega_passthru *);
+static int mega_internal_command(adapter_t *, megacmd_t *, mega_passthru *);
 static void mega_internal_done(Scsi_Cmnd *);
 static int mega_support_cluster(adapter_t *);
 #endif
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 69df1a9..4675343 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -25,7 +25,6 @@
 #include <linux/delay.h>
 #include <linux/blkdev.h>
 #include <linux/list.h>
-#include <linux/version.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <asm/semaphore.h>
@@ -97,7 +96,6 @@
  * @param dpc_h			: tasklet handle
  * @param pdev			: pci configuration pointer for kernel
  * @param host			: pointer to host structure of mid-layer
- * @param host_lock		: pointer to appropriate lock
  * @param lock			: synchronization lock for mid-layer and driver
  * @param quiescent		: driver is quiescent for now.
  * @param outstanding_cmds	: number of commands pending in the driver
@@ -152,7 +150,6 @@
 	struct tasklet_struct	dpc_h;
 	struct pci_dev		*pdev;
 	struct Scsi_Host	*host;
-	spinlock_t		*host_lock;
 	spinlock_t		lock;
 	uint8_t			quiescent;
 	int			outstanding_cmds;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 1a3d195..4b5d420 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -533,8 +533,6 @@
 
 	// Initialize the synchronization lock for kernel and LLD
 	spin_lock_init(&adapter->lock);
-	adapter->host_lock = &adapter->lock;
-
 
 	// Initialize the command queues: the list of free SCBs and the list
 	// of pending SCBs.
@@ -715,9 +713,6 @@
 	SCSIHOST2ADAP(host)	= (caddr_t)adapter;
 	adapter->host		= host;
 
-	// export the parameters required by the mid-layer
-	scsi_assign_lock(host, adapter->host_lock);
-
 	host->irq		= adapter->irq;
 	host->unique_id		= adapter->unique_id;
 	host->can_queue		= adapter->max_cmds;
@@ -1560,10 +1555,6 @@
 	scp->scsi_done	= done;
 	scp->result	= 0;
 
-	assert_spin_locked(adapter->host_lock);
-
-	spin_unlock(adapter->host_lock);
-
 	/*
 	 * Allocate and build a SCB request
 	 * if_busy flag will be set if megaraid_mbox_build_cmd() command could
@@ -1573,23 +1564,16 @@
 	 * return 0 in that case, and we would do the callback right away.
 	 */
 	if_busy	= 0;
-	scb	= megaraid_mbox_build_cmd(adapter, scp, &if_busy);
-
-	if (scb) {
-		megaraid_mbox_runpendq(adapter, scb);
-	}
-
-	spin_lock(adapter->host_lock);
-
+	scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy);
 	if (!scb) {	// command already completed
 		done(scp);
 		return 0;
 	}
 
+	megaraid_mbox_runpendq(adapter, scb);
 	return if_busy;
 }
 
-
 /**
  * megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid
  * firmware lingua
@@ -2546,9 +2530,7 @@
 		megaraid_dealloc_scb(adapter, scb);
 
 		// send the scsi packet back to kernel
-		spin_lock(adapter->host_lock);
 		scp->scsi_done(scp);
-		spin_unlock(adapter->host_lock);
 	}
 
 	return;
@@ -2563,7 +2545,7 @@
  * aborted. All the commands issued to the F/W must complete.
  **/
 static int
-__megaraid_abort_handler(struct scsi_cmnd *scp)
+megaraid_abort_handler(struct scsi_cmnd *scp)
 {
 	adapter_t		*adapter;
 	mraid_device_t		*raid_dev;
@@ -2577,8 +2559,6 @@
 	adapter		= SCP2ADAPTER(scp);
 	raid_dev	= ADAP2RAIDDEV(adapter);
 
-	assert_spin_locked(adapter->host_lock);
-
 	con_log(CL_ANN, (KERN_WARNING
 		"megaraid: aborting-%ld cmd=%x <c=%d t=%d l=%d>\n",
 		scp->serial_number, scp->cmnd[0], SCP2CHANNEL(scp),
@@ -2658,6 +2638,7 @@
 	// traverse through the list of all SCB, since driver does not
 	// maintain these SCBs on any list
 	found = 0;
+	spin_lock_irq(&adapter->lock);
 	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
 		scb = adapter->kscb_list + i;
 
@@ -2680,6 +2661,7 @@
 			}
 		}
 	}
+	spin_unlock_irq(&adapter->lock);
 
 	if (!found) {
 		con_log(CL_ANN, (KERN_WARNING
@@ -2696,22 +2678,6 @@
 	return FAILED;
 }
 
-static int
-megaraid_abort_handler(struct scsi_cmnd *scp)
-{
-	adapter_t	*adapter;
-	int rc;
-
-	adapter		= SCP2ADAPTER(scp);
-
-	spin_lock_irq(adapter->host_lock);
-	rc = __megaraid_abort_handler(scp);
-	spin_unlock_irq(adapter->host_lock);
-
-	return rc;
-}
-
-
 /**
  * megaraid_reset_handler - device reset hadler for mailbox based driver
  * @scp		: reference command
@@ -2723,7 +2689,7 @@
  * host
  **/
 static int
-__megaraid_reset_handler(struct scsi_cmnd *scp)
+megaraid_reset_handler(struct scsi_cmnd *scp)
 {
 	adapter_t	*adapter;
 	scb_t		*scb;
@@ -2739,10 +2705,6 @@
 	adapter		= SCP2ADAPTER(scp);
 	raid_dev	= ADAP2RAIDDEV(adapter);
 
-	assert_spin_locked(adapter->host_lock);
-
-	con_log(CL_ANN, (KERN_WARNING "megaraid: reseting the host...\n"));
-
 	// return failure if adapter is not responding
 	if (raid_dev->hw_error) {
 		con_log(CL_ANN, (KERN_NOTICE
@@ -2779,8 +2741,6 @@
 			adapter->outstanding_cmds, MBOX_RESET_WAIT));
 	}
 
-	spin_unlock(adapter->host_lock);
-
 	recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
 
 	recovering = adapter->outstanding_cmds;
@@ -2806,7 +2766,7 @@
 		msleep(1000);
 	}
 
-	spin_lock(adapter->host_lock);
+	spin_lock(&adapter->lock);
 
 	// If still outstanding commands, bail out
 	if (adapter->outstanding_cmds) {
@@ -2815,7 +2775,8 @@
 
 		raid_dev->hw_error = 1;
 
-		return FAILED;
+		rval = FAILED;
+		goto out;
 	}
 	else {
 		con_log(CL_ANN, (KERN_NOTICE
@@ -2824,7 +2785,10 @@
 
 
 	// If the controller supports clustering, reset reservations
-	if (!adapter->ha) return SUCCESS;
+	if (!adapter->ha) {
+		rval = SUCCESS;
+		goto out;
+	}
 
 	// clear reservations if any
 	raw_mbox[0] = CLUSTER_CMD;
@@ -2841,22 +2805,11 @@
 				"megaraid: reservation reset failed\n"));
 	}
 
+ out:
+	spin_unlock_irq(&adapter->lock);
 	return rval;
 }
 
-static int
-megaraid_reset_handler(struct scsi_cmnd *cmd)
-{
-	int rc;
-
-	spin_lock_irq(cmd->device->host->host_lock);
-	rc = __megaraid_reset_handler(cmd);
-	spin_unlock_irq(cmd->device->host->host_lock);
-
-	return rc;
-}
-
-
 /*
  * START: internal commands library
  *
@@ -3776,9 +3729,9 @@
 	/*
 	 * Set the quiescent flag to stop issuing cmds to FW.
 	 */
-	spin_lock_irqsave(adapter->host_lock, flags);
+	spin_lock_irqsave(&adapter->lock, flags);
 	adapter->quiescent++;
-	spin_unlock_irqrestore(adapter->host_lock, flags);
+	spin_unlock_irqrestore(&adapter->lock, flags);
 
 	/*
 	 * Wait till there are no more cmds outstanding at FW. Try for at most
diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h
index 7e36c46..eb8c390 100644
--- a/drivers/scsi/megaraid/megaraid_mm.h
+++ b/drivers/scsi/megaraid/megaraid_mm.h
@@ -18,7 +18,6 @@
 #include <linux/spinlock.h>
 #include <linux/fs.h>
 #include <asm/uaccess.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 4245d05..3c32e69 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -26,7 +26,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/list.h>
-#include <linux/version.h>
 #include <linux/moduleparam.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
@@ -767,17 +766,12 @@
 		return FAILED;
 	}
 
-	spin_unlock(scmd->device->host->host_lock);
-
 	ret_val = megasas_wait_for_outstanding(instance);
-
 	if (ret_val == SUCCESS)
 		printk(KERN_NOTICE "megasas: reset successful \n");
 	else
 		printk(KERN_ERR "megasas: failed to do reset\n");
 
-	spin_lock(scmd->device->host->host_lock);
-
 	return ret_val;
 }
 
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index 2fb31ee..cb367c2 100644
--- a/drivers/scsi/mvme147.c
+++ b/drivers/scsi/mvme147.c
@@ -2,7 +2,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/interrupt.h>
 
 #include <asm/page.h>
@@ -64,7 +63,7 @@
     m147_pcc->dma_cntrl = 0;
 }
 
-int mvme147_detect(Scsi_Host_Template *tpnt)
+int mvme147_detect(struct scsi_host_template *tpnt)
 {
     static unsigned char called = 0;
     wd33c93_regs regs;
@@ -131,7 +130,7 @@
 
 #include "mvme147.h"
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "MVME147",
 	.name			= "MVME147 built-in SCSI",
 	.detect			= mvme147_detect,
diff --git a/drivers/scsi/mvme147.h b/drivers/scsi/mvme147.h
index d8903f0..2f56d69 100644
--- a/drivers/scsi/mvme147.h
+++ b/drivers/scsi/mvme147.h
@@ -10,7 +10,7 @@
 
 #include <linux/types.h>
 
-int mvme147_detect(Scsi_Host_Template *);
+int mvme147_detect(struct scsi_host_template *);
 int mvme147_release(struct Scsi_Host *);
 const char *wd33c93_info(void);
 int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
index b2d8d8e..890e9e2 100644
--- a/drivers/scsi/mvme16x.c
+++ b/drivers/scsi/mvme16x.c
@@ -7,7 +7,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -22,7 +21,7 @@
 #include<linux/stat.h>
 
 
-int mvme16x_scsi_detect(Scsi_Host_Template *tpnt)
+int mvme16x_scsi_detect(struct scsi_host_template *tpnt)
 {
     static unsigned char called = 0;
     int clock;
@@ -62,7 +61,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name			= "MVME16x NCR53c710 SCSI",
 	.detect			= mvme16x_scsi_detect,
 	.release		= mvme16x_scsi_release,
diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h
index 25173c8..c7a1253 100644
--- a/drivers/scsi/mvme16x.h
+++ b/drivers/scsi/mvme16x.h
@@ -3,7 +3,7 @@
 
 #include <linux/types.h>
 
-int mvme16x_scsi_detect(Scsi_Host_Template *);
+int mvme16x_scsi_detect(struct scsi_host_template *);
 const char *NCR53c7x0_info(void);
 int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int NCR53c7xx_abort(Scsi_Cmnd *);
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index e4ff4f0..a279ebb 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -198,7 +198,7 @@
 static int  __init    init_nsp32  (void);
 static void __exit    exit_nsp32  (void);
 
-/* struct Scsi_Host_Template */
+/* struct struct scsi_host_template */
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
 static int         nsp32_proc_info   (struct Scsi_Host *, char *, char **, off_t, int, int);
 #else
@@ -208,7 +208,7 @@
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
 static int         nsp32_detect      (struct pci_dev *pdev);
 #else
-static int         nsp32_detect      (Scsi_Host_Template *);
+static int         nsp32_detect      (struct scsi_host_template *);
 #endif
 static int         nsp32_queuecommand(struct scsi_cmnd *,
 		void (*done)(struct scsi_cmnd *));
@@ -2683,7 +2683,7 @@
 #define DETECT_OK 1
 #define DETECT_NG 0
 #define PCIDEV    (data->Pci)
-static int nsp32_detect(Scsi_Host_Template *sht)
+static int nsp32_detect(struct scsi_host_template *sht)
 #endif
 {
 	struct Scsi_Host *host;	/* registered host structure */
diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h
index 5664398..5addf9f 100644
--- a/drivers/scsi/nsp32.h
+++ b/drivers/scsi/nsp32.h
@@ -16,6 +16,7 @@
 #ifndef _NSP32_H
 #define _NSP32_H
 
+#include <linux/version.h>
 //#define NSP32_DEBUG 9
 
 /*
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index 573d7ef..5d9c9ad 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -114,7 +114,7 @@
 				 */
 
 /***************************************************************** Detection */
-int oktagon_esp_detect(Scsi_Host_Template *tpnt)
+int oktagon_esp_detect(struct scsi_host_template *tpnt)
 {
 	struct NCR_ESP *esp;
 	struct zorro_dev *z = NULL;
@@ -585,7 +585,7 @@
 }
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "esp-oktagon",
 	.proc_info		= &esp_proc_info,
 	.name			= "BSC Oktagon SCSI",
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 72bc947..f09e94a 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -369,7 +369,7 @@
 }
 
 /* 
- * Function : int pas16_detect(Scsi_Host_Template * tpnt)
+ * Function : int pas16_detect(struct scsi_host_template * tpnt)
  *
  * Purpose : detects and initializes PAS16 controllers
  *	that were autoprobed, overridden on the LILO command line, 
@@ -381,7 +381,7 @@
  *
  */
 
-int __init pas16_detect(Scsi_Host_Template * tpnt)
+int __init pas16_detect(struct scsi_host_template * tpnt)
 {
     static int current_override = 0;
     static unsigned short current_base = 0;
@@ -615,7 +615,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name           = "Pro Audio Spectrum-16 SCSI",
 	.detect         = pas16_detect,
 	.release        = pas16_release,
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index 65ce1cc..8dc5b1a 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -117,7 +117,7 @@
 static int pas16_abort(Scsi_Cmnd *);
 static int pas16_biosparam(struct scsi_device *, struct block_device *,
 			   sector_t, int*);
-static int pas16_detect(Scsi_Host_Template *);
+static int pas16_detect(struct scsi_host_template *);
 static int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int pas16_bus_reset(Scsi_Cmnd *);
 
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
index c65afc9..0ebd8ce 100644
--- a/drivers/scsi/pci2000.h
+++ b/drivers/scsi/pci2000.h
@@ -26,9 +26,6 @@
 #ifndef	PSI_EIDE_SCSIOP
 #define	PSI_EIDE_SCSIOP	1
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif 
 #define	LINUXVERSION(v,p,s)    (((v)<<16) + ((p)<<8) + (s))
 
 /************************************************/
@@ -187,7 +184,7 @@
 #endif
 
 // function prototypes
-int Pci2000_Detect			(Scsi_Host_Template *tpnt);
+int Pci2000_Detect			(struct scsi_host_template *tpnt);
 int Pci2000_Command			(Scsi_Cmnd *SCpnt);
 int Pci2000_QueueCommand	(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
 int Pci2000_Abort			(Scsi_Cmnd *SCpnt);
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 3d2f710..050ea13 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -81,7 +81,7 @@
 MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
 
 /* /usr/src/linux/drivers/scsi/hosts.h */
-static Scsi_Host_Template nsp_driver_template = {
+static struct scsi_host_template nsp_driver_template = {
 	.proc_name	         = "nsp_cs",
 	.proc_info		 = nsp_proc_info,
 	.name			 = "WorkBit NinjaSCSI-3/32Bi(16bit)",
@@ -1310,7 +1310,7 @@
 /*----------------------------------------------------------------*/
 /* look for ninja3 card and init if found			  */
 /*----------------------------------------------------------------*/
-static struct Scsi_Host *nsp_detect(Scsi_Host_Template *sht)
+static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
 {
 	struct Scsi_Host *host;	/* registered host structure */
 	nsp_hw_data *data_b = &nsp_data_base, *data;
@@ -1358,7 +1358,7 @@
 }
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static int nsp_detect_old(Scsi_Host_Template *sht)
+static int nsp_detect_old(struct scsi_host_template *sht)
 {
 	if (nsp_detect(sht) == NULL) {
 		return 0;
@@ -1717,7 +1717,7 @@
 	struct Scsi_Host *host;
 	nsp_hw_data      *data = &nsp_data_base;
 #if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
-	Scsi_Device	 *dev;
+	struct scsi_device	 *dev;
 	dev_node_t	**tail, *node;
 #endif
 
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index c201b52..f8b9430 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -303,9 +303,9 @@
 static int         nsp_cs_event  (event_t event, int priority, event_callback_args_t *args);
 
 /* Linux SCSI subsystem specific functions */
-static struct Scsi_Host *nsp_detect     (Scsi_Host_Template *sht);
+static struct Scsi_Host *nsp_detect     (struct scsi_host_template *sht);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static        int        nsp_detect_old (Scsi_Host_Template *sht);
+static        int        nsp_detect_old (struct scsi_host_template *sht);
 static        int        nsp_release_old(struct Scsi_Host *shpnt);
 #endif
 static const  char      *nsp_info       (struct Scsi_Host *shpnt);
@@ -345,7 +345,7 @@
 static int  nsp_xfer             (Scsi_Cmnd *SCpnt, int phase);
 static int  nsp_dataphase_bypass (Scsi_Cmnd *SCpnt);
 static int  nsp_reselected       (Scsi_Cmnd *SCpnt);
-static struct Scsi_Host *nsp_detect(Scsi_Host_Template *sht);
+static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht);
 
 /* Interrupt handler */
 //static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs);
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 7a516f35..bb091a4 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -72,7 +72,7 @@
 #define DEBUG(n, args...)
 #endif
 
-static Scsi_Host_Template qlogicfas_driver_template = {
+static struct scsi_host_template qlogicfas_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= qlogic_name,
 	.proc_name		= qlogic_name,
@@ -108,7 +108,7 @@
 
 static dev_info_t dev_info = "qlogic_cs";
 
-static struct Scsi_Host *qlogic_detect(Scsi_Host_Template *host,
+static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
 				dev_link_t *link, int qbase, int qlirq)
 {
 	int qltyp;		/* type of chip */
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index a50588c..f557f17 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -41,7 +41,6 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <asm/io.h>
 #include <linux/libata.h>
@@ -139,7 +138,7 @@
 static void adma_irq_clear(struct ata_port *ap);
 static void adma_eng_timeout(struct ata_port *ap);
 
-static Scsi_Host_Template adma_ata_sht = {
+static struct scsi_host_template adma_ata_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
@@ -191,7 +190,7 @@
 	},
 };
 
-static struct pci_device_id adma_ata_pci_tbl[] = {
+static const struct pci_device_id adma_ata_pci_tbl[] = {
 	{ PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_1841_idx },
 
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index c89da7d..46624ab 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -71,7 +71,7 @@
 		up(&fc_sem);
 }
 
-int pluto_slave_configure(Scsi_Device *device)
+int pluto_slave_configure(struct scsi_device *device)
 {
 	int depth_to_use;
 
@@ -90,11 +90,11 @@
 
 /* Detect all SSAs attached to the machine.
    To be fast, do it on all online FC channels at the same time. */
-int __init pluto_detect(Scsi_Host_Template *tpnt)
+int __init pluto_detect(struct scsi_host_template *tpnt)
 {
 	int i, retry, nplutos;
 	fc_channel *fc;
-	Scsi_Device dev;
+	struct scsi_device dev;
 	DEFINE_TIMER(fc_timer, pluto_detect_timeout, 0, 0);
 
 	tpnt->proc_name = "pluto";
@@ -339,7 +339,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name			= "Sparc Storage Array 100/200",
 	.detect			= pluto_detect,
 	.release		= pluto_release,
diff --git a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h
index beb844a..5da2061 100644
--- a/drivers/scsi/pluto.h
+++ b/drivers/scsi/pluto.h
@@ -38,10 +38,10 @@
 /* This is the max number of outstanding SCSI commands per pluto */
 #define PLUTO_CAN_QUEUE		254
 
-int pluto_detect(Scsi_Host_Template *);
+int pluto_detect(struct scsi_host_template *);
 int pluto_release(struct Scsi_Host *);
 const char * pluto_info(struct Scsi_Host *);
-int pluto_slave_configure(Scsi_Device *);
+int pluto_slave_configure(struct scsi_device *);
 
 #endif /* !(_PLUTO_H) */
 
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
index 4322c95..5c2cdf5 100644
--- a/drivers/scsi/psi240i.c
+++ b/drivers/scsi/psi240i.c
@@ -538,7 +538,7 @@
  *	Returns:		Number of adapters found.
  *
  ****************************************************************/
-static int Psi240i_Detect (Scsi_Host_Template *tpnt)
+static int Psi240i_Detect (struct scsi_host_template *tpnt)
 	{
 	int					board;
 	int					count = 0;
@@ -669,7 +669,7 @@
 
 MODULE_LICENSE("GPL");
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "psi240i", 
 	.name			= "PSI-240I EIDE Disk Controller",
 	.detect			= Psi240i_Detect,
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 637fb65..0878f95 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -465,7 +465,7 @@
 	}
 	device->queue_depth = depth;
 }
-static inline struct Scsi_Host *scsi_host_alloc(Scsi_Host_Template *t, size_t s)
+static inline struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *t, size_t s)
 {
 	return scsi_register(t, s);
 }
@@ -639,10 +639,8 @@
 static struct pci_device_id qla1280_pci_tbl[] = {
 	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP12160,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-#ifdef CONFIG_SCSI_QLOGIC_1280_1040
 	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-#endif
 	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1080,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
 	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1240,
@@ -1177,7 +1175,7 @@
 
 #if LINUX_VERSION_CODE < 0x020600
 static int
-qla1280_detect(Scsi_Host_Template *template)
+qla1280_detect(struct scsi_host_template *template)
 {
 	struct pci_device_id *id = &qla1280_pci_tbl[0];
 	struct pci_dev *pdev = NULL;
@@ -4507,7 +4505,7 @@
 	.use_clustering		= ENABLE_CLUSTERING,
 };
 #else
-static Scsi_Host_Template qla1280_driver_template = {
+static struct scsi_host_template qla1280_driver_template = {
 	.proc_name		= "qla1280",
 	.name			= "Qlogic ISP 1280/12160",
 	.detect			= qla1280_detect,
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 89793c1..5c5d231 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -970,7 +970,7 @@
 	int		rval;
 	uint32_t	cnt, timer;
 	uint32_t	risc_address;
-	uint16_t	mb[4];
+	uint16_t	mb[4], wd;
 
 	uint32_t	stat;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
@@ -1514,10 +1514,10 @@
 
 		WRT_REG_DWORD(&reg->ctrl_status,
 		    CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
-		RD_REG_DWORD(&reg->ctrl_status);
+		pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
 
+		udelay(100);
 		/* Wait for firmware to complete NVRAM accesses. */
-		udelay(5);
 		mb[0] = (uint32_t) RD_REG_WORD(&reg->mailbox0);
 		for (cnt = 10000 ; cnt && mb[0]; cnt--) {
 			udelay(5);
@@ -1525,7 +1525,7 @@
 			barrier();
 		}
 
-		udelay(20);
+		/* Wait for soft-reset to complete. */
 		for (cnt = 0; cnt < 30000; cnt++) {
 			if ((RD_REG_DWORD(&reg->ctrl_status) &
 			    CSRX_ISP_SOFT_RESET) == 0)
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 72d9090..2d72012 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -147,8 +147,8 @@
 					 * LIP to complete
 					 */
 
-					if (atomic_read(&ha->loop_state) ==
-					    LOOP_DOWN && retry--) {
+					if (atomic_read(&ha->loop_state) !=
+					    LOOP_READY && retry--) {
 						goto check_fw_ready_again;
 					}
 					wait_time--;
@@ -567,6 +567,7 @@
 	unsigned long flags = 0;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 	uint32_t cnt, d2;
+	uint16_t wd;
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -581,10 +582,10 @@
 
 	WRT_REG_DWORD(&reg->ctrl_status,
 	    CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
-	RD_REG_DWORD(&reg->ctrl_status);
+	pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
 
+	udelay(100);
 	/* Wait for firmware to complete NVRAM accesses. */
-	udelay(5);
 	d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
 	for (cnt = 10000 ; cnt && d2; cnt--) {
 		udelay(5);
@@ -592,7 +593,7 @@
 		barrier();
 	}
 
-	udelay(20);
+	/* Wait for soft-reset to complete. */
 	d2 = RD_REG_DWORD(&reg->ctrl_status);
 	for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) {
 		udelay(5);
@@ -1258,9 +1259,15 @@
 	rval = qla2x00_get_adapter_id(ha,
 	    &loop_id, &al_pa, &area, &domain, &topo);
 	if (rval != QLA_SUCCESS) {
-		qla_printk(KERN_WARNING, ha,
-		    "ERROR -- Unable to get host loop ID.\n");
-		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		if (LOOP_NOT_READY(ha) || atomic_read(&ha->loop_down_timer) ||
+		    (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
+			DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
+			    __func__, ha->host_no));
+		} else {
+			qla_printk(KERN_WARNING, ha,
+			    "ERROR -- Unable to get host loop ID.\n");
+			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		}
 		return (rval);
 	}
 
@@ -1789,7 +1796,7 @@
 	}
 
 	if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
-		if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
+		if (LOOP_NOT_READY(ha)) {
 			rval = QLA_FUNCTION_FAILED;
 		} else {
 			rval = qla2x00_configure_fabric(ha);
@@ -2362,8 +2369,7 @@
 		if (qla2x00_is_reserved_id(ha, loop_id))
 			continue;
 
-		if (atomic_read(&ha->loop_down_timer) ||
-		    test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
+		if (atomic_read(&ha->loop_down_timer) || LOOP_NOT_READY(ha))
 			break;
 
 		if (swl != NULL) {
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index ad3cacb..9746cd1 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -868,10 +868,6 @@
 	DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no);)
 
 	fcport = sp->fcport;
-	if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
-	    atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
-		return 1;
-	}
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
@@ -1008,6 +1004,8 @@
 	mcp->tov = 30;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
+	if (mcp->mb[0] == MBS_COMMAND_ERROR)
+		rval = QLA_COMMAND_ERROR;
 
 	/* Return data. */
 	*id = mcp->mb[1];
@@ -2179,10 +2177,6 @@
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
 
 	fcport = sp->fcport;
-	if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
-	    atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
-		return QLA_FUNCTION_FAILED;
-	}
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 4bec0b4..d54d2a9 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -126,6 +126,7 @@
 
 	/* Wait for NVRAM to become ready */
 	WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+	RD_REG_WORD(&reg->nvram);		/* PCI Posting. */
 	do {
 		NVRAM_DELAY();
 		word = RD_REG_WORD(&reg->nvram);
@@ -178,6 +179,7 @@
 
 	/* Wait for NVRAM to become ready */
 	WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+	RD_REG_WORD(&reg->nvram);		/* PCI Posting. */
 	do {
 		NVRAM_DELAY();
 		word = RD_REG_WORD(&reg->nvram);
@@ -235,6 +237,7 @@
 	/* Read data from NVRAM. */
 	for (cnt = 0; cnt < 16; cnt++) {
 		WRT_REG_WORD(&reg->nvram, NVR_SELECT | NVR_CLOCK);
+		RD_REG_WORD(&reg->nvram);	/* PCI Posting. */
 		NVRAM_DELAY();
 		data <<= 1;
 		reg_data = RD_REG_WORD(&reg->nvram);
@@ -337,6 +340,7 @@
 
 		/* Wait for NVRAM to become ready. */
 		WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+		RD_REG_WORD(&reg->nvram);	/* PCI Posting. */
 		do {
 			NVRAM_DELAY();
 			word = RD_REG_WORD(&reg->nvram);
@@ -388,6 +392,7 @@
 
 	/* Wait for NVRAM to become ready. */
 	WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+	RD_REG_WORD(&reg->nvram);		/* PCI Posting. */
 	do {
 		NVRAM_DELAY();
 		word = RD_REG_WORD(&reg->nvram);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 0d5472f..f7937f7 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.01.00-k"
+#define QLA2XXX_VERSION      "8.01.03-k"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	1
-#define QLA_DRIVER_PATCH_VER	0
+#define QLA_DRIVER_PATCH_VER	3
 #define QLA_DRIVER_BETA_VER	0
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
index 55e698b..94baca8 100644
--- a/drivers/scsi/qlogicfas.c
+++ b/drivers/scsi/qlogicfas.c
@@ -47,7 +47,7 @@
  *	Look for qlogic card and init if found 
  */
  
-static struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host,
+static struct Scsi_Host *__qlogicfas_detect(struct scsi_host_template *host,
 								int qbase,
 								int qlirq)
 {
@@ -142,7 +142,7 @@
 MODULE_PARM_DESC(iobase, "I/O address");
 MODULE_PARM_DESC(irq, "IRQ");
 
-static int __devinit qlogicfas_detect(Scsi_Host_Template *sht)
+static int __devinit qlogicfas_detect(struct scsi_host_template *sht)
 {
 	struct Scsi_Host *shost;
 	struct qlogicfas408_priv *priv;
@@ -183,7 +183,7 @@
 /*
  *	The driver template is also needed for PCMCIA
  */
-static Scsi_Host_Template qlogicfas_driver_template = {
+static struct scsi_host_template qlogicfas_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= qlogicfas_name,
 	.proc_name		= qlogicfas_name,
diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
index a4b3b3f..94ef3f0 100644
--- a/drivers/scsi/qlogicfc.c
+++ b/drivers/scsi/qlogicfc.c
@@ -711,7 +711,7 @@
 }
 
 
-static int isp2x00_detect(Scsi_Host_Template * tmpt)
+static int isp2x00_detect(struct scsi_host_template * tmpt)
 {
 	int hosts = 0;
 	unsigned long wait_time;
@@ -2210,7 +2210,7 @@
 
 MODULE_LICENSE("GPL");
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
         .detect                 = isp2x00_detect,
         .release                = isp2x00_release,
         .info                   = isp2x00_info,
diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
deleted file mode 100644
index 6c9266b..0000000
--- a/drivers/scsi/qlogicisp.c
+++ /dev/null
@@ -1,1934 +0,0 @@
-/*
- * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI)
- * Written by Erik H. Moe, ehm@cris.com
- * Copyright 1995, Erik H. Moe
- * Copyright 1996, 1997  Michael A. Griffith <grif@acm.org>
- * Copyright 2000, Jayson C. Vantuyl <vantuyl@csc.smsu.edu>
- *             and Bryon W. Roche    <bryon@csc.smsu.edu>
- *
- * 64-bit addressing added by Kanoj Sarcar <kanoj@sgi.com>
- * 			   and Leo Dagum    <dagum@sgi.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, 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.
- */
-
-#include <linux/blkdev.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/unistd.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-/*
- * With the qlogic interface, every queue slot can hold a SCSI
- * command with up to 4 scatter/gather entries.  If we need more
- * than 4 entries, continuation entries can be used that hold
- * another 7 entries each.  Unlike for other drivers, this means
- * that the maximum number of scatter/gather entries we can
- * support at any given time is a function of the number of queue
- * slots available.  That is, host->can_queue and host->sg_tablesize
- * are dynamic and _not_ independent.  This all works fine because
- * requests are queued serially and the scatter/gather limit is
- * determined for each queue request anew.
- */
-#define QLOGICISP_REQ_QUEUE_LEN	63	/* must be power of two - 1 */
-#define QLOGICISP_MAX_SG(ql)	(4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
-
-/* Configuration section *****************************************************/
-
-/* Set the following macro to 1 to reload the ISP1020's firmware.  This is
-   the latest firmware provided by QLogic.  This may be an earlier/later
-   revision than supplied by your board. */
-
-#define RELOAD_FIRMWARE		1
-
-/* Set the following macro to 1 to reload the ISP1020's defaults from nvram.
-   If you are not sure of your settings, leave this alone, the driver will
-   use a set of 'safe' defaults */
-
-#define USE_NVRAM_DEFAULTS	0
-
-/*  Macros used for debugging */
-
-#define DEBUG_ISP1020		0
-#define DEBUG_ISP1020_INTR	0
-#define DEBUG_ISP1020_SETUP	0
-#define TRACE_ISP		0
-
-#define DEFAULT_LOOP_COUNT	1000000
-
-/* End Configuration section *************************************************/
-
-#include <linux/module.h>
-
-#if TRACE_ISP
-
-# define TRACE_BUF_LEN	(32*1024)
-
-struct {
-	u_long		next;
-	struct {
-		u_long		time;
-		u_int		index;
-		u_int		addr;
-		u_char *	name;
-	} buf[TRACE_BUF_LEN];
-} trace;
-
-#define TRACE(w, i, a)						\
-{								\
-	unsigned long flags;					\
-								\
-	trace.buf[trace.next].name  = (w);			\
-	trace.buf[trace.next].time  = jiffies;			\
-	trace.buf[trace.next].index = (i);			\
-	trace.buf[trace.next].addr  = (long) (a);		\
-	trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1);	\
-}
-
-#else
-# define TRACE(w, i, a)
-#endif
-
-#if DEBUG_ISP1020
-#define ENTER(x)	printk("isp1020 : entering %s()\n", x);
-#define LEAVE(x)	printk("isp1020 : leaving %s()\n", x);
-#define DEBUG(x)	x
-#else
-#define ENTER(x)
-#define LEAVE(x)
-#define DEBUG(x)
-#endif /* DEBUG_ISP1020 */
-
-#if DEBUG_ISP1020_INTR
-#define ENTER_INTR(x)	printk("isp1020 : entering %s()\n", x);
-#define LEAVE_INTR(x)	printk("isp1020 : leaving %s()\n", x);
-#define DEBUG_INTR(x)	x
-#else
-#define ENTER_INTR(x)
-#define LEAVE_INTR(x)
-#define DEBUG_INTR(x)
-#endif /* DEBUG ISP1020_INTR */
-
-#define ISP1020_REV_ID	1
-
-#define MAX_TARGETS	16
-#define MAX_LUNS	8
-
-/* host configuration and control registers */
-#define HOST_HCCR	0xc0	/* host command and control */
-
-/* pci bus interface registers */
-#define PCI_ID_LOW	0x00	/* vendor id */
-#define PCI_ID_HIGH	0x02	/* device id */
-#define ISP_CFG0	0x04	/* configuration register #0 */
-#define  ISP_CFG0_HWMSK  0x000f	/* Hardware revision mask */
-#define  ISP_CFG0_1020	 0x0001 /* ISP1020 */
-#define  ISP_CFG0_1020A	 0x0002 /* ISP1020A */
-#define  ISP_CFG0_1040	 0x0003 /* ISP1040 */
-#define  ISP_CFG0_1040A	 0x0004 /* ISP1040A */
-#define  ISP_CFG0_1040B	 0x0005 /* ISP1040B */
-#define  ISP_CFG0_1040C	 0x0006 /* ISP1040C */
-#define ISP_CFG1	0x06	/* configuration register #1 */
-#define  ISP_CFG1_F128	 0x0040	/* 128-byte FIFO threshold */
-#define  ISP_CFG1_F64	 0x0030	/* 128-byte FIFO threshold */
-#define  ISP_CFG1_F32	 0x0020	/* 128-byte FIFO threshold */
-#define  ISP_CFG1_F16	 0x0010	/* 128-byte FIFO threshold */
-#define  ISP_CFG1_BENAB	 0x0004	/* Global Bus burst enable */
-#define  ISP_CFG1_SXP	 0x0001	/* SXP register select */
-#define PCI_INTF_CTL	0x08	/* pci interface control */
-#define PCI_INTF_STS	0x0a	/* pci interface status */
-#define PCI_SEMAPHORE	0x0c	/* pci semaphore */
-#define PCI_NVRAM	0x0e	/* pci nvram interface */
-#define CDMA_CONF	0x20	/* Command DMA Config */
-#define DDMA_CONF	0x40	/* Data DMA Config */
-#define  DMA_CONF_SENAB	 0x0008	/* SXP to DMA Data enable */
-#define  DMA_CONF_RIRQ	 0x0004	/* RISC interrupt enable */
-#define  DMA_CONF_BENAB	 0x0002	/* Bus burst enable */
-#define  DMA_CONF_DIR	 0x0001	/* DMA direction (0=fifo->host 1=host->fifo) */
-
-/* mailbox registers */
-#define MBOX0		0x70	/* mailbox 0 */
-#define MBOX1		0x72	/* mailbox 1 */
-#define MBOX2		0x74	/* mailbox 2 */
-#define MBOX3		0x76	/* mailbox 3 */
-#define MBOX4		0x78	/* mailbox 4 */
-#define MBOX5		0x7a	/* mailbox 5 */
-#define MBOX6           0x7c    /* mailbox 6 */
-#define MBOX7           0x7e    /* mailbox 7 */
-
-/* mailbox command complete status codes */
-#define MBOX_COMMAND_COMPLETE		0x4000
-#define INVALID_COMMAND			0x4001
-#define HOST_INTERFACE_ERROR		0x4002
-#define TEST_FAILED			0x4003
-#define COMMAND_ERROR			0x4005
-#define COMMAND_PARAM_ERROR		0x4006
-
-/* async event status codes */
-#define ASYNC_SCSI_BUS_RESET		0x8001
-#define SYSTEM_ERROR			0x8002
-#define REQUEST_TRANSFER_ERROR		0x8003
-#define RESPONSE_TRANSFER_ERROR		0x8004
-#define REQUEST_QUEUE_WAKEUP		0x8005
-#define EXECUTION_TIMEOUT_RESET		0x8006
-
-#ifdef CONFIG_QL_ISP_A64
-#define IOCB_SEGS                       2
-#define CONTINUATION_SEGS               5
-#define MAX_CONTINUATION_ENTRIES        254
-#else
-#define IOCB_SEGS                       4
-#define CONTINUATION_SEGS               7
-#endif /* CONFIG_QL_ISP_A64 */
-
-struct Entry_header {
-	u_char	entry_type;
-	u_char	entry_cnt;
-	u_char	sys_def_1;
-	u_char	flags;
-};
-
-/* entry header type commands */
-#ifdef CONFIG_QL_ISP_A64
-#define ENTRY_COMMAND           9
-#define ENTRY_CONTINUATION      0xa
-#else
-#define ENTRY_COMMAND		1
-#define ENTRY_CONTINUATION	2
-#endif /* CONFIG_QL_ISP_A64 */
-
-#define ENTRY_STATUS		3
-#define ENTRY_MARKER		4
-#define ENTRY_EXTENDED_COMMAND	5
-
-/* entry header flag definitions */
-#define EFLAG_CONTINUATION	1
-#define EFLAG_BUSY		2
-#define EFLAG_BAD_HEADER	4
-#define EFLAG_BAD_PAYLOAD	8
-
-struct dataseg {
-	u_int			d_base;
-#ifdef CONFIG_QL_ISP_A64
-	u_int                   d_base_hi;
-#endif
-	u_int			d_count;
-};
-
-struct Command_Entry {
-	struct Entry_header	hdr;
-	u_int			handle;
-	u_char			target_lun;
-	u_char			target_id;
-	u_short			cdb_length;
-	u_short			control_flags;
-	u_short			rsvd;
-	u_short			time_out;
-	u_short			segment_cnt;
-	u_char			cdb[12];
-#ifdef CONFIG_QL_ISP_A64
-	u_int                   rsvd1;
-	u_int                   rsvd2;
-#endif
-	struct dataseg		dataseg[IOCB_SEGS];
-};
-
-/* command entry control flag definitions */
-#define CFLAG_NODISC		0x01
-#define CFLAG_HEAD_TAG		0x02
-#define CFLAG_ORDERED_TAG	0x04
-#define CFLAG_SIMPLE_TAG	0x08
-#define CFLAG_TAR_RTN		0x10
-#define CFLAG_READ		0x20
-#define CFLAG_WRITE		0x40
-
-struct Ext_Command_Entry {
-	struct Entry_header	hdr;
-	u_int			handle;
-	u_char			target_lun;
-	u_char			target_id;
-	u_short			cdb_length;
-	u_short			control_flags;
-	u_short			rsvd;
-	u_short			time_out;
-	u_short			segment_cnt;
-	u_char			cdb[44];
-};
-
-struct Continuation_Entry {
-	struct Entry_header	hdr;
-#ifndef CONFIG_QL_ISP_A64
-	u_int			reserved;
-#endif
-	struct dataseg		dataseg[CONTINUATION_SEGS];
-};
-
-struct Marker_Entry {
-	struct Entry_header	hdr;
-	u_int			reserved;
-	u_char			target_lun;
-	u_char			target_id;
-	u_char			modifier;
-	u_char			rsvd;
-	u_char			rsvds[52];
-};
-
-/* marker entry modifier definitions */
-#define SYNC_DEVICE	0
-#define SYNC_TARGET	1
-#define SYNC_ALL	2
-
-struct Status_Entry {
-	struct Entry_header	hdr;
-	u_int			handle;
-	u_short			scsi_status;
-	u_short			completion_status;
-	u_short			state_flags;
-	u_short			status_flags;
-	u_short			time;
-	u_short			req_sense_len;
-	u_int			residual;
-	u_char			rsvd[8];
-	u_char			req_sense_data[32];
-};
-
-/* status entry completion status definitions */
-#define CS_COMPLETE			0x0000
-#define CS_INCOMPLETE			0x0001
-#define CS_DMA_ERROR			0x0002
-#define CS_TRANSPORT_ERROR		0x0003
-#define CS_RESET_OCCURRED		0x0004
-#define CS_ABORTED			0x0005
-#define CS_TIMEOUT			0x0006
-#define CS_DATA_OVERRUN			0x0007
-#define CS_COMMAND_OVERRUN		0x0008
-#define CS_STATUS_OVERRUN		0x0009
-#define CS_BAD_MESSAGE			0x000a
-#define CS_NO_MESSAGE_OUT		0x000b
-#define CS_EXT_ID_FAILED		0x000c
-#define CS_IDE_MSG_FAILED		0x000d
-#define CS_ABORT_MSG_FAILED		0x000e
-#define CS_REJECT_MSG_FAILED		0x000f
-#define CS_NOP_MSG_FAILED		0x0010
-#define CS_PARITY_ERROR_MSG_FAILED	0x0011
-#define CS_DEVICE_RESET_MSG_FAILED	0x0012
-#define CS_ID_MSG_FAILED		0x0013
-#define CS_UNEXP_BUS_FREE		0x0014
-#define CS_DATA_UNDERRUN		0x0015
-
-/* status entry state flag definitions */
-#define SF_GOT_BUS			0x0100
-#define SF_GOT_TARGET			0x0200
-#define SF_SENT_CDB			0x0400
-#define SF_TRANSFERRED_DATA		0x0800
-#define SF_GOT_STATUS			0x1000
-#define SF_GOT_SENSE			0x2000
-
-/* status entry status flag definitions */
-#define STF_DISCONNECT			0x0001
-#define STF_SYNCHRONOUS			0x0002
-#define STF_PARITY_ERROR		0x0004
-#define STF_BUS_RESET			0x0008
-#define STF_DEVICE_RESET		0x0010
-#define STF_ABORTED			0x0020
-#define STF_TIMEOUT			0x0040
-#define STF_NEGOTIATION			0x0080
-
-/* interface control commands */
-#define ISP_RESET			0x0001
-#define ISP_EN_INT			0x0002
-#define ISP_EN_RISC			0x0004
-
-/* host control commands */
-#define HCCR_NOP			0x0000
-#define HCCR_RESET			0x1000
-#define HCCR_PAUSE			0x2000
-#define HCCR_RELEASE			0x3000
-#define HCCR_SINGLE_STEP		0x4000
-#define HCCR_SET_HOST_INTR		0x5000
-#define HCCR_CLEAR_HOST_INTR		0x6000
-#define HCCR_CLEAR_RISC_INTR		0x7000
-#define HCCR_BP_ENABLE			0x8000
-#define HCCR_BIOS_DISABLE		0x9000
-#define HCCR_TEST_MODE			0xf000
-
-#define RISC_BUSY			0x0004
-
-/* mailbox commands */
-#define MBOX_NO_OP			0x0000
-#define MBOX_LOAD_RAM			0x0001
-#define MBOX_EXEC_FIRMWARE		0x0002
-#define MBOX_DUMP_RAM			0x0003
-#define MBOX_WRITE_RAM_WORD		0x0004
-#define MBOX_READ_RAM_WORD		0x0005
-#define MBOX_MAILBOX_REG_TEST		0x0006
-#define MBOX_VERIFY_CHECKSUM		0x0007
-#define MBOX_ABOUT_FIRMWARE		0x0008
-#define MBOX_CHECK_FIRMWARE		0x000e
-#define MBOX_INIT_REQ_QUEUE		0x0010
-#define MBOX_INIT_RES_QUEUE		0x0011
-#define MBOX_EXECUTE_IOCB		0x0012
-#define MBOX_WAKE_UP			0x0013
-#define MBOX_STOP_FIRMWARE		0x0014
-#define MBOX_ABORT			0x0015
-#define MBOX_ABORT_DEVICE		0x0016
-#define MBOX_ABORT_TARGET		0x0017
-#define MBOX_BUS_RESET			0x0018
-#define MBOX_STOP_QUEUE			0x0019
-#define MBOX_START_QUEUE		0x001a
-#define MBOX_SINGLE_STEP_QUEUE		0x001b
-#define MBOX_ABORT_QUEUE		0x001c
-#define MBOX_GET_DEV_QUEUE_STATUS	0x001d
-#define MBOX_GET_FIRMWARE_STATUS	0x001f
-#define MBOX_GET_INIT_SCSI_ID		0x0020
-#define MBOX_GET_SELECT_TIMEOUT		0x0021
-#define MBOX_GET_RETRY_COUNT		0x0022
-#define MBOX_GET_TAG_AGE_LIMIT		0x0023
-#define MBOX_GET_CLOCK_RATE		0x0024
-#define MBOX_GET_ACT_NEG_STATE		0x0025
-#define MBOX_GET_ASYNC_DATA_SETUP_TIME	0x0026
-#define MBOX_GET_PCI_PARAMS		0x0027
-#define MBOX_GET_TARGET_PARAMS		0x0028
-#define MBOX_GET_DEV_QUEUE_PARAMS	0x0029
-#define MBOX_SET_INIT_SCSI_ID		0x0030
-#define MBOX_SET_SELECT_TIMEOUT		0x0031
-#define MBOX_SET_RETRY_COUNT		0x0032
-#define MBOX_SET_TAG_AGE_LIMIT		0x0033
-#define MBOX_SET_CLOCK_RATE		0x0034
-#define MBOX_SET_ACTIVE_NEG_STATE	0x0035
-#define MBOX_SET_ASYNC_DATA_SETUP_TIME	0x0036
-#define MBOX_SET_PCI_CONTROL_PARAMS	0x0037
-#define MBOX_SET_TARGET_PARAMS		0x0038
-#define MBOX_SET_DEV_QUEUE_PARAMS	0x0039
-#define MBOX_RETURN_BIOS_BLOCK_ADDR	0x0040
-#define MBOX_WRITE_FOUR_RAM_WORDS	0x0041
-#define MBOX_EXEC_BIOS_IOCB		0x0042
-
-#ifdef CONFIG_QL_ISP_A64
-#define MBOX_CMD_INIT_REQUEST_QUEUE_64      0x0052
-#define MBOX_CMD_INIT_RESPONSE_QUEUE_64     0x0053
-#endif /* CONFIG_QL_ISP_A64 */
-
-#include "qlogicisp_asm.c"
-
-#define PACKB(a, b)			(((a)<<4)|(b))
-
-static const u_char mbox_param[] = {
-	PACKB(1, 1),	/* MBOX_NO_OP */
-	PACKB(5, 5),	/* MBOX_LOAD_RAM */
-	PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */
-	PACKB(5, 5),	/* MBOX_DUMP_RAM */
-	PACKB(3, 3),	/* MBOX_WRITE_RAM_WORD */
-	PACKB(2, 3),	/* MBOX_READ_RAM_WORD */
-	PACKB(6, 6),	/* MBOX_MAILBOX_REG_TEST */
-	PACKB(2, 3),	/* MBOX_VERIFY_CHECKSUM	*/
-	PACKB(1, 3),	/* MBOX_ABOUT_FIRMWARE */
-	PACKB(0, 0),	/* 0x0009 */
-	PACKB(0, 0),	/* 0x000a */
-	PACKB(0, 0),	/* 0x000b */
-	PACKB(0, 0),	/* 0x000c */
-	PACKB(0, 0),	/* 0x000d */
-	PACKB(1, 2),	/* MBOX_CHECK_FIRMWARE */
-	PACKB(0, 0),	/* 0x000f */
-	PACKB(5, 5),	/* MBOX_INIT_REQ_QUEUE */
-	PACKB(6, 6),	/* MBOX_INIT_RES_QUEUE */
-	PACKB(4, 4),	/* MBOX_EXECUTE_IOCB */
-	PACKB(2, 2),	/* MBOX_WAKE_UP	*/
-	PACKB(1, 6),	/* MBOX_STOP_FIRMWARE */
-	PACKB(4, 4),	/* MBOX_ABORT */
-	PACKB(2, 2),	/* MBOX_ABORT_DEVICE */
-	PACKB(3, 3),	/* MBOX_ABORT_TARGET */
-	PACKB(2, 2),	/* MBOX_BUS_RESET */
-	PACKB(2, 3),	/* MBOX_STOP_QUEUE */
-	PACKB(2, 3),	/* MBOX_START_QUEUE */
-	PACKB(2, 3),	/* MBOX_SINGLE_STEP_QUEUE */
-	PACKB(2, 3),	/* MBOX_ABORT_QUEUE */
-	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_STATUS */
-	PACKB(0, 0),	/* 0x001e */
-	PACKB(1, 3),	/* MBOX_GET_FIRMWARE_STATUS */
-	PACKB(1, 2),	/* MBOX_GET_INIT_SCSI_ID */
-	PACKB(1, 2),	/* MBOX_GET_SELECT_TIMEOUT */
-	PACKB(1, 3),	/* MBOX_GET_RETRY_COUNT	*/
-	PACKB(1, 2),	/* MBOX_GET_TAG_AGE_LIMIT */
-	PACKB(1, 2),	/* MBOX_GET_CLOCK_RATE */
-	PACKB(1, 2),	/* MBOX_GET_ACT_NEG_STATE */
-	PACKB(1, 2),	/* MBOX_GET_ASYNC_DATA_SETUP_TIME */
-	PACKB(1, 3),	/* MBOX_GET_PCI_PARAMS */
-	PACKB(2, 4),	/* MBOX_GET_TARGET_PARAMS */
-	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_PARAMS */
-	PACKB(0, 0),	/* 0x002a */
-	PACKB(0, 0),	/* 0x002b */
-	PACKB(0, 0),	/* 0x002c */
-	PACKB(0, 0),	/* 0x002d */
-	PACKB(0, 0),	/* 0x002e */
-	PACKB(0, 0),	/* 0x002f */
-	PACKB(2, 2),	/* MBOX_SET_INIT_SCSI_ID */
-	PACKB(2, 2),	/* MBOX_SET_SELECT_TIMEOUT */
-	PACKB(3, 3),	/* MBOX_SET_RETRY_COUNT	*/
-	PACKB(2, 2),	/* MBOX_SET_TAG_AGE_LIMIT */
-	PACKB(2, 2),	/* MBOX_SET_CLOCK_RATE */
-	PACKB(2, 2),	/* MBOX_SET_ACTIVE_NEG_STATE */
-	PACKB(2, 2),	/* MBOX_SET_ASYNC_DATA_SETUP_TIME */
-	PACKB(3, 3),	/* MBOX_SET_PCI_CONTROL_PARAMS */
-	PACKB(4, 4),	/* MBOX_SET_TARGET_PARAMS */
-	PACKB(4, 4),	/* MBOX_SET_DEV_QUEUE_PARAMS */
-	PACKB(0, 0),	/* 0x003a */
-	PACKB(0, 0),	/* 0x003b */
-	PACKB(0, 0),	/* 0x003c */
-	PACKB(0, 0),	/* 0x003d */
-	PACKB(0, 0),	/* 0x003e */
-	PACKB(0, 0),	/* 0x003f */
-	PACKB(1, 2),	/* MBOX_RETURN_BIOS_BLOCK_ADDR */
-	PACKB(6, 1),	/* MBOX_WRITE_FOUR_RAM_WORDS */
-	PACKB(2, 3)	/* MBOX_EXEC_BIOS_IOCB */
-#ifdef CONFIG_QL_ISP_A64
-	,PACKB(0, 0),	/* 0x0043 */
-	PACKB(0, 0),	/* 0x0044 */
-	PACKB(0, 0),	/* 0x0045 */
-	PACKB(0, 0),	/* 0x0046 */
-	PACKB(0, 0),	/* 0x0047 */
-	PACKB(0, 0),	/* 0x0048 */
-	PACKB(0, 0),	/* 0x0049 */
-	PACKB(0, 0),	/* 0x004a */
-	PACKB(0, 0),	/* 0x004b */
-	PACKB(0, 0),	/* 0x004c */
-	PACKB(0, 0),	/* 0x004d */
-	PACKB(0, 0),	/* 0x004e */
-	PACKB(0, 0),	/* 0x004f */
-	PACKB(0, 0),	/* 0x0050 */
-	PACKB(0, 0),	/* 0x0051 */
-	PACKB(8, 8),	/* MBOX_CMD_INIT_REQUEST_QUEUE_64 (0x0052) */
-	PACKB(8, 8)	/* MBOX_CMD_INIT_RESPONSE_QUEUE_64 (0x0053) */
-#endif /* CONFIG_QL_ISP_A64 */
-};
-
-#define MAX_MBOX_COMMAND	(sizeof(mbox_param)/sizeof(u_short))
-
-struct host_param {
-	u_short		fifo_threshold;
-	u_short		host_adapter_enable;
-	u_short		initiator_scsi_id;
-	u_short		bus_reset_delay;
-	u_short		retry_count;
-	u_short		retry_delay;
-	u_short		async_data_setup_time;
-	u_short		req_ack_active_negation;
-	u_short		data_line_active_negation;
-	u_short		data_dma_burst_enable;
-	u_short		command_dma_burst_enable;
-	u_short		tag_aging;
-	u_short		selection_timeout;
-	u_short		max_queue_depth;
-};
-
-/*
- * Device Flags:
- *
- * Bit  Name
- * ---------
- *  7   Disconnect Privilege
- *  6   Parity Checking
- *  5   Wide Data Transfers
- *  4   Synchronous Data Transfers
- *  3   Tagged Queuing
- *  2   Automatic Request Sense
- *  1   Stop Queue on Check Condition
- *  0   Renegotiate on Error
- */
-
-struct dev_param {
-	u_short		device_flags;
-	u_short		execution_throttle;
-	u_short		synchronous_period;
-	u_short		synchronous_offset;
-	u_short		device_enable;
-	u_short		reserved; /* pad */
-};
-
-/*
- * The result queue can be quite a bit smaller since continuation entries
- * do not show up there:
- */
-#define RES_QUEUE_LEN		((QLOGICISP_REQ_QUEUE_LEN + 1) / 8 - 1)
-#define QUEUE_ENTRY_LEN		64
-#define QSIZE(entries)  (((entries) + 1) * QUEUE_ENTRY_LEN)
-
-struct isp_queue_entry {
-	char __opaque[QUEUE_ENTRY_LEN];
-};
-
-struct isp1020_hostdata {
-	void __iomem *memaddr;
-	u_char	revision;
-	struct	host_param host_param;
-	struct	dev_param dev_param[MAX_TARGETS];
-	struct	pci_dev *pci_dev;
-	
-	struct isp_queue_entry *res_cpu; /* CPU-side address of response queue. */
-	struct isp_queue_entry *req_cpu; /* CPU-size address of request queue. */
-
-	/* result and request queues (shared with isp1020): */
-	u_int	req_in_ptr;		/* index of next request slot */
-	u_int	res_out_ptr;		/* index of next result slot */
-
-	/* this is here so the queues are nicely aligned */
-	long	send_marker;		/* do we need to send a marker? */
-
-	/* The cmd->handle has a fixed size, and is only 32-bits.  We
-	 * need to take care to handle 64-bit systems correctly thus what
-	 * we actually place in cmd->handle is an index to the following
-	 * table.  Kudos to Matt Jacob for the technique.  -DaveM
-	 */
-	Scsi_Cmnd *cmd_slots[QLOGICISP_REQ_QUEUE_LEN + 1];
-
-	dma_addr_t res_dma;	/* PCI side view of response queue */
-	dma_addr_t req_dma;	/* PCI side view of request queue */
-};
-
-/* queue length's _must_ be power of two: */
-#define QUEUE_DEPTH(in, out, ql)	((in - out) & (ql))
-#define REQ_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, 		     \
-						    QLOGICISP_REQ_QUEUE_LEN)
-#define RES_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
-
-static void	isp1020_enable_irqs(struct Scsi_Host *);
-static void	isp1020_disable_irqs(struct Scsi_Host *);
-static int	isp1020_init(struct Scsi_Host *);
-static int	isp1020_reset_hardware(struct Scsi_Host *);
-static int	isp1020_set_defaults(struct Scsi_Host *);
-static int	isp1020_load_parameters(struct Scsi_Host *);
-static int	isp1020_mbox_command(struct Scsi_Host *, u_short []); 
-static int	isp1020_return_status(struct Status_Entry *);
-static void	isp1020_intr_handler(int, void *, struct pt_regs *);
-static irqreturn_t do_isp1020_intr_handler(int, void *, struct pt_regs *);
-
-#if USE_NVRAM_DEFAULTS
-static int	isp1020_get_defaults(struct Scsi_Host *);
-static int	isp1020_verify_nvram(struct Scsi_Host *);
-static u_short	isp1020_read_nvram_word(struct Scsi_Host *, u_short);
-#endif
-
-#if DEBUG_ISP1020
-static void	isp1020_print_scsi_cmd(Scsi_Cmnd *);
-#endif
-#if DEBUG_ISP1020_INTR
-static void	isp1020_print_status_entry(struct Status_Entry *);
-#endif
-
-/* memaddr should be used to determine if memmapped port i/o is being used
- * non-null memaddr == mmap'd
- * JV 7-Jan-2000
- */
-static inline u_short isp_inw(struct Scsi_Host *host, long offset)
-{
-	struct isp1020_hostdata *h = (struct isp1020_hostdata *)host->hostdata;
-	if (h->memaddr)
-		return readw(h->memaddr + offset);
-	else
-		return inw(host->io_port + offset);
-}
-
-static inline void isp_outw(u_short val, struct Scsi_Host *host, long offset)
-{
-	struct isp1020_hostdata *h = (struct isp1020_hostdata *)host->hostdata;
-	if (h->memaddr)
-		writew(val, h->memaddr + offset);
-	else
-		outw(val, host->io_port + offset);
-}
-
-static inline void isp1020_enable_irqs(struct Scsi_Host *host)
-{
-	isp_outw(ISP_EN_INT|ISP_EN_RISC, host, PCI_INTF_CTL);
-}
-
-
-static inline void isp1020_disable_irqs(struct Scsi_Host *host)
-{
-	isp_outw(0x0, host, PCI_INTF_CTL);
-}
-
-
-static int isp1020_detect(Scsi_Host_Template *tmpt)
-{
-	int hosts = 0;
-	struct Scsi_Host *host;
-	struct isp1020_hostdata *hostdata;
-	struct pci_dev *pdev = NULL;
-
-	ENTER("isp1020_detect");
-
-	tmpt->proc_name = "isp1020";
-
-	while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, pdev)))
-	{
-		if (pci_enable_device(pdev))
-			continue;
-
-		host = scsi_register(tmpt, sizeof(struct isp1020_hostdata));
-		if (!host)
-			continue;
-
-		hostdata = (struct isp1020_hostdata *) host->hostdata;
-
-		memset(hostdata, 0, sizeof(struct isp1020_hostdata));
-
-		hostdata->pci_dev = pdev;
-
-		if (isp1020_init(host))
-			goto fail_and_unregister;
-
-		if (isp1020_reset_hardware(host)
-#if USE_NVRAM_DEFAULTS
-		    || isp1020_get_defaults(host)
-#else
-		    || isp1020_set_defaults(host)
-#endif /* USE_NVRAM_DEFAULTS */
-		    || isp1020_load_parameters(host)) {
-			goto fail_uninit;
-		}
-
-		host->this_id = hostdata->host_param.initiator_scsi_id;
-		host->max_sectors = 64;
-
-		if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
-				"qlogicisp", host))
-		{
-			printk("qlogicisp : interrupt %d already in use\n",
-			       host->irq);
-			goto fail_uninit;
-		}
-
-		isp_outw(0x0, host, PCI_SEMAPHORE);
-		isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
-		isp1020_enable_irqs(host);
-
-		hosts++;
-		continue;
-
-	fail_uninit:
-		iounmap(hostdata->memaddr);
-		release_region(host->io_port, 0xff);
-	fail_and_unregister:
-		if (hostdata->res_cpu)
-			pci_free_consistent(hostdata->pci_dev,
-					    QSIZE(RES_QUEUE_LEN),
-					    hostdata->res_cpu,
-					    hostdata->res_dma);
-		if (hostdata->req_cpu)
-			pci_free_consistent(hostdata->pci_dev,
-					    QSIZE(QLOGICISP_REQ_QUEUE_LEN),
-					    hostdata->req_cpu,
-					    hostdata->req_dma);
-		scsi_unregister(host);
-	}
-
-	LEAVE("isp1020_detect");
-
-	return hosts;
-}
-
-
-static int isp1020_release(struct Scsi_Host *host)
-{
-	struct isp1020_hostdata *hostdata;
-
-	ENTER("isp1020_release");
-
-	hostdata = (struct isp1020_hostdata *) host->hostdata;
-
-	isp_outw(0x0, host, PCI_INTF_CTL);
-	free_irq(host->irq, host);
-
-	iounmap(hostdata->memaddr);
-
-	release_region(host->io_port, 0xff);
-
-	LEAVE("isp1020_release");
-
-	return 0;
-}
-
-
-static const char *isp1020_info(struct Scsi_Host *host)
-{
-	static char buf[80];
-	struct isp1020_hostdata *hostdata;
-
-	ENTER("isp1020_info");
-
-	hostdata = (struct isp1020_hostdata *) host->hostdata;
-	sprintf(buf,
-		"QLogic ISP1020 SCSI on PCI bus %02x device %02x irq %d %s base 0x%lx",
-		hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq,
-		(hostdata->memaddr ? "MEM" : "I/O"),
-		(hostdata->memaddr ? (unsigned long)hostdata->memaddr : host->io_port));
-
-	LEAVE("isp1020_info");
-
-	return buf;
-}
-
-
-/*
- * The middle SCSI layer ensures that queuecommand never gets invoked
- * concurrently with itself or the interrupt handler (though the
- * interrupt handler may call this routine as part of
- * request-completion handling).
- */
-static int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
-{
-	int i, n, num_free;
-	u_int in_ptr, out_ptr;
-	struct dataseg * ds;
-	struct scatterlist *sg;
-	struct Command_Entry *cmd;
-	struct Continuation_Entry *cont;
-	struct Scsi_Host *host;
-	struct isp1020_hostdata *hostdata;
-	dma_addr_t	dma_addr;
-
-	ENTER("isp1020_queuecommand");
-
-	host = Cmnd->device->host;
-	hostdata = (struct isp1020_hostdata *) host->hostdata;
-	Cmnd->scsi_done = done;
-
-	DEBUG(isp1020_print_scsi_cmd(Cmnd));
-
-	out_ptr = isp_inw(host, + MBOX4);
-	in_ptr  = hostdata->req_in_ptr;
-
-	DEBUG(printk("qlogicisp : request queue depth %d\n",
-		     REQ_QUEUE_DEPTH(in_ptr, out_ptr)));
-
-	cmd = (struct Command_Entry *) &hostdata->req_cpu[in_ptr];
-	in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
-	if (in_ptr == out_ptr) {
-		printk("qlogicisp : request queue overflow\n");
-		return 1;
-	}
-
-	if (hostdata->send_marker) {
-		struct Marker_Entry *marker;
-
-		TRACE("queue marker", in_ptr, 0);
-
-		DEBUG(printk("qlogicisp : adding marker entry\n"));
-		marker = (struct Marker_Entry *) cmd;
-		memset(marker, 0, sizeof(struct Marker_Entry));
-
-		marker->hdr.entry_type = ENTRY_MARKER;
-		marker->hdr.entry_cnt = 1;
-		marker->modifier = SYNC_ALL;
-
-		hostdata->send_marker = 0;
-
-		if (((in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN) == out_ptr) {
-			isp_outw(in_ptr, host, MBOX4);
-			hostdata->req_in_ptr = in_ptr;
-			printk("qlogicisp : request queue overflow\n");
-			return 1;
-		}
-		cmd = (struct Command_Entry *) &hostdata->req_cpu[in_ptr];
-		in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
-	}
-
-	TRACE("queue command", in_ptr, Cmnd);
-
-	memset(cmd, 0, sizeof(struct Command_Entry));
-
-	cmd->hdr.entry_type = ENTRY_COMMAND;
-	cmd->hdr.entry_cnt = 1;
-
-	cmd->target_lun = Cmnd->device->lun;
-	cmd->target_id = Cmnd->device->id;
-	cmd->cdb_length = cpu_to_le16(Cmnd->cmd_len);
-	cmd->control_flags = cpu_to_le16(CFLAG_READ | CFLAG_WRITE);
-	cmd->time_out = cpu_to_le16(30);
-
-	memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
-
-	if (Cmnd->use_sg) {
-		int sg_count;
-
-		sg = (struct scatterlist *) Cmnd->request_buffer;
-		ds = cmd->dataseg;
-
-		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg,
-				      Cmnd->sc_data_direction);
-
-		cmd->segment_cnt = cpu_to_le16(sg_count);
-
-		/* fill in first four sg entries: */
-		n = sg_count;
-		if (n > IOCB_SEGS)
-			n = IOCB_SEGS;
-		for (i = 0; i < n; i++) {
-			dma_addr = sg_dma_address(sg);
-			ds[i].d_base  = cpu_to_le32((u32) dma_addr);
-#ifdef CONFIG_QL_ISP_A64
-			ds[i].d_base_hi = cpu_to_le32((u32) (dma_addr>>32));
-#endif /* CONFIG_QL_ISP_A64 */
-			ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
-			++sg;
-		}
-		sg_count -= IOCB_SEGS;
-
-		while (sg_count > 0) {
-			++cmd->hdr.entry_cnt;
-			cont = (struct Continuation_Entry *)
-				&hostdata->req_cpu[in_ptr];
-			in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
-			if (in_ptr == out_ptr) {
-				printk("isp1020: unexpected request queue "
-				       "overflow\n");
-				return 1;
-			}
-			TRACE("queue continuation", in_ptr, 0);
-			cont->hdr.entry_type = ENTRY_CONTINUATION;
-			cont->hdr.entry_cnt  = 0;
-			cont->hdr.sys_def_1  = 0;
-			cont->hdr.flags      = 0;
-#ifndef CONFIG_QL_ISP_A64
-			cont->reserved = 0;
-#endif
-			ds = cont->dataseg;
-			n = sg_count;
-			if (n > CONTINUATION_SEGS)
-				n = CONTINUATION_SEGS;
-			for (i = 0; i < n; ++i) {
-				dma_addr = sg_dma_address(sg);
-				ds[i].d_base = cpu_to_le32((u32) dma_addr);
-#ifdef CONFIG_QL_ISP_A64
-				ds[i].d_base_hi = cpu_to_le32((u32)(dma_addr>>32));
-#endif /* CONFIG_QL_ISP_A64 */
-				ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
-				++sg;
-			}
-			sg_count -= n;
-		}
-	} else if (Cmnd->request_bufflen) {
-		/*Cmnd->SCp.ptr = (char *)(unsigned long)*/
-		dma_addr = pci_map_single(hostdata->pci_dev,
-				       Cmnd->request_buffer,
-				       Cmnd->request_bufflen,
-				       Cmnd->sc_data_direction);
-		Cmnd->SCp.ptr = (char *)(unsigned long) dma_addr;
-
-		cmd->dataseg[0].d_base =
-			cpu_to_le32((u32) dma_addr);
-#ifdef CONFIG_QL_ISP_A64
-		cmd->dataseg[0].d_base_hi =
-			cpu_to_le32((u32) (dma_addr>>32));
-#endif /* CONFIG_QL_ISP_A64 */
-		cmd->dataseg[0].d_count =
-			cpu_to_le32((u32)Cmnd->request_bufflen);
-		cmd->segment_cnt = cpu_to_le16(1);
-	} else {
-		cmd->dataseg[0].d_base = 0;
-#ifdef CONFIG_QL_ISP_A64
-		cmd->dataseg[0].d_base_hi = 0;
-#endif /* CONFIG_QL_ISP_A64 */
-		cmd->dataseg[0].d_count = 0;
-		cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
-	}
-
-	/* Committed, record Scsi_Cmd so we can find it later. */
-	cmd->handle = in_ptr;
-	hostdata->cmd_slots[in_ptr] = Cmnd;
-
-	isp_outw(in_ptr, host, MBOX4);
-	hostdata->req_in_ptr = in_ptr;
-
-	num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
-	host->can_queue = host->host_busy + num_free;
-	host->sg_tablesize = QLOGICISP_MAX_SG(num_free);
-
-	LEAVE("isp1020_queuecommand");
-
-	return 0;
-}
-
-
-#define ASYNC_EVENT_INTERRUPT	0x01
-
-irqreturn_t do_isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct Scsi_Host *host = dev_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(host->host_lock, flags);
-	isp1020_intr_handler(irq, dev_id, regs);
-	spin_unlock_irqrestore(host->host_lock, flags);
-
-	return IRQ_HANDLED;
-}
-
-void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-	Scsi_Cmnd *Cmnd;
-	struct Status_Entry *sts;
-	struct Scsi_Host *host = dev_id;
-	struct isp1020_hostdata *hostdata;
-	u_int in_ptr, out_ptr;
-	u_short status;
-
-	ENTER_INTR("isp1020_intr_handler");
-
-	hostdata = (struct isp1020_hostdata *) host->hostdata;
-
-	DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq));
-
-	if (!(isp_inw(host, PCI_INTF_STS) & 0x04)) {
-		/* spurious interrupts can happen legally */
-		DEBUG_INTR(printk("qlogicisp: got spurious interrupt\n"));
-		return;
-	}
-	in_ptr = isp_inw(host, MBOX5);
-	isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
-
-	if ((isp_inw(host, PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) {
-		status = isp_inw(host, MBOX0);
-
-		DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n",
-				  status));
-
-		switch (status) {
-		      case ASYNC_SCSI_BUS_RESET:
-		      case EXECUTION_TIMEOUT_RESET:
-			hostdata->send_marker = 1;
-			break;
-		      case INVALID_COMMAND:
-		      case HOST_INTERFACE_ERROR:
-		      case COMMAND_ERROR:
-		      case COMMAND_PARAM_ERROR:
-			printk("qlogicisp : bad mailbox return status\n");
-			break;
-		}
-		isp_outw(0x0, host, PCI_SEMAPHORE);
-	}
-	out_ptr = hostdata->res_out_ptr;
-
-	DEBUG_INTR(printk("qlogicisp : response queue update\n"));
-	DEBUG_INTR(printk("qlogicisp : response queue depth %d\n",
-			  QUEUE_DEPTH(in_ptr, out_ptr, RES_QUEUE_LEN)));
-
-	while (out_ptr != in_ptr) {
-		u_int cmd_slot;
-
-		sts = (struct Status_Entry *) &hostdata->res_cpu[out_ptr];
-		out_ptr = (out_ptr + 1) & RES_QUEUE_LEN;
-
-		cmd_slot = sts->handle;
-		Cmnd = hostdata->cmd_slots[cmd_slot];
-		hostdata->cmd_slots[cmd_slot] = NULL;
-
-		TRACE("done", out_ptr, Cmnd);
-
-		if (le16_to_cpu(sts->completion_status) == CS_RESET_OCCURRED
-		    || le16_to_cpu(sts->completion_status) == CS_ABORTED
-		    || (le16_to_cpu(sts->status_flags) & STF_BUS_RESET))
-			hostdata->send_marker = 1;
-
-		if (le16_to_cpu(sts->state_flags) & SF_GOT_SENSE)
-			memcpy(Cmnd->sense_buffer, sts->req_sense_data,
-			       sizeof(Cmnd->sense_buffer));
-
-		DEBUG_INTR(isp1020_print_status_entry(sts));
-
-		if (sts->hdr.entry_type == ENTRY_STATUS)
-			Cmnd->result = isp1020_return_status(sts);
-		else
-			Cmnd->result = DID_ERROR << 16;
-
-		if (Cmnd->use_sg)
-			pci_unmap_sg(hostdata->pci_dev,
-				     (struct scatterlist *)Cmnd->buffer,
-				     Cmnd->use_sg,
-				     Cmnd->sc_data_direction);
-		else if (Cmnd->request_bufflen)
-			pci_unmap_single(hostdata->pci_dev,
-#ifdef CONFIG_QL_ISP_A64
-					 (dma_addr_t)((long)Cmnd->SCp.ptr),
-#else
-					 (u32)((long)Cmnd->SCp.ptr),
-#endif
-					 Cmnd->request_bufflen,
-					 Cmnd->sc_data_direction);
-
-		isp_outw(out_ptr, host, MBOX5);
-		(*Cmnd->scsi_done)(Cmnd);
-	}
-	hostdata->res_out_ptr = out_ptr;
-
-	LEAVE_INTR("isp1020_intr_handler");
-}
-
-
-static int isp1020_return_status(struct Status_Entry *sts)
-{
-	int host_status = DID_ERROR;
-#if DEBUG_ISP1020_INTR
-	static char *reason[] = {
-		"DID_OK",
-		"DID_NO_CONNECT",
-		"DID_BUS_BUSY",
-		"DID_TIME_OUT",
-		"DID_BAD_TARGET",
-		"DID_ABORT",
-		"DID_PARITY",
-		"DID_ERROR",
-		"DID_RESET",
-		"DID_BAD_INTR"
-	};
-#endif /* DEBUG_ISP1020_INTR */
-
-	ENTER("isp1020_return_status");
-
-	DEBUG(printk("qlogicisp : completion status = 0x%04x\n",
-		     le16_to_cpu(sts->completion_status)));
-
-	switch(le16_to_cpu(sts->completion_status)) {
-	      case CS_COMPLETE:
-		host_status = DID_OK;
-		break;
-	      case CS_INCOMPLETE:
-		if (!(le16_to_cpu(sts->state_flags) & SF_GOT_BUS))
-			host_status = DID_NO_CONNECT;
-		else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_TARGET))
-			host_status = DID_BAD_TARGET;
-		else if (!(le16_to_cpu(sts->state_flags) & SF_SENT_CDB))
-			host_status = DID_ERROR;
-		else if (!(le16_to_cpu(sts->state_flags) & SF_TRANSFERRED_DATA))
-			host_status = DID_ERROR;
-		else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_STATUS))
-			host_status = DID_ERROR;
-		else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_SENSE))
-			host_status = DID_ERROR;
-		break;
-	      case CS_DMA_ERROR:
-	      case CS_TRANSPORT_ERROR:
-		host_status = DID_ERROR;
-		break;
-	      case CS_RESET_OCCURRED:
-		host_status = DID_RESET;
-		break;
-	      case CS_ABORTED:
-		host_status = DID_ABORT;
-		break;
-	      case CS_TIMEOUT:
-		host_status = DID_TIME_OUT;
-		break;
-	      case CS_DATA_OVERRUN:
-	      case CS_COMMAND_OVERRUN:
-	      case CS_STATUS_OVERRUN:
-	      case CS_BAD_MESSAGE:
-	      case CS_NO_MESSAGE_OUT:
-	      case CS_EXT_ID_FAILED:
-	      case CS_IDE_MSG_FAILED:
-	      case CS_ABORT_MSG_FAILED:
-	      case CS_NOP_MSG_FAILED:
-	      case CS_PARITY_ERROR_MSG_FAILED:
-	      case CS_DEVICE_RESET_MSG_FAILED:
-	      case CS_ID_MSG_FAILED:
-	      case CS_UNEXP_BUS_FREE:
-		host_status = DID_ERROR;
-		break;
-	      case CS_DATA_UNDERRUN:
-		host_status = DID_OK;
-		break;
-	      default:
-		printk("qlogicisp : unknown completion status 0x%04x\n",
-		       le16_to_cpu(sts->completion_status));
-		host_status = DID_ERROR;
-		break;
-	}
-
-	DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n",
-			  reason[host_status], le16_to_cpu(sts->scsi_status)));
-
-	LEAVE("isp1020_return_status");
-
-	return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16);
-}
-
-
-static int isp1020_biosparam(struct scsi_device *sdev, struct block_device *n,
-		sector_t capacity, int ip[])
-{
-	int size = capacity;
-
-	ENTER("isp1020_biosparam");
-
-	ip[0] = 64;
-	ip[1] = 32;
-	ip[2] = size >> 11;
-	if (ip[2] > 1024) {
-		ip[0] = 255;
-		ip[1] = 63;
-		ip[2] = size / (ip[0] * ip[1]);
-#if 0
-		if (ip[2] > 1023)
-			ip[2] = 1023;
-#endif			
-	}
-
-	LEAVE("isp1020_biosparam");
-
-	return 0;
-}
-
-
-static int isp1020_reset_hardware(struct Scsi_Host *host)
-{
-	u_short param[6];
-	int loop_count;
-
-	ENTER("isp1020_reset_hardware");
-
-	isp_outw(ISP_RESET, host, PCI_INTF_CTL);
-	udelay(100);
-	isp_outw(HCCR_RESET, host, HOST_HCCR);
-	udelay(100);
-	isp_outw(HCCR_RELEASE, host, HOST_HCCR);
-	isp_outw(HCCR_BIOS_DISABLE, host, HOST_HCCR);
-
-	loop_count = DEFAULT_LOOP_COUNT;
-	while (--loop_count && isp_inw(host, HOST_HCCR) == RISC_BUSY) {
-		barrier();
-		cpu_relax();
-	}
-	if (!loop_count)
-		printk("qlogicisp: reset_hardware loop timeout\n");
-
-	isp_outw(0, host, ISP_CFG1);
-
-#if DEBUG_ISP1020
-	printk("qlogicisp : mbox 0 0x%04x \n", isp_inw(host, MBOX0));
-	printk("qlogicisp : mbox 1 0x%04x \n", isp_inw(host, MBOX1));
-	printk("qlogicisp : mbox 2 0x%04x \n", isp_inw(host, MBOX2));
-	printk("qlogicisp : mbox 3 0x%04x \n", isp_inw(host, MBOX3));
-	printk("qlogicisp : mbox 4 0x%04x \n", isp_inw(host, MBOX4));
-	printk("qlogicisp : mbox 5 0x%04x \n", isp_inw(host, MBOX5));
-#endif /* DEBUG_ISP1020 */
-
-	param[0] = MBOX_NO_OP;
-	isp1020_mbox_command(host, param);
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : NOP test failed\n");
-		return 1;
-	}
-
-	DEBUG(printk("qlogicisp : loading risc ram\n"));
-
-#if RELOAD_FIRMWARE
-	for (loop_count = 0; loop_count < risc_code_length01; loop_count++) {
-		param[0] = MBOX_WRITE_RAM_WORD;
-		param[1] = risc_code_addr01 + loop_count;
-		param[2] = risc_code01[loop_count];
-		isp1020_mbox_command(host, param);
-		if (param[0] != MBOX_COMMAND_COMPLETE) {
-			printk("qlogicisp : firmware load failure at %d\n",
-			    loop_count);
-			return 1;
-		}
-	}
-#endif /* RELOAD_FIRMWARE */
-
-	DEBUG(printk("qlogicisp : verifying checksum\n"));
-
-	param[0] = MBOX_VERIFY_CHECKSUM;
-	param[1] = risc_code_addr01;
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : ram checksum failure\n");
-		return 1;
-	}
-
-	DEBUG(printk("qlogicisp : executing firmware\n"));
-
-	param[0] = MBOX_EXEC_FIRMWARE;
-	param[1] = risc_code_addr01;
-
-	isp1020_mbox_command(host, param);
-
-	param[0] = MBOX_ABOUT_FIRMWARE;
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : about firmware failure\n");
-		return 1;
-	}
-
-	DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1]));
-	DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2]));
-
-	LEAVE("isp1020_reset_hardware");
-
-	return 0;
-}
-
-
-static int isp1020_init(struct Scsi_Host *sh)
-{
-	u_long io_base, mem_base, io_flags, mem_flags;
-	struct isp1020_hostdata *hostdata;
-	u_char revision;
-	u_int irq;
-	u_short command;
-	struct pci_dev *pdev;
-
-	ENTER("isp1020_init");
-
-	hostdata = (struct isp1020_hostdata *) sh->hostdata;
-	pdev = hostdata->pci_dev;
-
-	if (pci_read_config_word(pdev, PCI_COMMAND, &command)
-	    || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision))
-	{
-		printk("qlogicisp : error reading PCI configuration\n");
-		return 1;
-	}
-
-	io_base = pci_resource_start(pdev, 0);
-	mem_base = pci_resource_start(pdev, 1);
-	io_flags = pci_resource_flags(pdev, 0);
-	mem_flags = pci_resource_flags(pdev, 1);
-	irq = pdev->irq;
-
-	if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) {
-		printk("qlogicisp : 0x%04x is not QLogic vendor ID\n",
-		       pdev->vendor);
-		return 1;
-	}
-
-	if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP1020) {
-		printk("qlogicisp : 0x%04x does not match ISP1020 device id\n",
-		       pdev->device);
-		return 1;
-	}
-
-#ifdef __alpha__
-	/* Force ALPHA to use bus I/O and not bus MEM.
-	   This is to avoid having to use HAE_MEM registers,
-	   which is broken on some platforms and with SMP.  */
-	command &= ~PCI_COMMAND_MEMORY; 
-#endif
-
-	sh->io_port = io_base;
-
-	if (!request_region(sh->io_port, 0xff, "qlogicisp")) {
-		printk("qlogicisp : i/o region 0x%lx-0x%lx already "
-		       "in use\n",
-		       sh->io_port, sh->io_port + 0xff);
-		return 1;
-	}
-
- 	if ((command & PCI_COMMAND_MEMORY) &&
- 	    ((mem_flags & 1) == 0)) {
- 		hostdata->memaddr = ioremap(mem_base, PAGE_SIZE);
-		if (!hostdata->memaddr) {
- 			printk("qlogicisp : i/o remapping failed.\n");
-			goto out_release;
-		}
- 	} else {
-		if (command & PCI_COMMAND_IO && (io_flags & 3) != 1) {
-			printk("qlogicisp : i/o mapping is disabled\n");
-			goto out_release;
- 		}
- 		hostdata->memaddr = NULL; /* zero to signify no i/o mapping */
- 		mem_base = 0;
-	}
-
-	if (revision != ISP1020_REV_ID)
-		printk("qlogicisp : new isp1020 revision ID (%d)\n", revision);
-
-	if (isp_inw(sh,  PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
-	    || isp_inw(sh, PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020)
-	{
-		printk("qlogicisp : can't decode %s address space 0x%lx\n",
-		       (io_base ? "I/O" : "MEM"),
-		       (io_base ? io_base : mem_base));
-		goto out_unmap;
-	}
-
-	hostdata->revision = revision;
-
-	sh->irq = irq;
-	sh->max_id = MAX_TARGETS;
-	sh->max_lun = MAX_LUNS;
-
-	hostdata->res_cpu = pci_alloc_consistent(hostdata->pci_dev,
-						 QSIZE(RES_QUEUE_LEN),
-						 &hostdata->res_dma);
-	if (hostdata->res_cpu == NULL) {
-		printk("qlogicisp : can't allocate response queue\n");
-		goto out_unmap;
-	}
-
-	hostdata->req_cpu = pci_alloc_consistent(hostdata->pci_dev,
-						 QSIZE(QLOGICISP_REQ_QUEUE_LEN),
-						 &hostdata->req_dma);
-	if (hostdata->req_cpu == NULL) {
-		pci_free_consistent(hostdata->pci_dev,
-				    QSIZE(RES_QUEUE_LEN),
-				    hostdata->res_cpu,
-				    hostdata->res_dma);
-		printk("qlogicisp : can't allocate request queue\n");
-		goto out_unmap;
-	}
-
-	pci_set_master(pdev);
-
-	LEAVE("isp1020_init");
-
-	return 0;
-
-out_unmap:
-	iounmap(hostdata->memaddr);
-out_release:
-	release_region(sh->io_port, 0xff);
-	return 1;
-}
-
-
-#if USE_NVRAM_DEFAULTS
-
-static int isp1020_get_defaults(struct Scsi_Host *host)
-{
-	int i;
-	u_short value;
-	struct isp1020_hostdata *hostdata =
-		(struct isp1020_hostdata *) host->hostdata;
-
-	ENTER("isp1020_get_defaults");
-
-	if (!isp1020_verify_nvram(host)) {
-		printk("qlogicisp : nvram checksum failure\n");
-		printk("qlogicisp : attempting to use default parameters\n");
-		return isp1020_set_defaults(host);
-	}
-
-	value = isp1020_read_nvram_word(host, 2);
-	hostdata->host_param.fifo_threshold = (value >> 8) & 0x03;
-	hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01;
-	hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f;
-
-	value = isp1020_read_nvram_word(host, 3);
-	hostdata->host_param.bus_reset_delay = value & 0xff;
-	hostdata->host_param.retry_count = value >> 8;
-
-	value = isp1020_read_nvram_word(host, 4);
-	hostdata->host_param.retry_delay = value & 0xff;
-	hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f;
-	hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01;
-	hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01;
-	hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01;
-	hostdata->host_param.command_dma_burst_enable = (value >> 15);
-
-	value = isp1020_read_nvram_word(host, 5);
-	hostdata->host_param.tag_aging = value & 0xff;
-
-	value = isp1020_read_nvram_word(host, 6);
-	hostdata->host_param.selection_timeout = value & 0xffff;
-
-	value = isp1020_read_nvram_word(host, 7);
-	hostdata->host_param.max_queue_depth = value & 0xffff;
-
-#if DEBUG_ISP1020_SETUP
-	printk("qlogicisp : fifo threshold=%d\n",
-	       hostdata->host_param.fifo_threshold);
-	printk("qlogicisp : initiator scsi id=%d\n",
-	       hostdata->host_param.initiator_scsi_id);
-	printk("qlogicisp : bus reset delay=%d\n",
-	       hostdata->host_param.bus_reset_delay);
-	printk("qlogicisp : retry count=%d\n",
-	       hostdata->host_param.retry_count);
-	printk("qlogicisp : retry delay=%d\n",
-	       hostdata->host_param.retry_delay);
-	printk("qlogicisp : async data setup time=%d\n",
-	       hostdata->host_param.async_data_setup_time);
-	printk("qlogicisp : req/ack active negation=%d\n",
-	       hostdata->host_param.req_ack_active_negation);
-	printk("qlogicisp : data line active negation=%d\n",
-	       hostdata->host_param.data_line_active_negation);
-	printk("qlogicisp : data DMA burst enable=%d\n",
-	       hostdata->host_param.data_dma_burst_enable);
-	printk("qlogicisp : command DMA burst enable=%d\n",
-	       hostdata->host_param.command_dma_burst_enable);
-	printk("qlogicisp : tag age limit=%d\n",
-	       hostdata->host_param.tag_aging);
-	printk("qlogicisp : selection timeout limit=%d\n",
-	       hostdata->host_param.selection_timeout);
-	printk("qlogicisp : max queue depth=%d\n",
-	       hostdata->host_param.max_queue_depth);
-#endif /* DEBUG_ISP1020_SETUP */
-
-	for (i = 0; i < MAX_TARGETS; i++) {
-
-		value = isp1020_read_nvram_word(host, 14 + i * 3);
-		hostdata->dev_param[i].device_flags = value & 0xff;
-		hostdata->dev_param[i].execution_throttle = value >> 8;
-
-		value = isp1020_read_nvram_word(host, 15 + i * 3);
-		hostdata->dev_param[i].synchronous_period = value & 0xff;
-		hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f;
-		hostdata->dev_param[i].device_enable = (value >> 12) & 0x01;
-
-#if DEBUG_ISP1020_SETUP
-		printk("qlogicisp : target 0x%02x\n", i);
-		printk("qlogicisp :     device flags=0x%02x\n",
-		       hostdata->dev_param[i].device_flags);
-		printk("qlogicisp :     execution throttle=%d\n",
-		       hostdata->dev_param[i].execution_throttle);
-		printk("qlogicisp :     synchronous period=%d\n",
-		       hostdata->dev_param[i].synchronous_period);
-		printk("qlogicisp :     synchronous offset=%d\n",
-		       hostdata->dev_param[i].synchronous_offset);
-		printk("qlogicisp :     device enable=%d\n",
-		       hostdata->dev_param[i].device_enable);
-#endif /* DEBUG_ISP1020_SETUP */
-	}
-
-	LEAVE("isp1020_get_defaults");
-
-	return 0;
-}
-
-
-#define ISP1020_NVRAM_LEN	0x40
-#define ISP1020_NVRAM_SIG1	0x5349
-#define ISP1020_NVRAM_SIG2	0x2050
-
-static int isp1020_verify_nvram(struct Scsi_Host *host)
-{
-	int	i;
-	u_short value;
-	u_char checksum = 0;
-
-	for (i = 0; i < ISP1020_NVRAM_LEN; i++) {
-		value = isp1020_read_nvram_word(host, i);
-
-		switch (i) {
-		      case 0:
-			if (value != ISP1020_NVRAM_SIG1) return 0;
-			break;
-		      case 1:
-			if (value != ISP1020_NVRAM_SIG2) return 0;
-			break;
-		      case 2:
-			if ((value & 0xff) != 0x02) return 0;
-			break;
-		}
-		checksum += value & 0xff;
-		checksum += value >> 8;
-	}
-
-	return (checksum == 0);
-}
-
-#define NVRAM_DELAY() udelay(2) /* 2 microsecond delay */
-
-
-u_short isp1020_read_nvram_word(struct Scsi_Host *host, u_short byte)
-{
-	int i;
-	u_short value, output, input;
-
-	byte &= 0x3f; byte |= 0x0180;
-
-	for (i = 8; i >= 0; i--) {
-		output = ((byte >> i) & 0x1) ? 0x4 : 0x0;
-		isp_outw(output | 0x2, host, PCI_NVRAM); NVRAM_DELAY();
-		isp_outw(output | 0x3, host, PCI_NVRAM); NVRAM_DELAY();
-		isp_outw(output | 0x2, host, PCI_NVRAM); NVRAM_DELAY();
-	}
-
-	for (i = 0xf, value = 0; i >= 0; i--) {
-		value <<= 1;
-		isp_outw(0x3, host, PCI_NVRAM); NVRAM_DELAY();
-		input = isp_inw(host, PCI_NVRAM); NVRAM_DELAY();
-		isp_outw(0x2, host, PCI_NVRAM); NVRAM_DELAY();
-		if (input & 0x8) value |= 1;
-	}
-
-	isp_outw(0x0, host, PCI_NVRAM); NVRAM_DELAY();
-
-	return value;
-}
-
-#endif /* USE_NVRAM_DEFAULTS */
-
-
-static int isp1020_set_defaults(struct Scsi_Host *host)
-{
-	struct isp1020_hostdata *hostdata =
-		(struct isp1020_hostdata *) host->hostdata;
-	int i;
-
-	ENTER("isp1020_set_defaults");
-
-	hostdata->host_param.fifo_threshold = 2;
-	hostdata->host_param.host_adapter_enable = 1;
-	hostdata->host_param.initiator_scsi_id = 7;
-	hostdata->host_param.bus_reset_delay = 3;
-	hostdata->host_param.retry_count = 0;
-	hostdata->host_param.retry_delay = 1;
-	hostdata->host_param.async_data_setup_time = 6;
-	hostdata->host_param.req_ack_active_negation = 1;
-	hostdata->host_param.data_line_active_negation = 1;
-	hostdata->host_param.data_dma_burst_enable = 1;
-	hostdata->host_param.command_dma_burst_enable = 1;
-	hostdata->host_param.tag_aging = 8;
-	hostdata->host_param.selection_timeout = 250;
-	hostdata->host_param.max_queue_depth = 256;
-
-	for (i = 0; i < MAX_TARGETS; i++) {
-		hostdata->dev_param[i].device_flags = 0xfd;
-		hostdata->dev_param[i].execution_throttle = 16;
-		hostdata->dev_param[i].synchronous_period = 25;
-		hostdata->dev_param[i].synchronous_offset = 12;
-		hostdata->dev_param[i].device_enable = 1;
-	}
-
-	LEAVE("isp1020_set_defaults");
-
-	return 0;
-}
-
-
-static int isp1020_load_parameters(struct Scsi_Host *host)
-{
-	int i, k;
-#ifdef CONFIG_QL_ISP_A64
-	u_long queue_addr;
-	u_short param[8];
-#else
-	u_int queue_addr;
-	u_short param[6];
-#endif
-	u_short isp_cfg1, hwrev;
-	struct isp1020_hostdata *hostdata =
-		(struct isp1020_hostdata *) host->hostdata;
-
-	ENTER("isp1020_load_parameters");
-
-	hwrev = isp_inw(host, ISP_CFG0) & ISP_CFG0_HWMSK;
-	isp_cfg1 = ISP_CFG1_F64 | ISP_CFG1_BENAB;
-	if (hwrev == ISP_CFG0_1040A) {
-		/* Busted fifo, says mjacob. */
-		isp_cfg1 &= ISP_CFG1_BENAB;
-	}
-
-	isp_outw(isp_inw(host, ISP_CFG1) | isp_cfg1, host, ISP_CFG1);
-	isp_outw(isp_inw(host, CDMA_CONF) | DMA_CONF_BENAB, host, CDMA_CONF);
-	isp_outw(isp_inw(host, DDMA_CONF) | DMA_CONF_BENAB, host, DDMA_CONF);
-
-	param[0] = MBOX_SET_INIT_SCSI_ID;
-	param[1] = hostdata->host_param.initiator_scsi_id;
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : set initiator id failure\n");
-		return 1;
-	}
-
-	param[0] = MBOX_SET_RETRY_COUNT;
-	param[1] = hostdata->host_param.retry_count;
-	param[2] = hostdata->host_param.retry_delay;
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : set retry count failure\n");
-		return 1;
-	}
-
-	param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME;
-	param[1] = hostdata->host_param.async_data_setup_time;
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : async data setup time failure\n");
-		return 1;
-	}
-
-	param[0] = MBOX_SET_ACTIVE_NEG_STATE;
-	param[1] = (hostdata->host_param.req_ack_active_negation << 4)
-		| (hostdata->host_param.data_line_active_negation << 5);
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : set active negation state failure\n");
-		return 1;
-	}
-
-	param[0] = MBOX_SET_PCI_CONTROL_PARAMS;
-	param[1] = hostdata->host_param.data_dma_burst_enable << 1;
-	param[2] = hostdata->host_param.command_dma_burst_enable << 1;
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : set pci control parameter failure\n");
-		return 1;
-	}
-
-	param[0] = MBOX_SET_TAG_AGE_LIMIT;
-	param[1] = hostdata->host_param.tag_aging;
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : set tag age limit failure\n");
-		return 1;
-	}
-
-	param[0] = MBOX_SET_SELECT_TIMEOUT;
-	param[1] = hostdata->host_param.selection_timeout;
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : set selection timeout failure\n");
-		return 1;
-	}
-
-	for (i = 0; i < MAX_TARGETS; i++) {
-
-		if (!hostdata->dev_param[i].device_enable)
-			continue;
-
-		param[0] = MBOX_SET_TARGET_PARAMS;
-		param[1] = i << 8;
-		param[2] = hostdata->dev_param[i].device_flags << 8;
-		param[3] = (hostdata->dev_param[i].synchronous_offset << 8)
-			| hostdata->dev_param[i].synchronous_period;
-
-		isp1020_mbox_command(host, param);
-
-		if (param[0] != MBOX_COMMAND_COMPLETE) {
-			printk("qlogicisp : set target parameter failure\n");
-			return 1;
-		}
-
-		for (k = 0; k < MAX_LUNS; k++) {
-
-			param[0] = MBOX_SET_DEV_QUEUE_PARAMS;
-			param[1] = (i << 8) | k;
-			param[2] = hostdata->host_param.max_queue_depth;
-			param[3] = hostdata->dev_param[i].execution_throttle;
-
-			isp1020_mbox_command(host, param);
-
-			if (param[0] != MBOX_COMMAND_COMPLETE) {
-				printk("qlogicisp : set device queue "
-				       "parameter failure\n");
-				return 1;
-			}
-		}
-	}
-
-	queue_addr = hostdata->res_dma;
-#ifdef CONFIG_QL_ISP_A64
-	param[0] = MBOX_CMD_INIT_RESPONSE_QUEUE_64;
-#else
-	param[0] = MBOX_INIT_RES_QUEUE;
-#endif
-	param[1] = RES_QUEUE_LEN + 1;
-	param[2] = (u_short) (queue_addr >> 16);
-	param[3] = (u_short) (queue_addr & 0xffff);
-	param[4] = 0;
-	param[5] = 0;
-#ifdef CONFIG_QL_ISP_A64
-	param[6] = (u_short) (queue_addr >> 48);
-	param[7] = (u_short) (queue_addr >> 32);
-#endif
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : set response queue failure\n");
-		return 1;
-	}
-
-	queue_addr = hostdata->req_dma;
-#ifdef CONFIG_QL_ISP_A64
-	param[0] = MBOX_CMD_INIT_REQUEST_QUEUE_64;
-#else
-	param[0] = MBOX_INIT_REQ_QUEUE;
-#endif
-	param[1] = QLOGICISP_REQ_QUEUE_LEN + 1;
-	param[2] = (u_short) (queue_addr >> 16);
-	param[3] = (u_short) (queue_addr & 0xffff);
-	param[4] = 0;
-
-#ifdef CONFIG_QL_ISP_A64
-	param[5] = 0;
-	param[6] = (u_short) (queue_addr >> 48);
-	param[7] = (u_short) (queue_addr >> 32);
-#endif
-
-	isp1020_mbox_command(host, param);
-
-	if (param[0] != MBOX_COMMAND_COMPLETE) {
-		printk("qlogicisp : set request queue failure\n");
-		return 1;
-	}
-
-	LEAVE("isp1020_load_parameters");
-
-	return 0;
-}
-
-
-/*
- * currently, this is only called during initialization or abort/reset,
- * at which times interrupts are disabled, so polling is OK, I guess...
- */
-static int isp1020_mbox_command(struct Scsi_Host *host, u_short param[])
-{
-	int loop_count;
-
-	if (mbox_param[param[0]] == 0)
-		return 1;
-
-	loop_count = DEFAULT_LOOP_COUNT;
-	while (--loop_count && isp_inw(host, HOST_HCCR) & 0x0080) {
-		barrier();
-		cpu_relax();
-	}
-	if (!loop_count)
-		printk("qlogicisp: mbox_command loop timeout #1\n");
-
-	switch(mbox_param[param[0]] >> 4) {
-	      case 8: isp_outw(param[7], host, MBOX7);
-	      case 7: isp_outw(param[6], host, MBOX6);
-	      case 6: isp_outw(param[5], host, MBOX5);
-	      case 5: isp_outw(param[4], host, MBOX4);
-	      case 4: isp_outw(param[3], host, MBOX3);
-	      case 3: isp_outw(param[2], host, MBOX2);
-	      case 2: isp_outw(param[1], host, MBOX1);
-	      case 1: isp_outw(param[0], host, MBOX0);
-	}
-
-	isp_outw(0x0, host, PCI_SEMAPHORE);
-	isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
-	isp_outw(HCCR_SET_HOST_INTR, host, HOST_HCCR);
-
-	loop_count = DEFAULT_LOOP_COUNT;
-	while (--loop_count && !(isp_inw(host, PCI_INTF_STS) & 0x04)) {
-		barrier();
-		cpu_relax();
-	}
-	if (!loop_count)
-		printk("qlogicisp: mbox_command loop timeout #2\n");
-
-	loop_count = DEFAULT_LOOP_COUNT;
-	while (--loop_count && isp_inw(host, MBOX0) == 0x04) {
-		barrier();
-		cpu_relax();
-	}
-	if (!loop_count)
-		printk("qlogicisp: mbox_command loop timeout #3\n");
-
-	switch(mbox_param[param[0]] & 0xf) {
-	      case 8: param[7] = isp_inw(host, MBOX7);
-	      case 7: param[6] = isp_inw(host, MBOX6);
-	      case 6: param[5] = isp_inw(host, MBOX5);
-	      case 5: param[4] = isp_inw(host, MBOX4);
-	      case 4: param[3] = isp_inw(host, MBOX3);
-	      case 3: param[2] = isp_inw(host, MBOX2);
-	      case 2: param[1] = isp_inw(host, MBOX1);
-	      case 1: param[0] = isp_inw(host, MBOX0);
-	}
-
-	isp_outw(0x0, host, PCI_SEMAPHORE);
-	isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
-
-	return 0;
-}
-
-
-#if DEBUG_ISP1020_INTR
-
-void isp1020_print_status_entry(struct Status_Entry *status)
-{
-	int i;
-
-	printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n",
-	       status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags);
-	printk("qlogicisp : scsi status = 0x%04x, completion status = 0x%04x\n",
-	       le16_to_cpu(status->scsi_status), le16_to_cpu(status->completion_status));
-	printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n",
-	       le16_to_cpu(status->state_flags), le16_to_cpu(status->status_flags));
-	printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n",
-	       le16_to_cpu(status->time), le16_to_cpu(status->req_sense_len));
-	printk("qlogicisp : residual transfer length = 0x%08x\n",
-	       le32_to_cpu(status->residual));
-
-	for (i = 0; i < le16_to_cpu(status->req_sense_len); i++)
-		printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]);
-}
-
-#endif /* DEBUG_ISP1020_INTR */
-
-
-#if DEBUG_ISP1020
-
-void isp1020_print_scsi_cmd(Scsi_Cmnd *cmd)
-{
-	int i;
-
-	printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
-	       cmd->target, cmd->lun, cmd->cmd_len);
-	printk("qlogicisp : command = ");
-	for (i = 0; i < cmd->cmd_len; i++)
-		printk("0x%02x ", cmd->cmnd[i]);
-	printk("\n");
-}
-
-#endif /* DEBUG_ISP1020 */
-
-MODULE_LICENSE("GPL");
-
-static Scsi_Host_Template driver_template = {
-	.detect			= isp1020_detect,
-	.release		= isp1020_release,
-	.info			= isp1020_info,	
-	.queuecommand		= isp1020_queuecommand,
-	.bios_param		= isp1020_biosparam,
-	.can_queue		= QLOGICISP_REQ_QUEUE_LEN,
-	.this_id		= -1,
-	.sg_tablesize		= QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN),
-	.cmd_per_lun		= 1,
-	.use_clustering		= DISABLE_CLUSTERING,
-};
-#include "scsi_module.c"
diff --git a/drivers/scsi/qlogicisp_asm.c b/drivers/scsi/qlogicisp_asm.c
deleted file mode 100644
index 9ea4bec..0000000
--- a/drivers/scsi/qlogicisp_asm.c
+++ /dev/null
@@ -1,2034 +0,0 @@
-/*
- *      Firmware Version 7.63.00 (12:07 Jan 27, 1999)
- */
-static const unsigned short risc_code_version = 7*1024+63;
-
-static const unsigned short risc_code_addr01 = 0x1000 ;
-
-#if RELOAD_FIRMWARE
-
-static const unsigned short risc_code01[] = {
-	0x0078, 0x103a, 0x0000, 0x3f14, 0x0000, 0x2043, 0x4f50, 0x5952,
-	0x4947, 0x4854, 0x2031, 0x3939, 0x3520, 0x514c, 0x4f47, 0x4943,
-	0x2043, 0x4f52, 0x504f, 0x5241, 0x5449, 0x4f4e, 0x2049, 0x5350,
-	0x3130, 0x3230, 0x2049, 0x2f54, 0x2046, 0x6972, 0x6d77, 0x6172,
-	0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x372e, 0x3633,
-	0x2020, 0x2043, 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20,
-	0x3030, 0x2050, 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020,
-	0x3031, 0x2024, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x0048,
-	0x1045, 0x0038, 0x104b, 0x0078, 0x1047, 0x0028, 0x104b, 0x20b9,
-	0x1212, 0x0078, 0x104d, 0x20b9, 0x2222, 0x20c1, 0x0008, 0x2071,
-	0x0010, 0x70c3, 0x0004, 0x20c9, 0x76ff, 0x2089, 0x1186, 0x70c7,
-	0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0007, 0x3f00,
-	0x70d6, 0x20c1, 0x0008, 0x2019, 0x0000, 0x2009, 0xfeff, 0x2100,
-	0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, 0x206b, 0x0a0a, 0xaddc,
-	0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, 0xa286, 0xa5a5, 0x0040,
-	0x10bf, 0xa386, 0x000f, 0x0040, 0x1085, 0x2c6a, 0x2a5a, 0x20c1,
-	0x0000, 0x2019, 0x000f, 0x0078, 0x1065, 0x2c6a, 0x2a5a, 0x20c1,
-	0x0008, 0x2009, 0x7fff, 0x2148, 0x2944, 0x204b, 0x0a0a, 0xa9bc,
-	0x3fff, 0x2734, 0x203b, 0x5050, 0x2114, 0xa286, 0x0a0a, 0x0040,
-	0x10a9, 0x284a, 0x263a, 0x20c1, 0x0004, 0x2009, 0x3fff, 0x2134,
-	0x200b, 0x5050, 0x2114, 0xa286, 0x5050, 0x0040, 0x10aa, 0x0078,
-	0x118e, 0x284a, 0x263a, 0x98c0, 0xa188, 0x1000, 0x212c, 0x200b,
-	0xa5a5, 0x2114, 0xa286, 0xa5a5, 0x0040, 0x10bc, 0x250a, 0xa18a,
-	0x1000, 0x98c1, 0x0078, 0x10c1, 0x250a, 0x0078, 0x10c1, 0x2c6a,
-	0x2a5a, 0x2130, 0xa18a, 0x0040, 0x2128, 0xa1a2, 0x5000, 0x8424,
-	0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0xa192, 0x7700, 0x2009,
-	0x0000, 0x2001, 0x0031, 0x1078, 0x1c9d, 0x2218, 0x2079, 0x5000,
-	0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109,
-	0x00c0, 0x10dc, 0x7ef2, 0x8528, 0x7de6, 0x7cea, 0x7bee, 0x7883,
-	0x0000, 0x2031, 0x0030, 0x78cf, 0x0101, 0x780b, 0x0002, 0x780f,
-	0x0002, 0x784f, 0x0003, 0x2069, 0x5040, 0x2001, 0x04fd, 0x2004,
-	0xa082, 0x0005, 0x0048, 0x1104, 0x0038, 0x1100, 0x0078, 0x1108,
-	0x681b, 0x003c, 0x0078, 0x110a, 0x00a8, 0x1108, 0x681b, 0x003c,
-	0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008,
-	0x6813, 0x0005, 0x6823, 0x0000, 0x6827, 0x0006, 0x6817, 0x0008,
-	0x682b, 0x0000, 0x681f, 0x0019, 0x2069, 0x5280, 0x2011, 0x0020,
-	0x2009, 0x0010, 0x680b, 0x080c, 0x680f, 0x0019, 0x6803, 0xfd00,
-	0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004,
-	0x8109, 0x00c0, 0x1122, 0x2069, 0x5300, 0x2009, 0x0002, 0x20a9,
-	0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bf0, 0xa386, 0xfeff,
-	0x00c0, 0x1148, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, 0x114c,
-	0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x0070, 0x1152,
-	0x0078, 0x1139, 0x8109, 0x00c0, 0x1137, 0x1078, 0x21e9, 0x1078,
-	0x46e9, 0x1078, 0x1946, 0x1078, 0x4bdf, 0x3200, 0xa085, 0x000d,
-	0x2090, 0x70c3, 0x0000, 0x0090, 0x116c, 0x70c0, 0xa086, 0x0002,
-	0x00c0, 0x116c, 0x1078, 0x1284, 0x1078, 0x1196, 0x78cc, 0xa005,
-	0x00c0, 0x117a, 0x1078, 0x1cc6, 0x0010, 0x1180, 0x0068, 0x1180,
-	0x1078, 0x20c8, 0x0010, 0x1180, 0x0068, 0x1180, 0x1078, 0x1a2b,
-	0x00e0, 0x116c, 0x1078, 0x4a66, 0x0078, 0x116c, 0x118e, 0x1190,
-	0x23ea, 0x23ea, 0x476a, 0x476a, 0x23ea, 0x23ea, 0x0078, 0x118e,
-	0x0078, 0x1190, 0x0078, 0x1192, 0x0078, 0x1194, 0x0068, 0x1201,
-	0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1201, 0x7814,
-	0xa005, 0x00c0, 0x11a7, 0x0010, 0x1202, 0x0078, 0x1201, 0x2009,
-	0x505b, 0x2104, 0xa005, 0x00c0, 0x1201, 0x2009, 0x5064, 0x200b,
-	0x0000, 0x7914, 0xa186, 0x0042, 0x00c0, 0x11cc, 0x7816, 0x2009,
-	0x5062, 0x2164, 0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca,
-	0x611c, 0xa18c, 0xff00, 0x6020, 0xa084, 0x00ff, 0xa105, 0x70ce,
-	0x1078, 0x192b, 0x0078, 0x11ff, 0x7814, 0xa086, 0x0018, 0x00c0,
-	0x11d3, 0x1078, 0x165a, 0x7817, 0x0000, 0x2009, 0x5062, 0x2104,
-	0xa065, 0x0040, 0x11ef, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x1996,
-	0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c, 0x6007,
-	0x0103, 0x1078, 0x1907, 0x00c0, 0x11fb, 0x1078, 0x192b, 0x2009,
-	0x5062, 0x200b, 0x0000, 0x2009, 0x505c, 0x2104, 0x200b, 0x0000,
-	0xa005, 0x0040, 0x11ff, 0x2001, 0x4005, 0x0078, 0x1286, 0x0078,
-	0x1284, 0x007c, 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000,
-	0x70cf, 0x0000, 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1252, 0x2038,
-	0x0079, 0x1212, 0x1284, 0x12e5, 0x12a9, 0x12fe, 0x130d, 0x1313,
-	0x12a0, 0x1748, 0x1317, 0x1298, 0x12ad, 0x12af, 0x12b1, 0x12b3,
-	0x174d, 0x1298, 0x1329, 0x1360, 0x1672, 0x1742, 0x12b5, 0x1591,
-	0x15ad, 0x15c9, 0x15f4, 0x154a, 0x1558, 0x156c, 0x1580, 0x13df,
-	0x1298, 0x138d, 0x1393, 0x1398, 0x139d, 0x13a3, 0x13a8, 0x13ad,
-	0x13b2, 0x13b7, 0x13bb, 0x13d0, 0x13dc, 0x1298, 0x1298, 0x1298,
-	0x1298, 0x13eb, 0x13f4, 0x1403, 0x1429, 0x1433, 0x143a, 0x1480,
-	0x148f, 0x149e, 0x14b0, 0x152a, 0x153a, 0x1298, 0x1298, 0x1298,
-	0x1298, 0x153f, 0xa0bc, 0xffa0, 0x00c0, 0x1298, 0x2038, 0xa084,
-	0x001f, 0x0079, 0x125b, 0x1786, 0x1789, 0x1799, 0x1298, 0x1298,
-	0x18d8, 0x18f5, 0x1298, 0x1298, 0x1298, 0x18f9, 0x1901, 0x1298,
-	0x1298, 0x1298, 0x1298, 0x12db, 0x12f4, 0x131f, 0x1356, 0x1668,
-	0x1764, 0x1778, 0x1298, 0x1829, 0x1298, 0x18b4, 0x18be, 0x18c2,
-	0x18d0, 0x1298, 0x1298, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078,
-	0x1286, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068,
-	0x1287, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x00e0,
-	0x128f, 0x00e0, 0x1291, 0x0068, 0x1291, 0x2091, 0x4080, 0x007c,
-	0x70c3, 0x4001, 0x0078, 0x1287, 0x70c3, 0x4006, 0x0078, 0x1287,
-	0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078,
-	0x1284, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x1284, 0x0078,
-	0x1284, 0x0078, 0x1284, 0x0078, 0x1284, 0x2091, 0x8000, 0x70c3,
-	0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3,
-	0x0007, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031,
-	0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061,
-	0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091,
-	0x4080, 0x0078, 0x0455, 0x1078, 0x1b36, 0x00c0, 0x129c, 0x75d8,
-	0x74dc, 0x75da, 0x74de, 0x0078, 0x12e8, 0x2029, 0x0000, 0x2520,
-	0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1a70, 0x0040, 0x1284,
-	0x70c3, 0x4002, 0x0078, 0x1284, 0x1078, 0x1b36, 0x00c0, 0x129c,
-	0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1301, 0x2029, 0x0000,
-	0x2520, 0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1ad0, 0x0040,
-	0x1284, 0x70c3, 0x4002, 0x0078, 0x1284, 0x71c4, 0x70c8, 0x2114,
-	0x200a, 0x0078, 0x1282, 0x71c4, 0x2114, 0x0078, 0x1282, 0x70c7,
-	0x0007, 0x70cb, 0x003f, 0x70cf, 0x0000, 0x0078, 0x1284, 0x1078,
-	0x1b36, 0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078,
-	0x132c, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0,
-	0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x1350, 0x8001,
-	0x7892, 0xa084, 0xfc00, 0x0040, 0x1345, 0x78cc, 0xa085, 0x0001,
-	0x78ce, 0x2001, 0x4005, 0x0078, 0x1286, 0x7a9a, 0x7b9e, 0x7da2,
-	0x7ea6, 0x7c96, 0x78cc, 0xa084, 0xfffc, 0x78ce, 0x0078, 0x1354,
-	0x78cc, 0xa085, 0x0001, 0x78ce, 0x0078, 0x1284, 0x1078, 0x1b36,
-	0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1363,
-	0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6,
-	0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, 0x1387, 0x8001, 0x78ae,
-	0xa084, 0xfc00, 0x0040, 0x137c, 0x78cc, 0xa085, 0x0100, 0x78ce,
-	0x2001, 0x4005, 0x0078, 0x1286, 0x7ab6, 0x7bba, 0x7dbe, 0x7ec2,
-	0x7cb2, 0x78cc, 0xa084, 0xfcff, 0x78ce, 0x0078, 0x138b, 0x78cc,
-	0xa085, 0x0100, 0x78ce, 0x0078, 0x1284, 0x2009, 0x5061, 0x210c,
-	0x7aec, 0x0078, 0x1282, 0x2009, 0x5041, 0x210c, 0x0078, 0x1283,
-	0x2009, 0x5042, 0x210c, 0x0078, 0x1283, 0x2061, 0x5040, 0x610c,
-	0x6210, 0x0078, 0x1282, 0x2009, 0x5045, 0x210c, 0x0078, 0x1283,
-	0x2009, 0x5046, 0x210c, 0x0078, 0x1283, 0x2009, 0x5048, 0x210c,
-	0x0078, 0x1283, 0x2009, 0x5049, 0x210c, 0x0078, 0x1283, 0x7908,
-	0x7a0c, 0x0078, 0x1282, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003,
-	0x8003, 0x8003, 0xa0e8, 0x5280, 0x6a00, 0x6804, 0xa084, 0x0008,
-	0x0040, 0x13cd, 0x6b08, 0x0078, 0x13ce, 0x6b0c, 0x0078, 0x1281,
-	0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091,
-	0x8001, 0x2708, 0x0078, 0x1281, 0x794c, 0x0078, 0x1283, 0x77c4,
-	0x1078, 0x1956, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091,
-	0x8001, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x127c,
-	0x1078, 0x22c1, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8,
-	0x127c, 0x2011, 0x5041, 0x2204, 0x007e, 0x2112, 0x1078, 0x227a,
-	0x017f, 0x0078, 0x1283, 0x71c4, 0x2011, 0x1421, 0x20a9, 0x0008,
-	0x2204, 0xa106, 0x0040, 0x1413, 0x8210, 0x0070, 0x1411, 0x0078,
-	0x1408, 0x0078, 0x127c, 0xa292, 0x1421, 0x027e, 0x2011, 0x5042,
-	0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x2286, 0x017f, 0x0078,
-	0x1283, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032,
-	0x004b, 0x2061, 0x5040, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8,
-	0x6012, 0x0078, 0x1282, 0x2061, 0x5040, 0x6114, 0x70c4, 0x6016,
-	0x0078, 0x1283, 0x2061, 0x5040, 0x71c4, 0x2011, 0x0004, 0x601f,
-	0x0019, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040, 0x145b, 0x2011,
-	0x0005, 0x601f, 0x0019, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040,
-	0x145b, 0x2011, 0x0006, 0x601f, 0x000c, 0x2019, 0x2222, 0xa186,
-	0x003c, 0x00c0, 0x127c, 0x6018, 0x007e, 0x611a, 0x7800, 0xa084,
-	0x0001, 0x00c0, 0x1476, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
-	0x0048, 0x146e, 0x0038, 0x1472, 0x0078, 0x1476, 0x0028, 0x1472,
-	0x0078, 0x1476, 0x2019, 0x2222, 0x0078, 0x1478, 0x2019, 0x1212,
-	0x23b8, 0x1078, 0x2297, 0x1078, 0x4bdf, 0x017f, 0x0078, 0x1283,
-	0x71c4, 0xa184, 0xffcf, 0x00c0, 0x127c, 0x2011, 0x5048, 0x2204,
-	0x2112, 0x007e, 0x1078, 0x22b9, 0x017f, 0x0078, 0x1283, 0x71c4,
-	0xa182, 0x0010, 0x00c8, 0x127c, 0x2011, 0x5049, 0x2204, 0x007e,
-	0x2112, 0x1078, 0x22a8, 0x017f, 0x0078, 0x1283, 0x71c4, 0x72c8,
-	0xa184, 0xfffd, 0x00c0, 0x127b, 0xa284, 0xfffd, 0x00c0, 0x127b,
-	0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x1282,
-	0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8,
-	0x5280, 0x2019, 0x0000, 0x72c8, 0xa284, 0x0080, 0x0040, 0x14c6,
-	0x6c14, 0x84ff, 0x00c0, 0x14c6, 0x6817, 0x0040, 0xa284, 0x0040,
-	0x0040, 0x14d0, 0x6c10, 0x84ff, 0x00c0, 0x14d0, 0x6813, 0x0001,
-	0x6800, 0x007e, 0xa226, 0x0040, 0x14f3, 0x6a02, 0xa484, 0x2000,
-	0x0040, 0x14dc, 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x14e2,
-	0xa39d, 0x0008, 0xa484, 0x4000, 0x0040, 0x14f3, 0x810f, 0xa284,
-	0x4000, 0x0040, 0x14ef, 0x1078, 0x22db, 0x0078, 0x14f3, 0x1078,
-	0x22cd, 0x0078, 0x14f3, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1522,
-	0xa2a4, 0x00ff, 0x2061, 0x5040, 0x6118, 0xa186, 0x0028, 0x0040,
-	0x1509, 0xa186, 0x0032, 0x0040, 0x150f, 0xa186, 0x003c, 0x0040,
-	0x1515, 0xa482, 0x0064, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482,
-	0x0050, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482, 0x0043, 0x0048,
-	0x151f, 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x127d, 0x6a0a,
-	0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4,
-	0x0078, 0x1281, 0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6a14,
-	0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708,
-	0x0078, 0x1281, 0x70c4, 0x794c, 0x784e, 0x0078, 0x1283, 0x71c4,
-	0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x127c, 0x1078, 0x22e9,
-	0x0078, 0x1281, 0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6a08,
-	0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282,
-	0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9,
-	0x6a0a, 0x6804, 0xa005, 0x0040, 0x1567, 0x1078, 0x21b1, 0x2091,
-	0x8001, 0x2708, 0x0078, 0x1282, 0x77c4, 0x1078, 0x1956, 0x2091,
-	0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005, 0x0040,
-	0x157b, 0x1078, 0x21b1, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282,
-	0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091,
-	0x8000, 0x1078, 0x1963, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078,
-	0x1282, 0x77c4, 0x72c8, 0x73cc, 0x77c6, 0x72ca, 0x73ce, 0x1078,
-	0x19c4, 0x00c0, 0x15a9, 0x6818, 0xa005, 0x0040, 0x15a9, 0x2708,
-	0x1078, 0x22f9, 0x00c0, 0x15a9, 0x7817, 0x0015, 0x2091, 0x8001,
-	0x007c, 0x2091, 0x8001, 0x0078, 0x1284, 0x77c4, 0x77c6, 0x2041,
-	0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078,
-	0x1963, 0x2061, 0x5040, 0x606f, 0x0003, 0x6782, 0x6093, 0x000f,
-	0x6073, 0x0000, 0x7817, 0x0016, 0x1078, 0x21b1, 0x2091, 0x8001,
-	0x007c, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2091,
-	0x8000, 0x2061, 0x5040, 0x606f, 0x0002, 0x6073, 0x0000, 0x6782,
-	0x6093, 0x000f, 0x7817, 0x0017, 0x1078, 0x21b1, 0x2091, 0x8001,
-	0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x2091, 0x8000,
-	0x1078, 0x1963, 0x70c8, 0x6836, 0x8738, 0xa784, 0x001f, 0x00c0,
-	0x15e8, 0x2091, 0x8001, 0x007c, 0x78cc, 0xa084, 0x0003, 0x00c0,
-	0x1618, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051,
-	0x0008, 0x1078, 0x1956, 0x2091, 0x8000, 0x6808, 0xa80d, 0x690a,
-	0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1601, 0xa7bc,
-	0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1601,
-	0x2091, 0x8000, 0x2069, 0x0100, 0x6830, 0xa084, 0x0040, 0x0040,
-	0x1641, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004,
-	0x0040, 0x162e, 0x0070, 0x162e, 0x0078, 0x1625, 0x684b, 0x0009,
-	0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x163b, 0x0070,
-	0x163b, 0x0078, 0x1632, 0x20a9, 0x00fa, 0x0070, 0x1641, 0x0078,
-	0x163d, 0x2079, 0x5000, 0x7817, 0x0018, 0x2061, 0x5040, 0x606f,
-	0x0001, 0x6073, 0x0000, 0x6093, 0x000f, 0x78cc, 0xa085, 0x0002,
-	0x78ce, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0048, 0x2091,
-	0x8001, 0x007c, 0x78cc, 0xa084, 0xfffd, 0x78ce, 0xa084, 0x0001,
-	0x00c0, 0x1664, 0x1078, 0x1a0e, 0x71c4, 0x71c6, 0x794a, 0x007c,
-	0x1078, 0x1b36, 0x00c0, 0x129c, 0x75d8, 0x74dc, 0x75da, 0x74de,
-	0x0078, 0x1675, 0x2029, 0x0000, 0x2520, 0x71c4, 0x73c8, 0x72cc,
-	0x71c6, 0x73ca, 0x72ce, 0x2079, 0x5000, 0x2091, 0x8000, 0x1078,
-	0x1911, 0x2091, 0x8001, 0x0040, 0x172c, 0x20a9, 0x0005, 0x20a1,
-	0x5018, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, 0x2009, 0x0020,
-	0x1078, 0x190c, 0x0040, 0x1698, 0x1078, 0x192b, 0x0078, 0x172c,
-	0x6004, 0xa084, 0xff00, 0x8007, 0x8009, 0x0040, 0x16fb, 0x0c7e,
-	0x2c68, 0x2091, 0x8000, 0x1078, 0x1911, 0x2091, 0x8001, 0x0040,
-	0x16cc, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x16a0, 0x609f, 0x0000,
-	0x0c7f, 0x0c7e, 0x7218, 0x731c, 0x7420, 0x7524, 0x2c68, 0x689c,
-	0xa065, 0x0040, 0x16fa, 0x2009, 0x0020, 0x1078, 0x190c, 0x00c0,
-	0x16e3, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x00c0, 0x16cc,
-	0x2d00, 0x6002, 0x0078, 0x16b2, 0x0c7f, 0x0c7e, 0x609c, 0x2060,
-	0x1078, 0x1996, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009,
-	0x000c, 0x6008, 0xa085, 0x0200, 0x600a, 0x1078, 0x1907, 0x1078,
-	0x192b, 0x0078, 0x172c, 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078,
-	0x1996, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c,
-	0x6007, 0x0103, 0x601b, 0x0003, 0x1078, 0x1907, 0x1078, 0x192b,
-	0x0078, 0x172c, 0x0c7f, 0x74c4, 0x73c8, 0x72cc, 0x6014, 0x2091,
-	0x8000, 0x7817, 0x0012, 0x0e7e, 0x2071, 0x5040, 0x706f, 0x0005,
-	0x7073, 0x0000, 0x7376, 0x727a, 0x747e, 0x7082, 0x7087, 0x0000,
-	0x2c00, 0x708a, 0x708f, 0x0000, 0xa02e, 0x2530, 0x611c, 0x61a2,
-	0xa184, 0x0060, 0x0040, 0x171e, 0x1078, 0x467f, 0x0e7f, 0x6596,
-	0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x1078,
-	0x21b1, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x1287,
-	0x20a9, 0x0005, 0x2099, 0x5018, 0x2091, 0x8000, 0x530a, 0x2091,
-	0x8001, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9,
-	0x0000, 0x007c, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x1284,
-	0x71c4, 0x71c6, 0x2168, 0x0078, 0x174f, 0x2069, 0x1000, 0x690c,
-	0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1751, 0xa285,
-	0x0000, 0x00c0, 0x175f, 0x70c3, 0x4000, 0x0078, 0x1761, 0x70c3,
-	0x4003, 0x70ca, 0x0078, 0x1287, 0x2011, 0x5067, 0x220c, 0x70c4,
-	0x8003, 0x0048, 0x1771, 0x1078, 0x3b49, 0xa184, 0x7fff, 0x0078,
-	0x1775, 0x1078, 0x3b3c, 0xa185, 0x8000, 0x2012, 0x0078, 0x1283,
-	0x71c4, 0x1078, 0x3b33, 0x6100, 0x2001, 0x5067, 0x2004, 0xa084,
-	0x8000, 0xa10d, 0x6204, 0x6308, 0x0078, 0x1281, 0x79e4, 0x0078,
-	0x1283, 0x71c4, 0x71c6, 0x2198, 0x20a1, 0x0042, 0x20a9, 0x0004,
-	0x53a3, 0x21a0, 0x2099, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x0078,
-	0x1284, 0x70c4, 0x2068, 0x2079, 0x5000, 0x2091, 0x8000, 0x1078,
-	0x1911, 0x2091, 0x8001, 0x0040, 0x1825, 0x6007, 0x0001, 0x600b,
-	0x0000, 0x602b, 0x0000, 0x601b, 0x0006, 0x6a10, 0xa28c, 0x000f,
-	0xa284, 0x00f0, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x6016,
-	0xa284, 0x0800, 0x0040, 0x17c0, 0x601b, 0x000a, 0x0078, 0x17c6,
-	0xa284, 0x1000, 0x0040, 0x17c6, 0x601b, 0x000c, 0xa284, 0x0300,
-	0x0040, 0x17cf, 0x602b, 0x0001, 0x8004, 0x8004, 0x8004, 0xa085,
-	0x0001, 0x601e, 0x6023, 0x0000, 0x6027, 0x0000, 0xa284, 0x0400,
-	0x0040, 0x17dc, 0x602b, 0x0000, 0x20a9, 0x0006, 0xac80, 0x000b,
-	0x20a0, 0xad80, 0x0005, 0x2098, 0x53a3, 0xa284, 0x0300, 0x00c0,
-	0x17f1, 0x6046, 0x604a, 0x604e, 0x6052, 0x6096, 0x609a, 0x0078,
-	0x17fb, 0x6800, 0x6046, 0x6804, 0x604a, 0x6e08, 0x664e, 0x6d0c,
-	0x6552, 0x6596, 0x669a, 0x6014, 0x2091, 0x8000, 0x7817, 0x0042,
-	0x2c08, 0x2061, 0x5040, 0x606f, 0x0005, 0x6073, 0x0000, 0x6077,
-	0x0000, 0x607b, 0x0000, 0x607f, 0x0000, 0x6082, 0x618a, 0xa284,
-	0x0400, 0x608e, 0x2091, 0x8001, 0x0e7e, 0x2071, 0x0020, 0x7007,
-	0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x0e7f, 0x2091, 0x8000,
-	0x1078, 0x21b1, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078,
-	0x1287, 0x0c7e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2091, 0x8000, 0x2071,
-	0x5040, 0x2079, 0x0100, 0x2061, 0x0010, 0x70a0, 0xa06d, 0x0040,
-	0x18aa, 0x6a04, 0xa294, 0x00ff, 0xa286, 0x0007, 0x0040, 0x1844,
-	0xa286, 0x000f, 0x00c0, 0x18aa, 0x691c, 0xa184, 0x0080, 0x00c0,
-	0x18aa, 0x6824, 0xa18c, 0xff00, 0xa085, 0x0019, 0x6826, 0x71b0,
-	0x81ff, 0x0040, 0x1865, 0x0d7e, 0x2069, 0x0020, 0x6908, 0x6808,
-	0xa106, 0x00c0, 0x1856, 0x690c, 0x680c, 0xa106, 0x00c0, 0x185b,
-	0xa184, 0x00ff, 0x00c0, 0x185b, 0x0d7f, 0x78b8, 0xa084, 0x801f,
-	0x00c0, 0x1865, 0x7848, 0xa085, 0x000c, 0x784a, 0x71b0, 0x81ff,
-	0x0040, 0x1888, 0x70b3, 0x0000, 0x0d7e, 0x2069, 0x0020, 0x6807,
-	0x0008, 0x6804, 0xa084, 0x0008, 0x00c0, 0x1879, 0x6807, 0x0008,
-	0x6804, 0xa084, 0x0008, 0x00c0, 0x1880, 0x6807, 0x0002, 0x0d7f,
-	0x61c4, 0x62c8, 0x63cc, 0x61c6, 0x62ca, 0x63ce, 0x0e7e, 0x2071,
-	0x5000, 0x7266, 0x736a, 0xae80, 0x0019, 0x0e7f, 0x1078, 0x4598,
-	0x78a3, 0x0000, 0x7858, 0xa084, 0xedff, 0x785a, 0x70b4, 0xa080,
-	0x00da, 0x781a, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001,
-	0x0078, 0x1284, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001,
-	0x2001, 0x4005, 0x0078, 0x1286, 0x7980, 0x71c6, 0x71c4, 0xa182,
-	0x0003, 0x00c8, 0x127c, 0x7982, 0x0078, 0x1284, 0x7980, 0x71c6,
-	0x0078, 0x1284, 0x7974, 0x71c6, 0x71c4, 0x7976, 0x7978, 0x71ca,
-	0x71c8, 0x797a, 0x797c, 0x71ce, 0x71cc, 0x797e, 0x0078, 0x1284,
-	0x7974, 0x71c6, 0x7978, 0x71ca, 0x797c, 0x71ce, 0x0078, 0x1284,
-	0x7900, 0x71c6, 0x71c4, 0x7902, 0x2001, 0x04fd, 0x2004, 0xa082,
-	0x0005, 0x0048, 0x18e7, 0x0038, 0x18e9, 0x0078, 0x18f3, 0x00a8,
-	0x18f3, 0xa18c, 0x0001, 0x00c0, 0x18f1, 0x20b9, 0x2222, 0x0078,
-	0x18f3, 0x20b9, 0x1212, 0x0078, 0x1284, 0x7900, 0x71c6, 0x0078,
-	0x1284, 0x2009, 0x5074, 0x2104, 0x70c6, 0x70c4, 0x200a, 0x0078,
-	0x1284, 0x2009, 0x5074, 0x2104, 0x70c6, 0x0078, 0x1284, 0xac80,
-	0x0001, 0x1078, 0x1af2, 0x007c, 0xac80, 0x0001, 0x1078, 0x1a92,
-	0x007c, 0x7850, 0xa065, 0x0040, 0x1919, 0x2c04, 0x7852, 0x2063,
-	0x0000, 0x007c, 0x0f7e, 0x2079, 0x5000, 0x7850, 0xa06d, 0x0040,
-	0x1929, 0x2d04, 0x7852, 0x6803, 0x0000, 0x6807, 0x0000, 0x680b,
-	0x0000, 0x0f7f, 0x007c, 0x2091, 0x8000, 0x0f7e, 0x2079, 0x5000,
-	0x7850, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1938, 0x1078, 0x23ca,
-	0x7852, 0x0f7f, 0x2091, 0x8001, 0x007c, 0x0f7e, 0x2079, 0x5000,
-	0x7850, 0x206a, 0x2d00, 0x7852, 0x0f7f, 0x007c, 0x2011, 0x7700,
-	0x7a52, 0x7bec, 0x8319, 0x0040, 0x1953, 0xa280, 0x0031, 0x2012,
-	0x2010, 0x0078, 0x194a, 0x2013, 0x0000, 0x007c, 0xa784, 0x0f00,
-	0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105,
-	0xa0e8, 0x5300, 0x007c, 0x1078, 0x1956, 0x2900, 0x682a, 0x2a00,
-	0x682e, 0x6808, 0xa084, 0xffef, 0xa80d, 0x690a, 0x2009, 0x5052,
-	0x210c, 0x6804, 0xa005, 0x0040, 0x1995, 0xa116, 0x00c0, 0x1980,
-	0x2060, 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x1983,
-	0x2009, 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1992, 0x6000,
-	0x6806, 0x1078, 0x19a3, 0x1078, 0x1c42, 0x6810, 0x8001, 0x6812,
-	0x00c0, 0x1983, 0x017f, 0x6902, 0x6906, 0x007c, 0xa065, 0x0040,
-	0x19a2, 0x609c, 0x609f, 0x0000, 0x2008, 0x1078, 0x192b, 0x2100,
-	0x0078, 0x1996, 0x007c, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9,
-	0x001c, 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828,
-	0x601a, 0x682c, 0x6022, 0x007c, 0x0e7e, 0x2071, 0x5040, 0x704c,
-	0xa08c, 0x0200, 0x00c0, 0x19c2, 0xa088, 0x5080, 0x2d0a, 0x8000,
-	0x704e, 0xa006, 0x0e7f, 0x007c, 0x1078, 0x1956, 0x2091, 0x8000,
-	0x6804, 0x781e, 0xa065, 0x0040, 0x1a0d, 0x0078, 0x19d5, 0x2c00,
-	0x781e, 0x6000, 0xa065, 0x0040, 0x1a0d, 0x600c, 0xa306, 0x00c0,
-	0x19cf, 0x6010, 0xa206, 0x00c0, 0x19cf, 0x2c28, 0x2001, 0x5052,
-	0x2004, 0xac06, 0x00c0, 0x19e6, 0x0078, 0x1a0b, 0x6804, 0xac06,
-	0x00c0, 0x19f3, 0x6000, 0xa065, 0x6806, 0x00c0, 0x19fd, 0x6803,
-	0x0000, 0x0078, 0x19fd, 0x6400, 0x781c, 0x2060, 0x6402, 0xa486,
-	0x0000, 0x00c0, 0x19fd, 0x2c00, 0x6802, 0x2560, 0x1078, 0x19a3,
-	0x601b, 0x0005, 0x6023, 0x0020, 0x1078, 0x1c42, 0x6810, 0x8001,
-	0x1050, 0x23ca, 0x6812, 0xa085, 0xffff, 0x007c, 0x2039, 0x0000,
-	0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, 0x8000,
-	0x1078, 0x1963, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1a18, 0xa7bc,
-	0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1a18,
-	0x2091, 0x8001, 0x007c, 0x2061, 0x0000, 0x6018, 0xa084, 0x0001,
-	0x00c0, 0x1a3c, 0x2091, 0x8000, 0x78e0, 0x78e3, 0x0000, 0x2091,
-	0x8001, 0xa005, 0x00c0, 0x1a3d, 0x007c, 0xa08c, 0xfff0, 0x0040,
-	0x1a43, 0x1078, 0x23ca, 0x0079, 0x1a45, 0x1a55, 0x1a58, 0x1a5e,
-	0x1a62, 0x1a56, 0x1a66, 0x1a6c, 0x1a56, 0x1a56, 0x1c0c, 0x1c30,
-	0x1c34, 0x1a56, 0x1a56, 0x1a56, 0x1a56, 0x007c, 0x1078, 0x23ca,
-	0x1078, 0x1a0e, 0x2001, 0x8001, 0x0078, 0x1c3a, 0x2001, 0x8003,
-	0x0078, 0x1c3a, 0x2001, 0x8004, 0x0078, 0x1c3a, 0x1078, 0x1a0e,
-	0x2001, 0x8006, 0x0078, 0x1c3a, 0x2001, 0x8007, 0x0078, 0x1c3a,
-	0x2030, 0x2138, 0xa782, 0x0021, 0x0048, 0x1a78, 0x2009, 0x0020,
-	0x2600, 0x1078, 0x1a92, 0x00c0, 0x1a91, 0xa7ba, 0x0020, 0x0048,
-	0x1a90, 0x0040, 0x1a90, 0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040,
-	0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1a72,
-	0xa006, 0x007c, 0x81ff, 0x0040, 0x1acd, 0x2099, 0x0030, 0x20a0,
-	0x700c, 0xa084, 0x00ff, 0x0040, 0x1aa4, 0x7007, 0x0004, 0x7004,
-	0xa084, 0x0004, 0x00c0, 0x1a9f, 0x21a8, 0x7017, 0x0000, 0x810b,
-	0x7112, 0x721a, 0x731e, 0x7422, 0x7526, 0x780c, 0xa085, 0x0001,
-	0x7002, 0x7007, 0x0001, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
-	0x00c8, 0x1ac1, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0,
-	0x1ab3, 0x7008, 0x800b, 0x00c8, 0x1ab3, 0x7007, 0x0002, 0xa08c,
-	0x01e0, 0x00c0, 0x1acd, 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c,
-	0x2030, 0x2138, 0xa782, 0x0021, 0x0048, 0x1ad8, 0x2009, 0x0020,
-	0x2600, 0x1078, 0x1af2, 0x00c0, 0x1af1, 0xa7ba, 0x0020, 0x0048,
-	0x1af0, 0x0040, 0x1af0, 0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040,
-	0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1ad2,
-	0xa006, 0x007c, 0x81ff, 0x0040, 0x1b33, 0x2098, 0x20a1, 0x0030,
-	0x700c, 0xa084, 0x00ff, 0x0040, 0x1b04, 0x7007, 0x0004, 0x7004,
-	0xa084, 0x0004, 0x00c0, 0x1aff, 0x21a8, 0x7017, 0x0000, 0x810b,
-	0x7112, 0x721a, 0x731e, 0x7422, 0x7526, 0x780c, 0xa085, 0x0000,
-	0x7002, 0x53a6, 0x7007, 0x0001, 0x2001, 0x04fd, 0x2004, 0xa082,
-	0x0005, 0x00c8, 0x1b22, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000,
-	0x00c0, 0x1b14, 0x7010, 0xa084, 0xf000, 0x0040, 0x1b2b, 0x7007,
-	0x0008, 0x0078, 0x1b2f, 0x7108, 0x8103, 0x00c8, 0x1b14, 0x7007,
-	0x0002, 0xa184, 0x01e0, 0x7003, 0x0000, 0x007c, 0x2001, 0x04fd,
-	0x2004, 0xa082, 0x0004, 0x00c8, 0x1b3f, 0x0078, 0x1b42, 0xa006,
-	0x0078, 0x1b44, 0xa085, 0x0001, 0x007c, 0x0e7e, 0x2071, 0x5000,
-	0x2d08, 0x7058, 0x6802, 0xa005, 0x00c0, 0x1b4f, 0x715e, 0x715a,
-	0x0e7f, 0x007c, 0x2c08, 0x7858, 0x6002, 0xa005, 0x00c0, 0x1b59,
-	0x795e, 0x795a, 0x007c, 0x2091, 0x8000, 0x6003, 0x0000, 0x2c08,
-	0x785c, 0xa065, 0x00c0, 0x1b67, 0x795a, 0x0078, 0x1b68, 0x6102,
-	0x795e, 0x2091, 0x8001, 0x1078, 0x21ce, 0x007c, 0x0e7e, 0x2071,
-	0x5000, 0x7058, 0xa06d, 0x0040, 0x1b7c, 0x6800, 0x705a, 0xa005,
-	0x00c0, 0x1b7b, 0x705e, 0x8dff, 0x0e7f, 0x007c, 0x0d7e, 0x0c7e,
-	0x0f7e, 0x2079, 0x5000, 0xaf80, 0x0016, 0x2060, 0x6000, 0xa005,
-	0x0040, 0x1bac, 0x2068, 0x6814, 0xa306, 0x00c0, 0x1b95, 0x6828,
-	0xa084, 0x00ff, 0xa406, 0x0040, 0x1b98, 0x2d60, 0x0078, 0x1b86,
-	0x6800, 0xa005, 0x6002, 0x00c0, 0x1ba4, 0xaf80, 0x0016, 0xac06,
-	0x0040, 0x1ba3, 0x2c00, 0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040,
-	0x1bab, 0x1078, 0x1996, 0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005,
-	0x007c, 0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5000, 0xaf80, 0x0016,
-	0x2060, 0x6000, 0xa005, 0x0040, 0x1bdb, 0x2068, 0x6814, 0xa084,
-	0x00ff, 0xa306, 0x0040, 0x1bc7, 0x2d60, 0x0078, 0x1bb9, 0x6800,
-	0xa005, 0x6002, 0x00c0, 0x1bd3, 0xaf80, 0x0016, 0xac06, 0x0040,
-	0x1bd2, 0x2c00, 0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040, 0x1bda,
-	0x1078, 0x1996, 0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c,
-	0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5000, 0xaf80, 0x0016, 0x2060,
-	0x6000, 0xa06d, 0x0040, 0x1c07, 0x6814, 0xa306, 0x0040, 0x1bf3,
-	0x2d60, 0x0078, 0x1be8, 0x6800, 0xa005, 0x6002, 0x00c0, 0x1bff,
-	0xaf80, 0x0016, 0xac06, 0x0040, 0x1bfe, 0x2c00, 0x785e, 0x0d7e,
-	0x689c, 0xa005, 0x0040, 0x1c06, 0x1078, 0x1996, 0x007f, 0x0f7f,
-	0x0c7f, 0x0d7f, 0xa005, 0x007c, 0x2091, 0x8000, 0x2069, 0x5040,
-	0x6800, 0xa086, 0x0000, 0x0040, 0x1c1a, 0x2091, 0x8001, 0x78e3,
-	0x0009, 0x007c, 0x6880, 0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049,
-	0x0004, 0x2051, 0x0010, 0x1078, 0x1963, 0x8738, 0xa784, 0x001f,
-	0x00c0, 0x1c23, 0x2091, 0x8001, 0x2001, 0x800a, 0x0078, 0x1c3a,
-	0x2001, 0x800c, 0x0078, 0x1c3a, 0x1078, 0x1a0e, 0x2001, 0x800d,
-	0x0078, 0x1c3a, 0x70c2, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091,
-	0x4080, 0x007c, 0x6004, 0x2c08, 0x2063, 0x0000, 0x7884, 0x8000,
-	0x7886, 0x7888, 0xa005, 0x798a, 0x0040, 0x1c51, 0x2c02, 0x0078,
-	0x1c52, 0x798e, 0x007c, 0x6807, 0x0103, 0x0c7e, 0x2061, 0x5000,
-	0x2d08, 0x206b, 0x0000, 0x6084, 0x8000, 0x6086, 0x6088, 0xa005,
-	0x618a, 0x0040, 0x1c66, 0x2d02, 0x0078, 0x1c67, 0x618e, 0x0c7f,
-	0x007c, 0x1078, 0x1c7a, 0x0040, 0x1c79, 0x0c7e, 0x609c, 0xa065,
-	0x0040, 0x1c74, 0x1078, 0x1996, 0x0c7f, 0x609f, 0x0000, 0x1078,
-	0x192b, 0x007c, 0x788c, 0xa065, 0x0040, 0x1c8c, 0x2091, 0x8000,
-	0x7884, 0x8001, 0x7886, 0x2c04, 0x788e, 0xa005, 0x00c0, 0x1c8a,
-	0x788a, 0x8000, 0x2091, 0x8001, 0x007c, 0x20a9, 0x0010, 0xa006,
-	0x8004, 0x8086, 0x818e, 0x00c8, 0x1c96, 0xa200, 0x0070, 0x1c9a,
-	0x0078, 0x1c91, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9, 0x0010,
-	0xa005, 0x0040, 0x1cc0, 0xa11a, 0x00c8, 0x1cc0, 0x8213, 0x818d,
-	0x0048, 0x1cb1, 0xa11a, 0x00c8, 0x1cb2, 0x0070, 0x1cb8, 0x0078,
-	0x1ca6, 0xa11a, 0x2308, 0x8210, 0x0070, 0x1cb8, 0x0078, 0x1ca6,
-	0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, 0x007c,
-	0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x1cbc, 0x7994, 0x70d0,
-	0xa106, 0x0040, 0x1d34, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004,
-	0xa005, 0x00c0, 0x1d34, 0x7008, 0x7208, 0xa206, 0x00c0, 0x1d34,
-	0xa286, 0x0008, 0x00c0, 0x1d34, 0x2071, 0x0010, 0x1078, 0x1911,
-	0x0040, 0x1d34, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, 0xa184, 0xff00,
-	0x0040, 0x1d02, 0x2031, 0x0000, 0x810b, 0x86b5, 0x810b, 0x86b5,
-	0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5,
-	0x2100, 0xa210, 0x2600, 0xa319, 0xa4a1, 0x0000, 0xa5a9, 0x0000,
-	0x0078, 0x1d0c, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, 0x0000,
-	0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x2009, 0x0020, 0x1078, 0x190c,
-	0x2091, 0x8001, 0x0040, 0x1d2b, 0x1078, 0x192b, 0x78a8, 0x8000,
-	0x78aa, 0xa086, 0x0002, 0x00c0, 0x1d34, 0x2091, 0x8000, 0x78e3,
-	0x0002, 0x78ab, 0x0000, 0x78cc, 0xa085, 0x0003, 0x78ce, 0x2091,
-	0x8001, 0x0078, 0x1d34, 0x78ab, 0x0000, 0x1078, 0x208b, 0x6004,
-	0xa084, 0x000f, 0x0079, 0x1d39, 0x2071, 0x0010, 0x2091, 0x8001,
-	0x007c, 0x1d49, 0x1d6b, 0x1d91, 0x1d49, 0x1dae, 0x1d58, 0x1f0d,
-	0x1f28, 0x1d49, 0x1d65, 0x1d8b, 0x1df6, 0x1e63, 0x1eb3, 0x1ec5,
-	0x1f24, 0x2039, 0x0400, 0x78dc, 0xa705, 0x78de, 0x6008, 0xa705,
-	0x600a, 0x1078, 0x1fa6, 0x609c, 0x78da, 0x1078, 0x2073, 0x007c,
-	0x78dc, 0xa084, 0x0100, 0x0040, 0x1d5f, 0x0078, 0x1d49, 0x601c,
-	0xa085, 0x0080, 0x601e, 0x0078, 0x1d72, 0x1078, 0x1b36, 0x00c0,
-	0x1d49, 0x1078, 0x20a5, 0x78dc, 0xa084, 0x0100, 0x0040, 0x1d72,
-	0x0078, 0x1d49, 0x78df, 0x0000, 0x6004, 0x8007, 0xa084, 0x00ff,
-	0x78d2, 0x8001, 0x609f, 0x0000, 0x0040, 0x1d88, 0x1078, 0x1fa6,
-	0x0040, 0x1d88, 0x78dc, 0xa085, 0x0100, 0x78de, 0x0078, 0x1d8a,
-	0x1078, 0x1fca, 0x007c, 0x1078, 0x1b36, 0x00c0, 0x1d49, 0x1078,
-	0x20a1, 0x78dc, 0xa08c, 0x0e00, 0x00c0, 0x1d9a, 0xa084, 0x0100,
-	0x00c0, 0x1d9c, 0x0078, 0x1d49, 0x1078, 0x1fa6, 0x00c0, 0x1dad,
-	0x6104, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x1f63, 0xa186,
-	0x000f, 0x0040, 0x1f63, 0x1078, 0x1fca, 0x007c, 0x78dc, 0xa084,
-	0x0100, 0x0040, 0x1db5, 0x0078, 0x1d49, 0x78df, 0x0000, 0x6714,
-	0x2011, 0x0001, 0x20a9, 0x0001, 0x6018, 0xa084, 0x00ff, 0xa005,
-	0x0040, 0x1dd8, 0x2011, 0x0001, 0xa7bc, 0xff00, 0x20a9, 0x0020,
-	0xa08e, 0x0001, 0x0040, 0x1dd8, 0x2039, 0x0000, 0x2011, 0x0002,
-	0x20a9, 0x0100, 0xa08e, 0x0002, 0x0040, 0x1dd8, 0x0078, 0x1df3,
-	0x1078, 0x1956, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000,
-	0x6808, 0xa084, 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, 0x8001,
-	0x0070, 0x1dec, 0x0078, 0x1dda, 0x8211, 0x0040, 0x1df3, 0x20a9,
-	0x0100, 0x0078, 0x1dda, 0x1078, 0x192b, 0x007c, 0x2001, 0x5067,
-	0x2004, 0xa084, 0x8000, 0x0040, 0x1f8b, 0x6114, 0x1078, 0x20c2,
-	0x6900, 0xa184, 0x0001, 0x0040, 0x1e17, 0x6028, 0xa084, 0x00ff,
-	0x00c0, 0x1f83, 0x6800, 0xa084, 0x0001, 0x0040, 0x1f8b, 0x6803,
-	0x0000, 0x680b, 0x0000, 0x6807, 0x0000, 0x0078, 0x1f93, 0x2011,
-	0x0001, 0x6020, 0xa084, 0x4000, 0x0040, 0x1e20, 0xa295, 0x0002,
-	0x6020, 0xa084, 0x0100, 0x0040, 0x1e27, 0xa295, 0x0008, 0x601c,
-	0xa084, 0x0002, 0x0040, 0x1e2e, 0xa295, 0x0004, 0x602c, 0xa08c,
-	0x00ff, 0xa182, 0x0002, 0x0048, 0x1f8f, 0xa182, 0x001b, 0x00c8,
-	0x1f8f, 0x0040, 0x1f8f, 0x690e, 0x602c, 0x8007, 0xa08c, 0x00ff,
-	0xa182, 0x0002, 0x0048, 0x1f8f, 0xa182, 0x001b, 0x00c8, 0x1f8f,
-	0x0040, 0x1f8f, 0x6912, 0x6030, 0xa005, 0x00c0, 0x1e51, 0x2001,
-	0x001e, 0x8000, 0x6816, 0x6028, 0xa084, 0x00ff, 0x0040, 0x1f8b,
-	0x6806, 0x6028, 0x8007, 0xa084, 0x00ff, 0x0040, 0x1f8b, 0x680a,
-	0x6a02, 0x0078, 0x1f93, 0x2001, 0x5067, 0x2004, 0xa084, 0x8000,
-	0x0040, 0x1f8b, 0x6114, 0x1078, 0x20c2, 0x2091, 0x8000, 0x6a04,
-	0x6b08, 0x6418, 0xa484, 0x0003, 0x0040, 0x1e89, 0x6128, 0xa18c,
-	0x00ff, 0x8001, 0x00c0, 0x1e82, 0x2100, 0xa210, 0x0048, 0x1eaf,
-	0x0078, 0x1e89, 0x8001, 0x00c0, 0x1eaf, 0x2100, 0xa212, 0x0048,
-	0x1eaf, 0xa484, 0x000c, 0x0040, 0x1ea3, 0x6128, 0x810f, 0xa18c,
-	0x00ff, 0xa082, 0x0004, 0x00c0, 0x1e9b, 0x2100, 0xa318, 0x0048,
-	0x1eaf, 0x0078, 0x1ea3, 0xa082, 0x0004, 0x00c0, 0x1eaf, 0x2100,
-	0xa31a, 0x0048, 0x1eaf, 0x6030, 0xa005, 0x0040, 0x1ea9, 0x8000,
-	0x6816, 0x6a06, 0x6b0a, 0x2091, 0x8001, 0x0078, 0x1f93, 0x2091,
-	0x8001, 0x0078, 0x1f8f, 0x6114, 0x1078, 0x20c2, 0x2091, 0x8000,
-	0x6b08, 0x8318, 0x0048, 0x1ec1, 0x6b0a, 0x2091, 0x8001, 0x0078,
-	0x1fa2, 0x2091, 0x8001, 0x0078, 0x1f8f, 0x6024, 0x8007, 0xa084,
-	0x00ff, 0x0040, 0x1ee3, 0xa086, 0x0080, 0x00c0, 0x1f0b, 0x20a9,
-	0x0008, 0x2069, 0x7410, 0x2091, 0x8000, 0x6800, 0xa084, 0xfcff,
-	0x6802, 0xade8, 0x0008, 0x0070, 0x1edf, 0x0078, 0x1ed5, 0x2091,
-	0x8001, 0x0078, 0x1f93, 0x6028, 0xa015, 0x0040, 0x1f0b, 0x6114,
-	0x1078, 0x20c2, 0x0d7e, 0xade8, 0x0007, 0x2091, 0x8000, 0x6800,
-	0xa00d, 0x0040, 0x1f08, 0xa206, 0x0040, 0x1ef9, 0x2168, 0x0078,
-	0x1eef, 0x0c7e, 0x2160, 0x6000, 0x6802, 0x1078, 0x192b, 0x0c7f,
-	0x0d7f, 0x6808, 0x8000, 0x680a, 0x2091, 0x8001, 0x0078, 0x1fa2,
-	0x2091, 0x8001, 0x0d7f, 0x0078, 0x1f8b, 0x6114, 0x1078, 0x20c2,
-	0x6800, 0xa084, 0x0001, 0x0040, 0x1f7b, 0x2091, 0x8000, 0x6a04,
-	0x8210, 0x0048, 0x1f20, 0x6a06, 0x2091, 0x8001, 0x0078, 0x1fa2,
-	0x2091, 0x8001, 0x0078, 0x1f8f, 0x1078, 0x1b36, 0x00c0, 0x1d49,
-	0x6114, 0x1078, 0x20c2, 0x60be, 0x6900, 0xa184, 0x0008, 0x0040,
-	0x1f35, 0x6020, 0xa085, 0x0100, 0x6022, 0xa184, 0x0001, 0x0040,
-	0x1f8b, 0xa184, 0x0100, 0x00c0, 0x1f77, 0xa184, 0x0200, 0x00c0,
-	0x1f73, 0x681c, 0xa005, 0x00c0, 0x1f7f, 0x6004, 0xa084, 0x00ff,
-	0xa086, 0x000f, 0x00c0, 0x1f4e, 0x1078, 0x20a5, 0x78df, 0x0000,
-	0x6004, 0x8007, 0xa084, 0x00ff, 0x78d2, 0x8001, 0x609f, 0x0000,
-	0x0040, 0x1f63, 0x1078, 0x1fa6, 0x0040, 0x1f63, 0x78dc, 0xa085,
-	0x0100, 0x78de, 0x007c, 0x78d7, 0x0000, 0x78db, 0x0000, 0x6024,
-	0xa084, 0xff00, 0x6026, 0x1078, 0x39aa, 0x0040, 0x1cc6, 0x1078,
-	0x1b5b, 0x0078, 0x1cc6, 0x2009, 0x0017, 0x0078, 0x1f95, 0x2009,
-	0x000e, 0x0078, 0x1f95, 0x2009, 0x0007, 0x0078, 0x1f95, 0x2009,
-	0x0035, 0x0078, 0x1f95, 0x2009, 0x003e, 0x0078, 0x1f95, 0x2009,
-	0x0004, 0x0078, 0x1f95, 0x2009, 0x0006, 0x0078, 0x1f95, 0x2009,
-	0x0016, 0x0078, 0x1f95, 0x2009, 0x0001, 0x6024, 0xa084, 0xff00,
-	0xa105, 0x6026, 0x2091, 0x8000, 0x1078, 0x1c42, 0x2091, 0x8001,
-	0x0078, 0x1cc6, 0x1078, 0x192b, 0x0078, 0x1cc6, 0x78d4, 0xa06d,
-	0x00c0, 0x1fb1, 0x2c00, 0x78d6, 0x78da, 0x609f, 0x0000, 0x0078,
-	0x1fbd, 0x2c00, 0x689e, 0x609f, 0x0000, 0x78d6, 0x2d00, 0x6002,
-	0x78d8, 0xad06, 0x00c0, 0x1fbd, 0x6002, 0x78d0, 0x8001, 0x78d2,
-	0x00c0, 0x1fc9, 0x78dc, 0xa084, 0xfeff, 0x78de, 0x78d8, 0x2060,
-	0xa006, 0x007c, 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184, 0xe1ff,
-	0x601e, 0xa184, 0x0060, 0x0040, 0x1fd9, 0x0e7e, 0x1078, 0x467f,
-	0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3,
-	0x0000, 0x6714, 0x1078, 0x1956, 0x2091, 0x8000, 0x60a0, 0xa084,
-	0x8000, 0x00c0, 0x2000, 0x6808, 0xa084, 0x0001, 0x0040, 0x2000,
-	0x2091, 0x8001, 0x1078, 0x19a3, 0x2091, 0x8000, 0x1078, 0x1c42,
-	0x2091, 0x8001, 0x78d7, 0x0000, 0x78db, 0x0000, 0x0078, 0x2072,
-	0x6024, 0xa096, 0x0001, 0x00c0, 0x2007, 0x8000, 0x6026, 0x6a10,
-	0x6814, 0x2091, 0x8001, 0xa202, 0x0048, 0x2016, 0x0040, 0x2016,
-	0x2039, 0x0200, 0x1078, 0x2073, 0x0078, 0x2072, 0x2c08, 0x2091,
-	0x8000, 0x60a0, 0xa084, 0x8000, 0x0040, 0x2043, 0x6800, 0xa065,
-	0x0040, 0x2048, 0x6a04, 0x0e7e, 0x2071, 0x5040, 0x7000, 0xa084,
-	0x0001, 0x0040, 0x203d, 0x7048, 0xa206, 0x00c0, 0x203d, 0x6b04,
-	0x231c, 0x2160, 0x6302, 0x2300, 0xa005, 0x00c0, 0x2038, 0x6902,
-	0x2260, 0x6102, 0x0e7f, 0x0078, 0x204f, 0x2160, 0x6202, 0x6906,
-	0x0e7f, 0x0078, 0x204f, 0x6800, 0xa065, 0x0040, 0x2048, 0x6102,
-	0x6902, 0x00c0, 0x204c, 0x6906, 0x2160, 0x6003, 0x0000, 0x2160,
-	0x60a0, 0xa084, 0x8000, 0x0040, 0x2059, 0x6808, 0xa084, 0xfffc,
-	0x680a, 0x6810, 0x8000, 0x6812, 0x2091, 0x8001, 0x6808, 0xa08c,
-	0x0040, 0x0040, 0x2068, 0xa086, 0x0040, 0x680a, 0x1078, 0x19b4,
-	0x2091, 0x8000, 0x1078, 0x21b1, 0x2091, 0x8001, 0x78db, 0x0000,
-	0x78d7, 0x0000, 0x007c, 0x6008, 0xa705, 0x600a, 0x2091, 0x8000,
-	0x1078, 0x1c42, 0x2091, 0x8001, 0x78d8, 0xa065, 0x0040, 0x2086,
-	0x609c, 0x78da, 0x609f, 0x0000, 0x0078, 0x2076, 0x78d7, 0x0000,
-	0x78db, 0x0000, 0x007c, 0x7990, 0x7894, 0x8000, 0xa10a, 0x00c8,
-	0x2092, 0xa006, 0x7896, 0x70d2, 0x7804, 0xa005, 0x0040, 0x20a0,
-	0x8001, 0x7806, 0x00c0, 0x20a0, 0x0068, 0x20a0, 0x2091, 0x4080,
-	0x007c, 0x2039, 0x20b9, 0x0078, 0x20a7, 0x2039, 0x20bf, 0x2704,
-	0xa005, 0x0040, 0x20b8, 0xac00, 0x2068, 0x6b08, 0x6c0c, 0x6910,
-	0x6a14, 0x690a, 0x6a0e, 0x6b12, 0x6c16, 0x8738, 0x0078, 0x20a7,
-	0x007c, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015,
-	0x001b, 0x0000, 0x0c7e, 0x1078, 0x3b33, 0x2c68, 0x0c7f, 0x007c,
-	0x0010, 0x2139, 0x0068, 0x2139, 0x2029, 0x0000, 0x78cb, 0x0000,
-	0x788c, 0xa065, 0x0040, 0x2132, 0x2009, 0x5074, 0x2104, 0xa084,
-	0x0001, 0x0040, 0x2100, 0x6004, 0xa086, 0x0103, 0x00c0, 0x2100,
-	0x6018, 0xa005, 0x00c0, 0x2100, 0x6014, 0xa005, 0x00c0, 0x2100,
-	0x0d7e, 0x2069, 0x0000, 0x6818, 0xa084, 0x0001, 0x00c0, 0x20ff,
-	0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001,
-	0x2091, 0x4080, 0x0d7f, 0x1078, 0x1c69, 0x0078, 0x2137, 0x0d7f,
-	0x1078, 0x213a, 0x0040, 0x2132, 0x6204, 0xa294, 0x00ff, 0xa296,
-	0x0003, 0x0040, 0x2112, 0x6204, 0xa296, 0x0110, 0x00c0, 0x2120,
-	0x78cb, 0x0001, 0x6204, 0xa294, 0xff00, 0x8217, 0x8211, 0x0040,
-	0x2120, 0x85ff, 0x00c0, 0x2132, 0x8210, 0xa202, 0x00c8, 0x2132,
-	0x057e, 0x1078, 0x2149, 0x057f, 0x0040, 0x212d, 0x78e0, 0xa086,
-	0x0003, 0x0040, 0x2132, 0x0078, 0x2120, 0x8528, 0x78c8, 0xa005,
-	0x0040, 0x20d0, 0x85ff, 0x0040, 0x2139, 0x2091, 0x4080, 0x78b0,
-	0x70d6, 0x007c, 0x7bac, 0x79b0, 0x70d4, 0xa102, 0x00c0, 0x2143,
-	0x2300, 0xa005, 0x007c, 0x0048, 0x2147, 0xa302, 0x007c, 0x8002,
-	0x007c, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x2163,
-	0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x2198,
-	0x7008, 0x7208, 0xa206, 0x00c0, 0x2198, 0xa286, 0x0008, 0x00c0,
-	0x2198, 0x2071, 0x0010, 0x1078, 0x219d, 0x2009, 0x0020, 0x6004,
-	0xa086, 0x0103, 0x00c0, 0x2172, 0x6028, 0xa005, 0x00c0, 0x2172,
-	0x2009, 0x000c, 0x1078, 0x1907, 0x0040, 0x218b, 0x78c4, 0x8000,
-	0x78c6, 0xa086, 0x0002, 0x00c0, 0x2198, 0x2091, 0x8000, 0x78e3,
-	0x0003, 0x78c7, 0x0000, 0x78cc, 0xa085, 0x0300, 0x78ce, 0x2091,
-	0x8001, 0x0078, 0x2198, 0x78c7, 0x0000, 0x1078, 0x1c69, 0x79ac,
-	0x78b0, 0x8000, 0xa10a, 0x00c8, 0x2196, 0xa006, 0x78b2, 0xa006,
-	0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x8107, 0x8004, 0x8004,
-	0x7ab8, 0x7bb4, 0x7cc0, 0x7dbc, 0xa210, 0xa399, 0x0000, 0xa4a1,
-	0x0000, 0xa5a9, 0x0000, 0x007c, 0x2009, 0x505b, 0x2091, 0x8000,
-	0x200a, 0x0f7e, 0x0e7e, 0x2071, 0x5040, 0x7000, 0xa086, 0x0000,
-	0x00c0, 0x21cb, 0x2009, 0x5012, 0x2104, 0xa005, 0x00c0, 0x21cb,
-	0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x21cb, 0x0018,
-	0x21cb, 0x781b, 0x004b, 0x0e7f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e,
-	0x2071, 0x5040, 0x2091, 0x8000, 0x7000, 0xa086, 0x0000, 0x00c0,
-	0x21e4, 0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x21e4,
-	0x0018, 0x21e4, 0x781b, 0x004d, 0x2091, 0x8001, 0x0e7f, 0x0f7f,
-	0x007c, 0x127e, 0x2091, 0x2300, 0x2071, 0x5040, 0x2079, 0x0100,
-	0x784b, 0x000f, 0x0098, 0x21f7, 0x7838, 0x0078, 0x21f0, 0x20a9,
-	0x0040, 0x7800, 0xa082, 0x0004, 0x0048, 0x2200, 0x20a9, 0x0060,
-	0x789b, 0x0000, 0x78af, 0x0000, 0x78af, 0x0000, 0x0070, 0x220a,
-	0x0078, 0x2202, 0x7800, 0xa082, 0x0004, 0x0048, 0x2219, 0x70b7,
-	0x009b, 0x2019, 0x4da4, 0x1078, 0x2255, 0x702f, 0x8001, 0x0078,
-	0x2225, 0x70b7, 0x0000, 0x2019, 0x4c1c, 0x1078, 0x2255, 0x2019,
-	0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, 0x7003, 0x0000, 0x1078,
-	0x235e, 0x7004, 0xa084, 0x000f, 0x017e, 0x2009, 0x04fd, 0x210c,
-	0xa18a, 0x0005, 0x0048, 0x223a, 0x0038, 0x2240, 0xa085, 0x6280,
-	0x0078, 0x2242, 0x0028, 0x2240, 0xa085, 0x6280, 0x0078, 0x2242,
-	0xa085, 0x62c0, 0x017f, 0x7806, 0x780f, 0xb204, 0x7843, 0x00d8,
-	0x7853, 0x0080, 0x780b, 0x0008, 0x7047, 0x0008, 0x7053, 0x507f,
-	0x704f, 0x0000, 0x127f, 0x2000, 0x007c, 0x137e, 0x147e, 0x157e,
-	0x047e, 0x20a1, 0x012b, 0x2304, 0xa005, 0x789a, 0x0040, 0x2275,
-	0x8318, 0x2324, 0x8318, 0x2398, 0x24a8, 0xa484, 0xff00, 0x0040,
-	0x226d, 0xa482, 0x0100, 0x20a9, 0x0100, 0x2020, 0x53a6, 0xa005,
-	0x00c0, 0x2264, 0x3318, 0x0078, 0x225b, 0x047f, 0x157f, 0x147f,
-	0x137f, 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204, 0xa084,
-	0xfff0, 0xa105, 0x2012, 0x1078, 0x235e, 0x007c, 0x2011, 0x0101,
-	0x20a9, 0x0009, 0x810b, 0x0070, 0x228f, 0x0078, 0x228a, 0xa18c,
-	0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2009,
-	0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, 0x22a0, 0x0078, 0x229b,
-	0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x007c,
-	0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070, 0x22b1, 0x0078,
-	0x22ac, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012,
-	0x007c, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012,
-	0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100,
-	0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080,
-	0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084, 0xffdf,
-	0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e,
-	0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f,
-	0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100,
-	0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f,
-	0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040,
-	0x233c, 0x2061, 0x7400, 0x1078, 0x2344, 0x0040, 0x2328, 0x20a9,
-	0x0000, 0x2061, 0x7300, 0x0c7e, 0x1078, 0x2344, 0x0040, 0x2318,
-	0x0c7f, 0x8c60, 0x0070, 0x2316, 0x0078, 0x230b, 0x0078, 0x233c,
-	0x007f, 0xa082, 0x7300, 0x2071, 0x5040, 0x7086, 0x7182, 0x2001,
-	0x0004, 0x706e, 0x7093, 0x000f, 0x1078, 0x21ac, 0x0078, 0x2338,
-	0x60c0, 0xa005, 0x00c0, 0x233c, 0x2071, 0x5040, 0x7182, 0x2c00,
-	0x708a, 0x2001, 0x0006, 0x706e, 0x7093, 0x000f, 0x1078, 0x21ac,
-	0x2001, 0x0000, 0x0078, 0x233e, 0x2001, 0x0001, 0x2091, 0x8001,
-	0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, 0x0040, 0x235b,
-	0x2060, 0x600c, 0xa306, 0x00c0, 0x2358, 0x6010, 0xa206, 0x00c0,
-	0x2358, 0x6014, 0xa106, 0x00c0, 0x2358, 0xa006, 0x0078, 0x235d,
-	0x6000, 0x0078, 0x2345, 0xa085, 0x0001, 0x007c, 0x2011, 0x5041,
-	0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, 0xa084, 0x0100,
-	0x0040, 0x2374, 0x2021, 0xff04, 0x2122, 0x810b, 0x810b, 0x810b,
-	0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, 0x68e4, 0xa08c,
-	0x0020, 0x0040, 0x23c8, 0xa084, 0x0006, 0x00c0, 0x23c8, 0x6014,
-	0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0, 0x5280,
-	0x7004, 0xa084, 0x000a, 0x00c0, 0x23c8, 0x7108, 0xa194, 0xff00,
-	0x0040, 0x23c8, 0xa18c, 0x00ff, 0x2001, 0x000c, 0xa106, 0x0040,
-	0x23af, 0x2001, 0x0012, 0xa106, 0x0040, 0x23b3, 0x2001, 0x0014,
-	0xa106, 0x0040, 0x23b7, 0x2001, 0x0019, 0xa106, 0x0040, 0x23bb,
-	0x2001, 0x0032, 0xa106, 0x0040, 0x23bf, 0x0078, 0x23c3, 0x2009,
-	0x0012, 0x0078, 0x23c5, 0x2009, 0x0014, 0x0078, 0x23c5, 0x2009,
-	0x0019, 0x0078, 0x23c5, 0x2009, 0x0020, 0x0078, 0x23c5, 0x2009,
-	0x003f, 0x0078, 0x23c5, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a,
-	0x0e7f, 0x007c, 0x0068, 0x23ca, 0x2091, 0x8000, 0x2071, 0x0000,
-	0x007e, 0x7018, 0xa084, 0x0001, 0x00c0, 0x23d1, 0x007f, 0x2071,
-	0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x073f,
-	0x70df, 0x0000, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080,
-	0x0078, 0x23e8, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300, 0x7f3c,
-	0x7e58, 0x7c30, 0x7d38, 0x77c2, 0x74c6, 0x76ca, 0x75ce, 0xa594,
-	0x003f, 0xa49c, 0x0003, 0xa484, 0x000f, 0x0079, 0x23ff, 0x2411,
-	0x2411, 0x2411, 0x274b, 0x3907, 0x240f, 0x2440, 0x244a, 0x240f,
-	0x240f, 0x240f, 0x240f, 0x240f, 0x240f, 0x240f, 0x240f, 0x1078,
-	0x23ca, 0x8507, 0xa084, 0x001f, 0x0079, 0x2416, 0x2454, 0x274b,
-	0x2905, 0x2a02, 0x2a2a, 0x2cc3, 0x2f6e, 0x2fb1, 0x2ffc, 0x3081,
-	0x3139, 0x31e2, 0x2440, 0x2827, 0x2f43, 0x2436, 0x3c78, 0x3c98,
-	0x3e5e, 0x3e6a, 0x3f3f, 0x2436, 0x2436, 0x4012, 0x4016, 0x3c76,
-	0x2436, 0x3dc9, 0x2436, 0x3b56, 0x244a, 0x2436, 0x1078, 0x23ca,
-	0x0018, 0x23ef, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c,
-	0x2019, 0x4cfd, 0x1078, 0x2255, 0x702f, 0x0001, 0x781b, 0x004f,
-	0x0078, 0x2438, 0x2019, 0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000,
-	0x781b, 0x00d5, 0x0078, 0x2438, 0x7242, 0x2009, 0x500f, 0x200b,
-	0x0000, 0xa584, 0x0001, 0x00c0, 0x3b6a, 0x0040, 0x2471, 0x1078,
-	0x23ca, 0x7003, 0x0000, 0x704b, 0x0000, 0x7043, 0x0000, 0x7037,
-	0x0000, 0x1078, 0x38de, 0x0018, 0x23ef, 0x2009, 0x500f, 0x200b,
-	0x0000, 0x7068, 0xa005, 0x00c0, 0x253c, 0x706c, 0xa084, 0x0007,
-	0x0079, 0x247a, 0x2573, 0x2482, 0x248e, 0x24ab, 0x24cd, 0x251a,
-	0x24f3, 0x2482, 0x1078, 0x38c6, 0x2009, 0x0048, 0x1078, 0x2e0f,
-	0x00c0, 0x248c, 0x7003, 0x0004, 0x0078, 0x2438, 0x1078, 0x38c6,
-	0x00c0, 0x24a9, 0x7080, 0x8007, 0x7882, 0x789b, 0x0010, 0x78ab,
-	0x000c, 0x789b, 0x0060, 0x78ab, 0x0001, 0x785b, 0x0004, 0x2009,
-	0x00e5, 0x1078, 0x2e03, 0x00c0, 0x24a9, 0x7003, 0x0004, 0x7093,
-	0x000f, 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, 0x24cb, 0x7180,
-	0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d, 0x00c0,
-	0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b,
-	0x0004, 0x2009, 0x00e5, 0x1078, 0x2e03, 0x00c0, 0x24cb, 0x7003,
-	0x0004, 0x7093, 0x000f, 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0,
-	0x24f1, 0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f,
-	0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x7184, 0x79aa, 0x78ab,
-	0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009,
-	0x00e5, 0x1078, 0x2e03, 0x00c0, 0x24f1, 0x7003, 0x0004, 0x7093,
-	0x000f, 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, 0x2518, 0x7180,
-	0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d, 0x00c0,
-	0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b,
-	0x0004, 0x2009, 0x00e5, 0x1078, 0x2e03, 0x00c0, 0x2518, 0x7088,
-	0x708b, 0x0000, 0x2068, 0x704a, 0x7003, 0x0002, 0x7093, 0x000f,
-	0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, 0x2438, 0x7088, 0x2068,
-	0x6f14, 0x1078, 0x37bd, 0x2c50, 0x1078, 0x3978, 0x789b, 0x0010,
-	0x6814, 0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, 0x6e1c, 0x2041,
-	0x0001, 0x708c, 0xa084, 0x0400, 0x2001, 0x0004, 0x0040, 0x253a,
-	0x2001, 0x0006, 0x0078, 0x265b, 0x1078, 0x38c6, 0x00c0, 0x2438,
-	0x789b, 0x0010, 0x7068, 0x2068, 0x6f14, 0x1078, 0x37bd, 0x2c50,
-	0x1078, 0x3978, 0x6008, 0xa085, 0x0010, 0x600a, 0x6824, 0xa005,
-	0x0040, 0x255a, 0xa082, 0x0006, 0x0048, 0x2558, 0x0078, 0x255a,
-	0x6827, 0x0005, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0x7058,
-	0xa084, 0x8000, 0x0040, 0x2568, 0xa684, 0x0001, 0x0040, 0x256a,
-	0xa39c, 0xffbf, 0x7baa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001,
-	0x0003, 0x0078, 0x265b, 0x0018, 0x23ef, 0x744c, 0xa485, 0x0000,
-	0x0040, 0x258d, 0xa080, 0x5080, 0x2030, 0x7150, 0x8108, 0xa12a,
-	0x0048, 0x2584, 0x2009, 0x5080, 0x2164, 0x6504, 0x85ff, 0x00c0,
-	0x259e, 0x8421, 0x00c0, 0x257e, 0x7152, 0x7003, 0x0000, 0x704b,
-	0x0000, 0x7040, 0xa005, 0x0040, 0x3b6a, 0x0078, 0x2438, 0x764c,
-	0xa6b0, 0x5080, 0x7150, 0x2600, 0x0078, 0x2589, 0x7152, 0x2568,
-	0x2558, 0x754a, 0x2c50, 0x6034, 0xa085, 0x0000, 0x00c0, 0x259b,
-	0x6708, 0x773a, 0xa784, 0x033f, 0x0040, 0x25d4, 0xa784, 0x0021,
-	0x00c0, 0x259b, 0xa784, 0x0002, 0x0040, 0x25bd, 0xa784, 0x0004,
-	0x0040, 0x259b, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008, 0x00c0,
-	0x259b, 0xa784, 0x0010, 0x00c0, 0x259b, 0xa784, 0x0200, 0x00c0,
-	0x259b, 0xa784, 0x0100, 0x0040, 0x25d4, 0x6018, 0xa005, 0x00c0,
-	0x259b, 0xa7bc, 0xfeff, 0x670a, 0x6823, 0x0000, 0x6e1c, 0xa684,
-	0x000e, 0x6118, 0x0040, 0x25e4, 0x601c, 0xa102, 0x0048, 0x25e7,
-	0x0040, 0x25e7, 0x0078, 0x2597, 0x81ff, 0x00c0, 0x2597, 0x68c3,
-	0x0000, 0xa784, 0x0080, 0x00c0, 0x25ef, 0x700c, 0x6022, 0xa7bc,
-	0xff7f, 0x670a, 0x1078, 0x3978, 0x0018, 0x23ef, 0x789b, 0x0010,
-	0xa046, 0x1078, 0x38c6, 0x00c0, 0x2438, 0x6b14, 0xa39c, 0x001f,
-	0xa39d, 0x00c0, 0x7058, 0xa084, 0x8000, 0x0040, 0x260b, 0xa684,
-	0x0001, 0x0040, 0x260d, 0xa39c, 0xffbf, 0xa684, 0x0010, 0x0040,
-	0x2613, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e, 0x00c0,
-	0x261e, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x2659, 0x7158, 0xa18c,
-	0x0800, 0x0040, 0x33d7, 0x2011, 0x0020, 0xa684, 0x0008, 0x00c0,
-	0x262f, 0x8210, 0xa684, 0x0002, 0x00c0, 0x262f, 0x8210, 0x7aaa,
-	0x8840, 0x1078, 0x38de, 0x6a14, 0x610c, 0x8108, 0xa18c, 0x00ff,
-	0xa1e0, 0x7300, 0x2c64, 0x8cff, 0x0040, 0x2650, 0x6014, 0xa206,
-	0x00c0, 0x263a, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x2635, 0x0c7e,
-	0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078, 0x2573,
-	0x1078, 0x38c6, 0x00c0, 0x2438, 0x2a60, 0x610e, 0x79aa, 0x8840,
-	0x7132, 0x2001, 0x0001, 0x007e, 0x715c, 0xa184, 0x0018, 0x0040,
-	0x2676, 0xa184, 0x0010, 0x0040, 0x2669, 0x1078, 0x35d6, 0x00c0,
-	0x2699, 0xa184, 0x0008, 0x0040, 0x2676, 0x69a0, 0xa184, 0x0600,
-	0x00c0, 0x2676, 0x1078, 0x34c7, 0x0078, 0x2699, 0x69a0, 0xa184,
-	0x0800, 0x0040, 0x268d, 0x0c7e, 0x027e, 0x2960, 0x6000, 0xa085,
-	0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, 0x6106, 0x027f, 0x0c7f,
-	0x1078, 0x35d6, 0x00c0, 0x2699, 0x69a0, 0xa184, 0x0200, 0x0040,
-	0x2695, 0x1078, 0x3516, 0x0078, 0x2699, 0xa184, 0x0400, 0x00c0,
-	0x2672, 0x69a0, 0xa184, 0x1000, 0x0040, 0x26a4, 0x6914, 0xa18c,
-	0xff00, 0x810f, 0x1078, 0x22cd, 0x007f, 0x7002, 0xa68c, 0x00e0,
-	0xa684, 0x0060, 0x0040, 0x26b2, 0xa086, 0x0060, 0x00c0, 0x26b2,
-	0xa18d, 0x4000, 0x88ff, 0x0040, 0x26b7, 0xa18d, 0x0004, 0x795a,
-	0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, 0x0061, 0x6818,
-	0xa08d, 0x8000, 0xa084, 0x7fff, 0x691a, 0xa68c, 0x0080, 0x0040,
-	0x26d6, 0x7097, 0x0000, 0xa08a, 0x000d, 0x0050, 0x26d4, 0xa08a,
-	0x000c, 0x7196, 0x2001, 0x000c, 0x800c, 0x719a, 0x78aa, 0x8008,
-	0x810c, 0x0040, 0x33dd, 0xa18c, 0x00f8, 0x00c0, 0x33dd, 0x157e,
-	0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac,
-	0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814,
-	0x8007, 0x7882, 0x6d94, 0x7dd6, 0x7dde, 0x6e98, 0x7ed2, 0x7eda,
-	0x1078, 0x38c6, 0x00c0, 0x270d, 0x702c, 0x8003, 0x0048, 0x2706,
-	0x2019, 0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, 0x7830, 0xa084,
-	0x00c0, 0x00c0, 0x270d, 0x0098, 0x2715, 0x6008, 0xa084, 0xffef,
-	0x600a, 0x1078, 0x38de, 0x0078, 0x2461, 0x7200, 0xa284, 0x0007,
-	0xa086, 0x0001, 0x00c0, 0x2722, 0x781b, 0x004f, 0x1078, 0x38de,
-	0x0078, 0x2733, 0x6ab4, 0xa295, 0x2000, 0x7a5a, 0x781b, 0x004f,
-	0x1078, 0x38de, 0x7200, 0x2500, 0xa605, 0x0040, 0x2733, 0xa284,
-	0x0007, 0x1079, 0x2741, 0xad80, 0x0009, 0x7036, 0xa284, 0x0007,
-	0xa086, 0x0001, 0x00c0, 0x2438, 0x6018, 0x8000, 0x601a, 0x0078,
-	0x2438, 0x2749, 0x48f7, 0x48f7, 0x48e6, 0x48f7, 0x2749, 0x48e6,
-	0x2749, 0x1078, 0x23ca, 0x1078, 0x38c6, 0x0f7e, 0x2079, 0x5000,
-	0x78cc, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x276f, 0x706c, 0xa086,
-	0x0001, 0x00c0, 0x275e, 0x706e, 0x0078, 0x2802, 0x706c, 0xa086,
-	0x0005, 0x00c0, 0x276d, 0x7088, 0x2068, 0x681b, 0x0004, 0x6817,
-	0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x706f, 0x0000, 0x2011,
-	0x0004, 0x716c, 0xa186, 0x0001, 0x0040, 0x2790, 0xa186, 0x0007,
-	0x00c0, 0x2780, 0x2009, 0x5038, 0x200b, 0x0005, 0x0078, 0x2790,
-	0x2009, 0x5013, 0x2104, 0x2009, 0x5012, 0x200a, 0x2009, 0x5038,
-	0x200b, 0x0001, 0x706f, 0x0000, 0x7073, 0x0001, 0x0078, 0x2792,
-	0x706f, 0x0000, 0x1078, 0x4633, 0x157e, 0x20a9, 0x0010, 0x2039,
-	0x0000, 0x1078, 0x36b0, 0xa7b8, 0x0100, 0x0070, 0x27a1, 0x0078,
-	0x2799, 0x157f, 0x7000, 0x0079, 0x27a5, 0x27d3, 0x27ba, 0x27ba,
-	0x27ad, 0x27d3, 0x27d3, 0x27d3, 0x27d3, 0x2021, 0x505a, 0x2404,
-	0xa005, 0x0040, 0x27d3, 0xad06, 0x00c0, 0x27ba, 0x6800, 0x2022,
-	0x0078, 0x27ca, 0x6820, 0xa084, 0x0001, 0x00c0, 0x27c6, 0x6f14,
-	0x1078, 0x37bd, 0x1078, 0x33ae, 0x0078, 0x27ca, 0x7060, 0x2060,
-	0x6800, 0x6002, 0x6a1a, 0x6817, 0x0000, 0x6820, 0xa085, 0x0008,
-	0x6822, 0x1078, 0x1c53, 0x2021, 0x7400, 0x1078, 0x280f, 0x2021,
-	0x505a, 0x1078, 0x280f, 0x157e, 0x20a9, 0x0000, 0x2021, 0x7300,
-	0x1078, 0x280f, 0x8420, 0x0070, 0x27e7, 0x0078, 0x27e0, 0x2061,
-	0x5300, 0x2021, 0x0002, 0x20a9, 0x0100, 0x6018, 0x6110, 0x81ff,
-	0x0040, 0x27f6, 0xa102, 0x0050, 0x27f6, 0x6012, 0x601b, 0x0000,
-	0xace0, 0x0010, 0x0070, 0x27fe, 0x0078, 0x27ed, 0x8421, 0x00c0,
-	0x27eb, 0x157f, 0x709c, 0xa084, 0x8000, 0x0040, 0x2809, 0x1078,
-	0x39cc, 0x7003, 0x0000, 0x704b, 0x0000, 0x0078, 0x2438, 0x047e,
-	0x2404, 0xa005, 0x0040, 0x2823, 0x2068, 0x6800, 0x007e, 0x6a1a,
-	0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, 0x1c53,
-	0x007f, 0x0078, 0x2811, 0x047f, 0x2023, 0x0000, 0x007c, 0xa282,
-	0x0003, 0x0050, 0x282d, 0x1078, 0x23ca, 0x2300, 0x0079, 0x2830,
-	0x2833, 0x28a6, 0x28c3, 0xa282, 0x0002, 0x0040, 0x2839, 0x1078,
-	0x23ca, 0x706c, 0x706f, 0x0000, 0x7093, 0x0000, 0x0079, 0x2840,
-	0x2848, 0x2848, 0x284a, 0x287e, 0x33e3, 0x2848, 0x287e, 0x2848,
-	0x1078, 0x23ca, 0x7780, 0x1078, 0x36b0, 0x7780, 0xa7bc, 0x0f00,
-	0x1078, 0x37bd, 0x6018, 0xa005, 0x0040, 0x2875, 0x2021, 0x7400,
-	0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x28de, 0x0040, 0x2875,
-	0x157e, 0x20a9, 0x0000, 0x2021, 0x7300, 0x047e, 0x2009, 0x0004,
-	0x2011, 0x0010, 0x1078, 0x28de, 0x047f, 0x0040, 0x2874, 0x8420,
-	0x0070, 0x2874, 0x0078, 0x2865, 0x157f, 0x8738, 0xa784, 0x001f,
-	0x00c0, 0x2850, 0x0078, 0x2461, 0x0078, 0x2461, 0x7780, 0x1078,
-	0x37bd, 0x6018, 0xa005, 0x0040, 0x28a4, 0x2021, 0x7400, 0x2009,
-	0x0005, 0x2011, 0x0020, 0x1078, 0x28de, 0x0040, 0x28a4, 0x157e,
-	0x20a9, 0x0000, 0x2021, 0x7300, 0x047e, 0x2009, 0x0005, 0x2011,
-	0x0020, 0x1078, 0x28de, 0x047f, 0x0040, 0x28a3, 0x8420, 0x0070,
-	0x28a3, 0x0078, 0x2894, 0x157f, 0x0078, 0x2461, 0x2200, 0x0079,
-	0x28a9, 0x28ac, 0x28ae, 0x28ae, 0x1078, 0x23ca, 0x2009, 0x0012,
-	0x706c, 0xa086, 0x0002, 0x0040, 0x28b7, 0x2009, 0x000e, 0x6818,
-	0xa084, 0x8000, 0x0040, 0x28bd, 0x691a, 0x706f, 0x0000, 0x7073,
-	0x0001, 0x0078, 0x3854, 0x2200, 0x0079, 0x28c6, 0x28cb, 0x28ae,
-	0x28c9, 0x1078, 0x23ca, 0x1078, 0x4633, 0x7000, 0xa086, 0x0001,
-	0x00c0, 0x3373, 0x1078, 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a,
-	0x1078, 0x3366, 0x0040, 0x3373, 0x0078, 0x2573, 0x2404, 0xa005,
-	0x0040, 0x2901, 0x2068, 0x2d04, 0x007e, 0x6814, 0xa706, 0x0040,
-	0x28ed, 0x2d20, 0x007f, 0x0078, 0x28df, 0x007f, 0x2022, 0x691a,
-	0x6817, 0x0000, 0x6820, 0xa205, 0x6822, 0x1078, 0x1c53, 0x6010,
-	0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x33c4,
-	0x007c, 0xa085, 0x0001, 0x0078, 0x2900, 0x2300, 0x0079, 0x2908,
-	0x290d, 0x290b, 0x29a6, 0x1078, 0x23ca, 0x78ec, 0xa084, 0x0001,
-	0x00c0, 0x2921, 0x7000, 0xa086, 0x0004, 0x00c0, 0x2919, 0x0078,
-	0x2944, 0x1078, 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, 0x0078,
-	0x3373, 0x78e4, 0xa005, 0x00d0, 0x2944, 0x0018, 0x2438, 0x2008,
-	0xa084, 0x0030, 0x00c0, 0x2930, 0x781b, 0x004f, 0x0078, 0x2438,
-	0x78ec, 0xa084, 0x0003, 0x0040, 0x292c, 0x2100, 0xa084, 0x0007,
-	0x0079, 0x293a, 0x297d, 0x2988, 0x296e, 0x2942, 0x38b9, 0x38b9,
-	0x2942, 0x2997, 0x1078, 0x23ca, 0x7000, 0xa086, 0x0004, 0x00c0,
-	0x295e, 0x706c, 0xa086, 0x0002, 0x00c0, 0x2954, 0x2011, 0x0002,
-	0x2019, 0x0000, 0x0078, 0x2827, 0x706c, 0xa086, 0x0006, 0x0040,
-	0x294e, 0x706c, 0xa086, 0x0004, 0x0040, 0x294e, 0x79e4, 0xa184,
-	0x0030, 0x0040, 0x2968, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x296a,
-	0x0078, 0x2f43, 0x2001, 0x0003, 0x0078, 0x2cd7, 0x6818, 0xa084,
-	0x8000, 0x0040, 0x2975, 0x681b, 0x001d, 0x1078, 0x368f, 0x782b,
-	0x3008, 0x781b, 0x0056, 0x0078, 0x2438, 0x6818, 0xa084, 0x8000,
-	0x0040, 0x2984, 0x681b, 0x001d, 0x1078, 0x368f, 0x0078, 0x3884,
-	0x6818, 0xa084, 0x8000, 0x0040, 0x298f, 0x681b, 0x001d, 0x1078,
-	0x368f, 0x782b, 0x3008, 0x781b, 0x00d2, 0x0078, 0x2438, 0x6818,
-	0xa084, 0x8000, 0x0040, 0x299e, 0x681b, 0x001d, 0x1078, 0x368f,
-	0x782b, 0x3008, 0x781b, 0x0093, 0x0078, 0x2438, 0xa584, 0x000f,
-	0x00c0, 0x29c3, 0x7000, 0x0079, 0x29ad, 0x2461, 0x29b7, 0x29b5,
-	0x3373, 0x3373, 0x3373, 0x3373, 0x29b5, 0x1078, 0x23ca, 0x1078,
-	0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x3366, 0x0040,
-	0x3373, 0x0078, 0x2573, 0x78e4, 0xa005, 0x00d0, 0x2944, 0x0018,
-	0x2944, 0x2008, 0xa084, 0x0030, 0x00c0, 0x29d2, 0x781b, 0x004f,
-	0x0078, 0x2438, 0x78ec, 0xa084, 0x0003, 0x0040, 0x29ce, 0x2100,
-	0xa184, 0x0007, 0x0079, 0x29dc, 0x29ee, 0x29f2, 0x29e6, 0x29e4,
-	0x38b9, 0x38b9, 0x29e4, 0x38af, 0x1078, 0x23ca, 0x1078, 0x3697,
-	0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2438, 0x1078, 0x3697,
-	0x0078, 0x3884, 0x1078, 0x3697, 0x782b, 0x3008, 0x781b, 0x00d2,
-	0x0078, 0x2438, 0x1078, 0x3697, 0x782b, 0x3008, 0x781b, 0x0093,
-	0x0078, 0x2438, 0x2300, 0x0079, 0x2a05, 0x2a0a, 0x2a08, 0x2a0c,
-	0x1078, 0x23ca, 0x0078, 0x3081, 0x681b, 0x0008, 0x78a3, 0x0000,
-	0x79e4, 0xa184, 0x0030, 0x0040, 0x3081, 0x78ec, 0xa084, 0x0003,
-	0x0040, 0x3081, 0xa184, 0x0007, 0x0079, 0x2a1e, 0x2a26, 0x29f2,
-	0x296e, 0x3854, 0x38b9, 0x38b9, 0x2a26, 0x38af, 0x1078, 0x3868,
-	0x0078, 0x2438, 0xa282, 0x0005, 0x0050, 0x2a30, 0x1078, 0x23ca,
-	0x2300, 0x0079, 0x2a33, 0x2a36, 0x2c84, 0x2c92, 0x2200, 0x0079,
-	0x2a39, 0x2a53, 0x2a40, 0x2a53, 0x2a3e, 0x2c69, 0x1078, 0x23ca,
-	0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0048,
-	0x366b, 0xa08a, 0x0004, 0x00c8, 0x366b, 0x0079, 0x2a4f, 0x366b,
-	0x366b, 0x366b, 0x3619, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080,
-	0x0040, 0x2a64, 0x0078, 0x366b, 0x7000, 0xa005, 0x00c0, 0x2a5a,
-	0x2011, 0x0004, 0x0078, 0x31f5, 0xa184, 0x00ff, 0xa08a, 0x0010,
-	0x00c8, 0x366b, 0x0079, 0x2a6c, 0x2a7e, 0x2a7c, 0x2a96, 0x2a9a,
-	0x2b55, 0x366b, 0x366b, 0x2b57, 0x366b, 0x366b, 0x2c65, 0x2c65,
-	0x366b, 0x366b, 0x366b, 0x2c67, 0x1078, 0x23ca, 0xa684, 0x1000,
-	0x0040, 0x2a8b, 0x2001, 0x0500, 0x8000, 0x8000, 0x783a, 0x781b,
-	0x0091, 0x0078, 0x2438, 0x6818, 0xa084, 0x8000, 0x0040, 0x2a94,
-	0x681b, 0x001d, 0x0078, 0x2a82, 0x0078, 0x3854, 0x681b, 0x001d,
-	0x0078, 0x367b, 0x6920, 0x6922, 0xa684, 0x1800, 0x00c0, 0x2adb,
-	0x6820, 0xa084, 0x0001, 0x00c0, 0x2ae1, 0x6818, 0xa086, 0x0008,
-	0x00c0, 0x2aac, 0x681b, 0x0000, 0xa684, 0x0400, 0x0040, 0x2b51,
-	0xa684, 0x0080, 0x0040, 0x2ad7, 0x7097, 0x0000, 0x6818, 0xa084,
-	0x003f, 0xa08a, 0x000d, 0x0050, 0x2ad7, 0xa08a, 0x000c, 0x7196,
-	0x2001, 0x000c, 0x800c, 0x719a, 0x789b, 0x0061, 0x78aa, 0x157e,
-	0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac,
-	0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x781b,
-	0x0058, 0x0078, 0x2438, 0xa684, 0x1000, 0x0040, 0x2ae1, 0x0078,
-	0x2438, 0xa684, 0x0060, 0x0040, 0x2b4d, 0xa684, 0x0800, 0x0040,
-	0x2b4d, 0xa684, 0x8000, 0x00c0, 0x2aef, 0x0078, 0x2b09, 0xa6b4,
-	0x7fff, 0x7e5a, 0x6eb6, 0x789b, 0x0076, 0x7aac, 0x79ac, 0x78ac,
-	0x801b, 0x00c8, 0x2afc, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291,
-	0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303,
-	0x68ae, 0xa684, 0x4000, 0x0040, 0x2b11, 0xa6b4, 0xbfff, 0x7e5a,
-	0x6eb6, 0x7000, 0xa086, 0x0003, 0x00c0, 0x2b1e, 0x1078, 0x46e9,
-	0x1078, 0x48e6, 0x781b, 0x0064, 0x0078, 0x2438, 0xa006, 0x1078,
-	0x49ed, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040,
-	0x2b2d, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda,
-	0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x00c0, 0x2b3f, 0xa6b5,
-	0x4000, 0x7e5a, 0x6eb6, 0x781b, 0x0064, 0x0078, 0x2438, 0x781b,
-	0x0064, 0x2200, 0xa115, 0x00c0, 0x2b49, 0x1078, 0x48f7, 0x0078,
-	0x2438, 0x1078, 0x4942, 0x0078, 0x2438, 0x781b, 0x0065, 0x0078,
-	0x2438, 0x781b, 0x0058, 0x0078, 0x2438, 0x1078, 0x23ca, 0x0078,
-	0x2bb8, 0x6920, 0xa184, 0x0100, 0x0040, 0x2b6f, 0xa18c, 0xfeff,
-	0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000, 0xa084, 0xefff, 0x6002,
-	0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x2ba7, 0xa184,
-	0x0200, 0x0040, 0x2ba7, 0xa18c, 0xfdff, 0x6922, 0x0c7e, 0x7054,
-	0x2060, 0x6000, 0xa084, 0xdfff, 0x6002, 0x6004, 0xa084, 0xffef,
-	0x6006, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2ba7,
-	0x1078, 0x37b9, 0x1078, 0x34c7, 0x88ff, 0x0040, 0x2ba7, 0x789b,
-	0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684,
-	0x0400, 0x00c0, 0x2ba1, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078,
-	0x2438, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x7e58,
-	0xa684, 0x0400, 0x00c0, 0x2bb0, 0x781b, 0x0058, 0x0078, 0x2438,
-	0x781b, 0x0065, 0x0078, 0x2438, 0x0078, 0x3673, 0x0078, 0x3673,
-	0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x2bb6, 0x789b,
-	0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, 0x2bf6,
-	0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x2bee, 0x0048,
-	0x2bd3, 0x0078, 0x2bf0, 0xa380, 0x0002, 0xa102, 0x00c8, 0x2bee,
-	0x6920, 0xa18c, 0xfcff, 0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000,
-	0xa084, 0xefef, 0x6002, 0x6004, 0xa084, 0xffe5, 0x6006, 0x0c7f,
-	0x7e58, 0xa6b4, 0xfffb, 0x7e5a, 0x0078, 0x2ba8, 0x0078, 0x2b59,
-	0x24a8, 0x7aa8, 0x00f0, 0x2bf0, 0x0078, 0x2bc1, 0xa284, 0x00f0,
-	0xa086, 0x0020, 0x00c0, 0x2c56, 0x8318, 0x8318, 0x2300, 0xa102,
-	0x0040, 0x2c06, 0x0048, 0x2c06, 0x0078, 0x2c53, 0xa286, 0x0023,
-	0x0040, 0x2bb6, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684,
-	0xfff1, 0xa085, 0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, 0x0010,
-	0x600a, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f,
-	0xa184, 0x0010, 0x0040, 0x2c2a, 0x1078, 0x37b9, 0x1078, 0x35d6,
-	0x0078, 0x2c39, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008, 0x2c48,
-	0x0c7f, 0xa184, 0x0008, 0x0040, 0x2ba7, 0x1078, 0x37b9, 0x1078,
-	0x34c7, 0x88ff, 0x0040, 0x2ba7, 0x789b, 0x0060, 0x2800, 0x78aa,
-	0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2c4d, 0x782b,
-	0x3008, 0x781b, 0x0056, 0x0078, 0x2438, 0x782b, 0x3008, 0x781b,
-	0x0065, 0x0078, 0x2438, 0x7aa8, 0x0078, 0x2bc1, 0x8318, 0x2300,
-	0xa102, 0x0040, 0x2c5f, 0x0048, 0x2c5f, 0x0078, 0x2bc1, 0xa284,
-	0x0080, 0x00c0, 0x367b, 0x0078, 0x3673, 0x0078, 0x367b, 0x0078,
-	0x366b, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001,
-	0x0040, 0x2c74, 0x1078, 0x23ca, 0x7aa8, 0xa294, 0x00ff, 0x78a8,
-	0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x366b, 0x0079, 0x2c80,
-	0x366b, 0x3414, 0x366b, 0x356b, 0xa282, 0x0000, 0x00c0, 0x2c8a,
-	0x1078, 0x23ca, 0x1078, 0x368f, 0x782b, 0x3008, 0x781b, 0x0065,
-	0x0078, 0x2438, 0xa282, 0x0003, 0x00c0, 0x2c98, 0x1078, 0x23ca,
-	0xa484, 0x8000, 0x00c0, 0x2cbb, 0x706c, 0xa005, 0x0040, 0x2ca2,
-	0x1078, 0x23ca, 0x6f14, 0x7782, 0xa7bc, 0x0f00, 0x1078, 0x37bd,
-	0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x001f, 0x00c0,
-	0x2ca6, 0x1078, 0x3693, 0x706f, 0x0002, 0x2009, 0x5038, 0x200b,
-	0x0009, 0x0078, 0x2cbd, 0x1078, 0x369f, 0x782b, 0x3008, 0x781b,
-	0x0065, 0x0078, 0x2438, 0xa282, 0x0004, 0x0050, 0x2cc9, 0x1078,
-	0x23ca, 0x2300, 0x0079, 0x2ccc, 0x2ccf, 0x2db8, 0x2deb, 0xa286,
-	0x0003, 0x0040, 0x2cd5, 0x1078, 0x23ca, 0x2001, 0x0000, 0x007e,
-	0x68c0, 0xa005, 0x0040, 0x2cde, 0x7003, 0x0003, 0x68a0, 0xa084,
-	0x2000, 0x0040, 0x2ce7, 0x6008, 0xa085, 0x0002, 0x600a, 0x007f,
-	0x703e, 0x7000, 0xa084, 0x0007, 0x0079, 0x2cee, 0x2461, 0x2cf8,
-	0x2cf8, 0x2eed, 0x2f29, 0x2461, 0x2f29, 0x2cf6, 0x1078, 0x23ca,
-	0xa684, 0x1000, 0x00c0, 0x2d00, 0x1078, 0x4633, 0x0040, 0x2d92,
-	0x7868, 0xa08c, 0x00ff, 0x0040, 0x2d48, 0xa186, 0x0008, 0x00c0,
-	0x2d17, 0x1078, 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078,
-	0x3366, 0x0040, 0x2d48, 0x1078, 0x4633, 0x0078, 0x2d2f, 0xa186,
-	0x0028, 0x00c0, 0x2d48, 0x1078, 0x4633, 0x6008, 0xa084, 0xffef,
-	0x600a, 0x6018, 0xa005, 0x0040, 0x2d2f, 0x8001, 0x601a, 0xa005,
-	0x0040, 0x2d2f, 0x8001, 0xa005, 0x0040, 0x2d2f, 0x601e, 0x6820,
-	0xa084, 0x0001, 0x0040, 0x2461, 0x6820, 0xa084, 0xfffe, 0x6822,
-	0x7060, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802,
-	0xa005, 0x2d00, 0x00c0, 0x2d45, 0x6002, 0x6006, 0x0078, 0x2461,
-	0x017e, 0x1078, 0x2e1c, 0x017f, 0xa684, 0xdf00, 0x681e, 0x682b,
-	0x0000, 0x6f14, 0x81ff, 0x0040, 0x2d92, 0xa186, 0x0002, 0x00c0,
-	0x2d92, 0xa684, 0x0800, 0x00c0, 0x2d65, 0xa684, 0x0060, 0x0040,
-	0x2d65, 0x78d8, 0x7adc, 0x682e, 0x6a32, 0x6820, 0xa084, 0x0800,
-	0x00c0, 0x2d92, 0x8717, 0xa294, 0x000f, 0x8213, 0x8213, 0x8213,
-	0xa290, 0x5280, 0xa290, 0x0000, 0x221c, 0xa384, 0x0100, 0x00c0,
-	0x2d7b, 0x0078, 0x2d81, 0x8210, 0x2204, 0xa085, 0x0018, 0x2012,
-	0x8211, 0xa384, 0x0400, 0x0040, 0x2d8e, 0x68a0, 0xa084, 0x0100,
-	0x00c0, 0x2d8e, 0x1078, 0x2ea0, 0x0078, 0x2461, 0x6008, 0xa085,
-	0x0002, 0x600a, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, 0x2d9a,
-	0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078, 0x33b5, 0x1078,
-	0x33c4, 0x00c0, 0x2da7, 0x6008, 0xa084, 0xffef, 0x600a, 0x6820,
-	0xa084, 0x0001, 0x00c0, 0x2db0, 0x1078, 0x33ae, 0x0078, 0x2db4,
-	0x7060, 0x2060, 0x6800, 0x6002, 0x1078, 0x1c53, 0x0078, 0x2461,
-	0xa282, 0x0004, 0x0048, 0x2dbe, 0x1078, 0x23ca, 0x2200, 0x0079,
-	0x2dc1, 0x2dbc, 0x2dc5, 0x2dd2, 0x2dc5, 0x7000, 0xa086, 0x0005,
-	0x0040, 0x2dce, 0x1078, 0x368f, 0x782b, 0x3008, 0x781b, 0x0065,
-	0x0078, 0x2438, 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, 0xa080,
-	0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0040,
-	0x2de7, 0xa186, 0x0000, 0x0040, 0x2de7, 0x0078, 0x366b, 0x781b,
-	0x0065, 0x0078, 0x2438, 0x6820, 0xa085, 0x0004, 0x6822, 0x82ff,
-	0x00c0, 0x2df6, 0x1078, 0x368f, 0x0078, 0x2dfd, 0x8211, 0x0040,
-	0x2dfb, 0x1078, 0x23ca, 0x1078, 0x369f, 0x782b, 0x3008, 0x781b,
-	0x0065, 0x0078, 0x2438, 0x702c, 0x8003, 0x0048, 0x2e0d, 0x2019,
-	0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, 0x1078, 0x38de, 0x7830,
-	0xa084, 0x00c0, 0x00c0, 0x2e19, 0x0018, 0x2e19, 0x791a, 0xa006,
-	0x007c, 0xa085, 0x0001, 0x007c, 0xa684, 0x0060, 0x00c0, 0x2e26,
-	0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e9f, 0xa684, 0x0800,
-	0x00c0, 0x2e48, 0x68b4, 0xa084, 0x4800, 0xa635, 0xa684, 0x0800,
-	0x00c0, 0x2e48, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x703c, 0xa005,
-	0x00c0, 0x2e40, 0x2200, 0xa105, 0x0040, 0x2e47, 0x703f, 0x0015,
-	0x7000, 0xa086, 0x0006, 0x0040, 0x2e47, 0x1078, 0x4633, 0x007c,
-	0xa684, 0x0020, 0x0040, 0x2e6a, 0xa684, 0x4000, 0x0040, 0x2e56,
-	0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e40, 0x68b4, 0xa084,
-	0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x2e50, 0x703c, 0xa005,
-	0x00c0, 0x2e64, 0x703f, 0x0015, 0x79d8, 0x7adc, 0x692e, 0x6a32,
-	0x0078, 0x2e40, 0xa684, 0x4000, 0x0040, 0x2e74, 0x682f, 0x0000,
-	0x6833, 0x0000, 0x0078, 0x2e40, 0x68b4, 0xa084, 0x4800, 0xa635,
-	0xa684, 0x4000, 0x00c0, 0x2e6e, 0x703c, 0xa005, 0x00c0, 0x2e82,
-	0x703f, 0x0015, 0x79d8, 0x7adc, 0x78d0, 0x80fb, 0x00c8, 0x2e89,
-	0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32,
-	0x2100, 0xa205, 0x00c0, 0x2e96, 0x0078, 0x2e40, 0x7000, 0xa086,
-	0x0006, 0x0040, 0x2e9f, 0x1078, 0x49ed, 0x0078, 0x2e40, 0x007c,
-	0x6008, 0xa085, 0x0200, 0x600a, 0xa384, 0x0200, 0x0040, 0x2eac,
-	0x6008, 0xa085, 0x0002, 0x600a, 0x681b, 0x0006, 0x688f, 0x0000,
-	0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003,
-	0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020,
-	0x68b3, 0x0000, 0x68af, 0x0000, 0x7000, 0x0079, 0x2ec7, 0x2461,
-	0x2ed1, 0x2eda, 0x2ecf, 0x2ecf, 0x2ecf, 0x2ecf, 0x2ecf, 0x1078,
-	0x23ca, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2eda, 0x1078, 0x33ae,
-	0x0078, 0x2ee0, 0x7060, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60,
-	0x2021, 0x505a, 0x2404, 0xa005, 0x0040, 0x2ee9, 0x2020, 0x0078,
-	0x2ee2, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078, 0x33b5, 0x1078,
-	0x33c4, 0x6008, 0xa084, 0xfdff, 0x600a, 0x682b, 0x0000, 0x789b,
-	0x000e, 0x6f14, 0x6817, 0x0002, 0x1078, 0x4a35, 0xa684, 0x0800,
-	0x0040, 0x2f06, 0x691c, 0xa18d, 0x2000, 0x691e, 0x6818, 0xa084,
-	0x8000, 0x0040, 0x2f16, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x2f14,
-	0x681b, 0x001e, 0x0078, 0x2f16, 0x681b, 0x0000, 0x2021, 0x505a,
-	0x2404, 0xad06, 0x0040, 0x2f1d, 0x7460, 0x6800, 0x2022, 0x68c3,
-	0x0000, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x1c53, 0x0078,
-	0x2461, 0x1078, 0x2e1c, 0x682b, 0x0000, 0x2001, 0x000e, 0x6f14,
-	0x1078, 0x38e4, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xa084, 0x8000,
-	0x0040, 0x2f3c, 0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x706f,
-	0x0000, 0x0078, 0x2461, 0x7000, 0xa005, 0x00c0, 0x2f49, 0x0078,
-	0x2461, 0xa006, 0x1078, 0x4633, 0x6817, 0x0000, 0x681b, 0x0014,
-	0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, 0xa085, 0x00ff,
-	0x6822, 0x7000, 0x0079, 0x2f5c, 0x2461, 0x2f66, 0x2f66, 0x2f68,
-	0x2f68, 0x2f68, 0x2f68, 0x2f64, 0x1078, 0x23ca, 0x1078, 0x33c4,
-	0x6008, 0xa084, 0xffef, 0x600a, 0x0078, 0x337e, 0x2300, 0x0079,
-	0x2f71, 0x2f74, 0x2f76, 0x2faf, 0x1078, 0x23ca, 0x7000, 0x0079,
-	0x2f79, 0x2461, 0x2f83, 0x2f83, 0x2f9e, 0x2f83, 0x2fab, 0x2f9e,
-	0x2f81, 0x1078, 0x23ca, 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0,
-	0x2f9a, 0xa6b4, 0xffdf, 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a,
-	0x681c, 0xa084, 0xffdf, 0x681e, 0x1078, 0x4633, 0x1078, 0x48f7,
-	0x0078, 0x3854, 0xa684, 0x2000, 0x0040, 0x2f8d, 0x6818, 0xa084,
-	0x8000, 0x0040, 0x2fab, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040,
-	0x2fab, 0x681b, 0x0007, 0x1078, 0x3868, 0x0078, 0x2438, 0x1078,
-	0x23ca, 0x2300, 0x0079, 0x2fb4, 0x2fb7, 0x2fb9, 0x2fec, 0x1078,
-	0x23ca, 0x7000, 0x0079, 0x2fbc, 0x2461, 0x2fc6, 0x2fc6, 0x2fe1,
-	0x2fc6, 0x2fe8, 0x2fe1, 0x2fc4, 0x1078, 0x23ca, 0xa684, 0x0060,
-	0xa086, 0x0060, 0x00c0, 0x2fdd, 0xa6b4, 0xffbf, 0xa6b4, 0xbfff,
-	0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffbf, 0x681e, 0x1078,
-	0x4633, 0x1078, 0x48f7, 0x0078, 0x3854, 0xa684, 0x2000, 0x0040,
-	0x2fd0, 0x6818, 0xa084, 0x8000, 0x0040, 0x2fe8, 0x681b, 0x0007,
-	0x781b, 0x00d2, 0x0078, 0x2438, 0x6820, 0xa085, 0x0004, 0x6822,
-	0x1078, 0x381f, 0xa6b5, 0x0800, 0x1078, 0x368f, 0x782b, 0x3008,
-	0x781b, 0x0065, 0x0078, 0x2438, 0x2300, 0x0079, 0x2fff, 0x3002,
-	0x3004, 0x3006, 0x1078, 0x23ca, 0x0078, 0x367b, 0xa684, 0x0400,
-	0x00c0, 0x302f, 0x79e4, 0xa184, 0x0020, 0x0040, 0x3016, 0x78ec,
-	0xa084, 0x0003, 0x0040, 0x3016, 0x782b, 0x3009, 0x789b, 0x0060,
-	0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xa184, 0x0020,
-	0x0040, 0x3027, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x302b, 0x2001,
-	0x0014, 0x0078, 0x2cd7, 0xa184, 0x0007, 0x0079, 0x3067, 0x7a90,
-	0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0040, 0x3065,
-	0x789b, 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, 0x3056, 0x7ba8,
-	0x7ba8, 0xa386, 0x0001, 0x00c0, 0x3049, 0x2009, 0xfff7, 0x0078,
-	0x304f, 0xa386, 0x0003, 0x00c0, 0x3056, 0x2009, 0xffef, 0x0c7e,
-	0x7054, 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, 0x789b, 0x0060,
-	0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, 0x6920,
-	0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078, 0x3854, 0x297d,
-	0x2988, 0x3071, 0x3079, 0x306f, 0x306f, 0x3854, 0x3854, 0x1078,
-	0x23ca, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078,
-	0x385e, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078,
-	0x3854, 0x79e4, 0xa184, 0x0030, 0x0040, 0x308b, 0x78ec, 0xa084,
-	0x0003, 0x00c0, 0x30b2, 0x7000, 0xa086, 0x0004, 0x00c0, 0x30a5,
-	0x706c, 0xa086, 0x0002, 0x00c0, 0x309b, 0x2011, 0x0002, 0x2019,
-	0x0000, 0x0078, 0x2827, 0x706c, 0xa086, 0x0006, 0x0040, 0x3095,
-	0x706c, 0xa086, 0x0004, 0x0040, 0x3095, 0x7000, 0xa086, 0x0000,
-	0x0040, 0x2438, 0x6818, 0xa085, 0x8000, 0x681a, 0x2001, 0x0014,
-	0x0078, 0x2cd7, 0xa184, 0x0007, 0x0079, 0x30b6, 0x3854, 0x3854,
-	0x30be, 0x3854, 0x38b9, 0x38b9, 0x3854, 0x3854, 0xa684, 0x0080,
-	0x0040, 0x30ed, 0x7194, 0x81ff, 0x0040, 0x30ed, 0xa182, 0x000d,
-	0x00d0, 0x30ce, 0x7097, 0x0000, 0x0078, 0x30d3, 0xa182, 0x000c,
-	0x7096, 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa, 0x157e, 0x137e,
-	0x147e, 0x7098, 0x8114, 0xa210, 0x729a, 0xa080, 0x000b, 0xad00,
-	0x2098, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6,
-	0x147f, 0x137f, 0x157f, 0x0078, 0x385e, 0xa684, 0x0400, 0x00c0,
-	0x312e, 0x6820, 0xa084, 0x0001, 0x0040, 0x385e, 0xa68c, 0x0060,
-	0xa684, 0x0060, 0x0040, 0x3102, 0xa086, 0x0060, 0x00c0, 0x3102,
-	0xa18d, 0x4000, 0xa18c, 0xfffb, 0x795a, 0x69b6, 0x789b, 0x0060,
-	0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, 0xa085, 0x8000, 0x681a,
-	0x78aa, 0x8008, 0x810c, 0x0040, 0x33dd, 0xa18c, 0x00f8, 0x00c0,
-	0x33dd, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000,
-	0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f,
-	0x157f, 0x6814, 0x8007, 0x7882, 0x0078, 0x385e, 0x6818, 0xa084,
-	0x8000, 0x0040, 0x3135, 0x681b, 0x0008, 0x781b, 0x00c8, 0x0078,
-	0x2438, 0x2300, 0x0079, 0x313c, 0x3141, 0x31e0, 0x313f, 0x1078,
-	0x23ca, 0x7000, 0xa084, 0x0007, 0x0079, 0x3146, 0x2461, 0x3150,
-	0x3185, 0x315b, 0x314e, 0x2461, 0x314e, 0x314e, 0x1078, 0x23ca,
-	0x681c, 0xa084, 0x2000, 0x0040, 0x3169, 0x6008, 0xa085, 0x0002,
-	0x600a, 0x0078, 0x3169, 0x68c0, 0xa005, 0x00c0, 0x3185, 0x6920,
-	0xa18d, 0x0001, 0x6922, 0x68c3, 0x0001, 0x6800, 0x706a, 0x0078,
-	0x317f, 0x6920, 0xa18d, 0x0001, 0x6922, 0x6800, 0x6006, 0xa005,
-	0x00c0, 0x3173, 0x6002, 0x681c, 0xa084, 0x000e, 0x0040, 0x317f,
-	0x7014, 0x68ba, 0x7130, 0xa188, 0x7300, 0x0078, 0x3181, 0x2009,
-	0x7400, 0x2104, 0x6802, 0x2d0a, 0x7162, 0x6eb6, 0xa684, 0x0060,
-	0x0040, 0x31de, 0xa684, 0x0800, 0x00c0, 0x3199, 0xa684, 0x7fff,
-	0x68b6, 0x6894, 0x68a6, 0x6898, 0x68aa, 0x1078, 0x4633, 0x0078,
-	0x31de, 0xa684, 0x0020, 0x0040, 0x31ae, 0x68c0, 0xa005, 0x0040,
-	0x31a5, 0x1078, 0x4a35, 0x0078, 0x31a8, 0xa006, 0x1078, 0x49ed,
-	0x79d8, 0x7adc, 0x69aa, 0x6aa6, 0x0078, 0x31b4, 0x1078, 0x37ca,
-	0x69aa, 0x6aa6, 0x1078, 0x49ed, 0xa684, 0x8000, 0x0040, 0x31de,
-	0xa684, 0x7fff, 0x68b6, 0x2001, 0x0076, 0x1078, 0x38e4, 0x2010,
-	0x2001, 0x0078, 0x1078, 0x38e4, 0x2008, 0xa684, 0x0020, 0x00c0,
-	0x31d6, 0x2001, 0x007a, 0x1078, 0x38e4, 0x801b, 0x00c8, 0x31d1,
-	0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100,
-	0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x0078, 0x2461,
-	0x0078, 0x367b, 0x7037, 0x0000, 0xa282, 0x0006, 0x0050, 0x31ea,
-	0x1078, 0x23ca, 0x7000, 0xa084, 0x0007, 0x10c0, 0x398a, 0x2300,
-	0x0079, 0x31f2, 0x31f5, 0x321e, 0x3232, 0x2200, 0x0079, 0x31f8,
-	0x321c, 0x367b, 0x31fe, 0x321c, 0x324e, 0x3290, 0x7003, 0x0005,
-	0x2001, 0x7510, 0x2068, 0x704a, 0x157e, 0x20a9, 0x0031, 0x2003,
-	0x0000, 0x8000, 0x0070, 0x320e, 0x0078, 0x3207, 0x157f, 0xad80,
-	0x0009, 0x7036, 0x6817, 0x0000, 0x68b7, 0x0700, 0x6823, 0x0800,
-	0x6827, 0x0003, 0x0078, 0x366b, 0x1078, 0x23ca, 0x7003, 0x0005,
-	0x2001, 0x7510, 0x2068, 0x704a, 0xad80, 0x0009, 0x7036, 0x2200,
-	0x0079, 0x322a, 0x367b, 0x3230, 0x3230, 0x324e, 0x3230, 0x367b,
-	0x1078, 0x23ca, 0x7003, 0x0005, 0x2001, 0x7510, 0x2068, 0x704a,
-	0xad80, 0x0009, 0x7036, 0x2200, 0x0079, 0x323e, 0x3246, 0x3244,
-	0x3244, 0x3246, 0x3244, 0x3246, 0x1078, 0x23ca, 0x1078, 0x369f,
-	0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x7003, 0x0002,
-	0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f,
-	0xa215, 0x2069, 0x7400, 0x2d04, 0x2d08, 0x7162, 0x2068, 0xa005,
-	0x0040, 0x3269, 0x6814, 0xa206, 0x0040, 0x3285, 0x6800, 0x0078,
-	0x325c, 0x7003, 0x0005, 0x2001, 0x7510, 0x2068, 0x704a, 0x7036,
-	0x157e, 0x20a9, 0x0031, 0x2003, 0x0000, 0x8000, 0x0070, 0x327a,
-	0x0078, 0x3273, 0x157f, 0xad80, 0x0009, 0x7036, 0x6a16, 0x68b7,
-	0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820,
-	0xa084, 0x0c00, 0x0040, 0x32df, 0x1078, 0x3697, 0x0078, 0x32df,
-	0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8,
-	0xa484, 0x001f, 0xa215, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0xa1e8,
-	0x7300, 0x2d04, 0x2d08, 0x7162, 0x2068, 0xa005, 0x0040, 0x32af,
-	0x6814, 0xa206, 0x0040, 0x32ca, 0x6800, 0x0078, 0x32a2, 0x7003,
-	0x0005, 0x2001, 0x7510, 0x2068, 0x704a, 0x157e, 0x20a9, 0x0031,
-	0x2003, 0x0000, 0x8000, 0x0070, 0x32bf, 0x0078, 0x32b8, 0x157f,
-	0xad80, 0x0009, 0x7036, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800,
-	0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040,
-	0x32df, 0xa084, 0x0800, 0x0040, 0x32d9, 0x1078, 0x369b, 0x0078,
-	0x32df, 0x1078, 0x3697, 0x708b, 0x0000, 0x0078, 0x32df, 0x027e,
-	0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x5280,
-	0x2060, 0x7056, 0x6000, 0x705a, 0x6004, 0x705e, 0xa684, 0x0060,
-	0x0040, 0x3337, 0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x00c0,
-	0x3319, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, 0xb7ff, 0x7e5a,
-	0xa684, 0x0060, 0xa086, 0x0060, 0x0040, 0x3337, 0x68c0, 0xa005,
-	0x0040, 0x3312, 0x7003, 0x0003, 0x682b, 0x0000, 0x1078, 0x48e6,
-	0x0078, 0x3314, 0x1078, 0x48f7, 0xa6b5, 0x2000, 0x7e5a, 0x0078,
-	0x3337, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x0040,
-	0x3337, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xa6b4, 0xbfff,
-	0x7e5a, 0x007e, 0x68c0, 0xa005, 0x007f, 0x0040, 0x3335, 0x7003,
-	0x0003, 0x1078, 0x48e6, 0x0078, 0x3337, 0x1078, 0x4942, 0x077f,
-	0x1078, 0x37bd, 0x2009, 0x0065, 0xa684, 0x0004, 0x0040, 0x3358,
-	0x78e4, 0xa084, 0x0030, 0x0040, 0x3350, 0x78ec, 0xa084, 0x0003,
-	0x0040, 0x3350, 0x782b, 0x3008, 0x2009, 0x0065, 0x0078, 0x3358,
-	0x0f7e, 0x2079, 0x5000, 0x1078, 0x4633, 0x0f7f, 0x0040, 0x2461,
-	0x791a, 0x2d00, 0x704a, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003,
-	0x8003, 0xa080, 0x5280, 0x2048, 0x0078, 0x2438, 0x6020, 0xa005,
-	0x0040, 0x3372, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a,
-	0x7010, 0x6026, 0x007c, 0xa006, 0x1078, 0x4633, 0x6817, 0x0000,
-	0x681b, 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084,
-	0x0007, 0x0079, 0x3383, 0x2461, 0x338d, 0x338d, 0x33aa, 0x3395,
-	0x3393, 0x3395, 0x338b, 0x1078, 0x23ca, 0x1078, 0x33b5, 0x1078,
-	0x33ae, 0x1078, 0x1c53, 0x0078, 0x2461, 0x706c, 0x706f, 0x0000,
-	0x7093, 0x0000, 0x0079, 0x339c, 0x33a6, 0x33a6, 0x33a4, 0x33a4,
-	0x33a4, 0x33a6, 0x33a4, 0x33a6, 0x0079, 0x2840, 0x706f, 0x0000,
-	0x0078, 0x2461, 0x681b, 0x0000, 0x0078, 0x2eed, 0x6800, 0xa005,
-	0x00c0, 0x33b3, 0x6002, 0x6006, 0x007c, 0x6010, 0xa005, 0x0040,
-	0x33be, 0x8001, 0x00d0, 0x33be, 0x1078, 0x23ca, 0x6012, 0x6008,
-	0xa084, 0xffef, 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x33ca,
-	0x8001, 0x601a, 0x007c, 0x1078, 0x38de, 0x681b, 0x0018, 0x0078,
-	0x3401, 0x1078, 0x38de, 0x681b, 0x0019, 0x0078, 0x3401, 0x1078,
-	0x38de, 0x681b, 0x001a, 0x0078, 0x3401, 0x1078, 0x38de, 0x681b,
-	0x0003, 0x0078, 0x3401, 0x7780, 0x1078, 0x37bd, 0x7184, 0xa18c,
-	0x00ff, 0xa1e8, 0x7300, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0,
-	0x33f3, 0x0078, 0x2461, 0x6814, 0x7280, 0xa206, 0x0040, 0x33fb,
-	0x6800, 0x0078, 0x33ec, 0x6800, 0x200a, 0x681b, 0x0005, 0x708b,
-	0x0000, 0x1078, 0x33b5, 0x6820, 0xa084, 0x0001, 0x00c0, 0x340a,
-	0x1078, 0x33ae, 0x1078, 0x33c4, 0x681f, 0x0000, 0x6823, 0x0020,
-	0x1078, 0x1c53, 0x0078, 0x2461, 0xa282, 0x0003, 0x00c0, 0x366b,
-	0x7da8, 0xa5ac, 0x00ff, 0x7ca8, 0xa4a4, 0x00ff, 0x6920, 0xa18d,
-	0x0080, 0x6922, 0xa184, 0x0100, 0x0040, 0x3478, 0xa18c, 0xfeff,
-	0x6922, 0xa4a4, 0x00ff, 0x0040, 0x3462, 0xa482, 0x000c, 0x0048,
-	0x3435, 0x0040, 0x3435, 0x2021, 0x000c, 0x852b, 0x852b, 0x1078,
-	0x372e, 0x0040, 0x343f, 0x1078, 0x3531, 0x0078, 0x346b, 0x1078,
-	0x36e9, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078,
-	0x3558, 0x0c7f, 0x6920, 0xa18d, 0x0100, 0x6922, 0x7e58, 0xa6b5,
-	0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x345c, 0x782b, 0x3008,
-	0x781b, 0x0056, 0x0078, 0x2438, 0x782b, 0x3008, 0x781b, 0x0065,
-	0x0078, 0x2438, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006,
-	0x1078, 0x3558, 0x0c7f, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x3474,
-	0x781b, 0x0058, 0x0078, 0x2438, 0x781b, 0x0065, 0x0078, 0x2438,
-	0x0c7e, 0x7054, 0x2060, 0x6100, 0xa18c, 0x1000, 0x0040, 0x34b8,
-	0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, 0x348c,
-	0x0040, 0x348c, 0x2011, 0x000c, 0x2400, 0xa202, 0x00c8, 0x3491,
-	0x2220, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0,
-	0x34a1, 0xa282, 0x0019, 0x00c8, 0x34a7, 0x2011, 0x0019, 0x0078,
-	0x34a7, 0xa282, 0x000c, 0x00c8, 0x34a7, 0x2011, 0x000c, 0x2200,
-	0xa502, 0x00c8, 0x34ac, 0x2228, 0x1078, 0x36ed, 0x852b, 0x852b,
-	0x1078, 0x372e, 0x0040, 0x34b8, 0x1078, 0x3531, 0x0078, 0x34bc,
-	0x1078, 0x36e9, 0x1078, 0x3558, 0x7858, 0xa085, 0x0004, 0x785a,
-	0x0c7f, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x0c7e,
-	0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x34df, 0x6010, 0xa084,
-	0x000f, 0x00c0, 0x34d9, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x0c7f,
-	0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3506, 0x68a0,
-	0xa084, 0x0200, 0x00c0, 0x34d9, 0x6208, 0xa294, 0x00ff, 0x7018,
-	0xa086, 0x0028, 0x00c0, 0x34f4, 0xa282, 0x0019, 0x00c8, 0x34fa,
-	0x2011, 0x0019, 0x0078, 0x34fa, 0xa282, 0x000c, 0x00c8, 0x34fa,
-	0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c,
-	0x0048, 0x3506, 0x0040, 0x3506, 0x2019, 0x000c, 0x78ab, 0x0001,
-	0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005,
-	0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x2960,
-	0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078,
-	0x3521, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa,
-	0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f,
-	0x007c, 0x0c7e, 0x7154, 0x2160, 0x1078, 0x3538, 0x0c7f, 0x007c,
-	0x2008, 0xa084, 0xfff0, 0xa425, 0x7c86, 0x6018, 0x789a, 0x7cae,
-	0x6412, 0x78a4, 0xa084, 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6,
-	0x6016, 0x788a, 0xa4a4, 0x000f, 0x8427, 0x8204, 0x8004, 0xa084,
-	0x00ff, 0xa405, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, 0x007c,
-	0x0c7e, 0x7054, 0x2060, 0x1078, 0x355f, 0x0c7f, 0x007c, 0x6018,
-	0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084,
-	0xfff0, 0x7886, 0x007c, 0xa282, 0x0002, 0x00c0, 0x366b, 0x7aa8,
-	0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, 0x0200, 0x0040, 0x35b4,
-	0xa18c, 0xfdff, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8,
-	0x366b, 0x1078, 0x35fd, 0x1078, 0x3558, 0xa980, 0x0001, 0x200c,
-	0x1078, 0x37b9, 0x1078, 0x34c7, 0x88ff, 0x0040, 0x35a7, 0x789b,
-	0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684,
-	0x0400, 0x00c0, 0x35a1, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078,
-	0x2438, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x7e58,
-	0xa684, 0x0400, 0x00c0, 0x35b0, 0x781b, 0x0058, 0x0078, 0x2438,
-	0x781b, 0x0065, 0x0078, 0x2438, 0xa282, 0x0002, 0x00c8, 0x35bc,
-	0xa284, 0x0001, 0x0040, 0x35c6, 0x7154, 0xa188, 0x0000, 0x210c,
-	0xa18c, 0x2000, 0x00c0, 0x35c6, 0x2011, 0x0000, 0x1078, 0x36db,
-	0x1078, 0x35fd, 0x1078, 0x3558, 0x7858, 0xa085, 0x0004, 0x785a,
-	0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x0c7e, 0x027e,
-	0x2960, 0x6000, 0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x35ed,
-	0x6014, 0xa084, 0x0040, 0x00c0, 0x35eb, 0xa18c, 0xffef, 0x6106,
-	0xa006, 0x0078, 0x35fa, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab,
-	0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085,
-	0x0200, 0x6822, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7054, 0x2060,
-	0x1078, 0x3604, 0x0c7f, 0x007c, 0x82ff, 0x0040, 0x3609, 0x2011,
-	0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, 0xffbf,
-	0xa205, 0x78a6, 0x788a, 0x6016, 0x6004, 0xa084, 0xffef, 0x6006,
-	0x007c, 0x007e, 0x7000, 0xa086, 0x0003, 0x0040, 0x3622, 0x007f,
-	0x0078, 0x3625, 0x007f, 0x0078, 0x3667, 0xa684, 0x0020, 0x0040,
-	0x3667, 0x7888, 0xa084, 0x0040, 0x0040, 0x3667, 0x7bb8, 0xa384,
-	0x003f, 0x831b, 0x00c8, 0x3635, 0x8000, 0xa005, 0x0040, 0x364b,
-	0x831b, 0x00c8, 0x363e, 0x8001, 0x0040, 0x3663, 0xa684, 0x4000,
-	0x0040, 0x364b, 0x78b8, 0x801b, 0x00c8, 0x3647, 0x8000, 0xa084,
-	0x003f, 0x00c0, 0x3663, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc,
-	0x2001, 0x0001, 0xa108, 0x00c8, 0x3657, 0xa291, 0x0000, 0x79d2,
-	0x79da, 0x7ad6, 0x7ade, 0x1078, 0x49ed, 0x781b, 0x0064, 0x1078,
-	0x4872, 0x0078, 0x2438, 0x781b, 0x0064, 0x0078, 0x2438, 0x781b,
-	0x0065, 0x0078, 0x2438, 0x1078, 0x36a3, 0x782b, 0x3008, 0x781b,
-	0x0065, 0x0078, 0x2438, 0x1078, 0x368f, 0x782b, 0x3008, 0x781b,
-	0x0065, 0x0078, 0x2438, 0x6827, 0x0002, 0x1078, 0x3697, 0x78e4,
-	0xa084, 0x0030, 0x0040, 0x2461, 0x78ec, 0xa084, 0x0003, 0x0040,
-	0x2461, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x2001,
-	0x0005, 0x0078, 0x36a5, 0x2001, 0x000c, 0x0078, 0x36a5, 0x2001,
-	0x0006, 0x0078, 0x36a5, 0x2001, 0x000d, 0x0078, 0x36a5, 0x2001,
-	0x0009, 0x0078, 0x36a5, 0x2001, 0x0007, 0x789b, 0x0010, 0x78aa,
-	0x789b, 0x0060, 0x78ab, 0x0001, 0xa6b5, 0x0004, 0x7e5a, 0x007c,
-	0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0xa0e0,
-	0x5280, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f, 0x0040,
-	0x36c9, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, 0xa085, 0x0008,
-	0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, 0x0040,
-	0x36d9, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004, 0xa085, 0x0010,
-	0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab,
-	0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004,
-	0x007c, 0x2021, 0x0000, 0x2029, 0x0032, 0x789b, 0x0010, 0x78ab,
-	0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7caa, 0x789b,
-	0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007, 0xa084, 0x00ff,
-	0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xfff0,
-	0x2001, 0x5046, 0x2004, 0xa082, 0x0028, 0x0040, 0x3717, 0x2021,
-	0x37a0, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, 0x371d, 0x2021,
-	0x37ac, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, 0x2404,
-	0xa084, 0xfff0, 0xa106, 0x0040, 0x372c, 0x8420, 0x2300, 0xa210,
-	0x0070, 0x372c, 0x0078, 0x371f, 0x157f, 0x007c, 0x157e, 0x2009,
-	0x5046, 0x210c, 0xa182, 0x0032, 0x0048, 0x3742, 0x0040, 0x3746,
-	0x2009, 0x3792, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032,
-	0x0078, 0x3758, 0xa182, 0x0028, 0x0040, 0x3750, 0x2009, 0x37a0,
-	0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064, 0x0078, 0x3758,
-	0x2009, 0x37ac, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064,
-	0x2200, 0xa502, 0x0040, 0x3768, 0x0048, 0x3768, 0x8108, 0x2300,
-	0xa210, 0x0070, 0x3765, 0x0078, 0x3758, 0x157f, 0xa006, 0x007c,
-	0x157f, 0xa582, 0x0064, 0x00c8, 0x3777, 0x7808, 0xa085, 0x0070,
-	0x780a, 0x7044, 0xa085, 0x0070, 0x7046, 0x0078, 0x3777, 0x78ec,
-	0xa084, 0x0300, 0x0040, 0x377f, 0x2104, 0x0078, 0x3790, 0x2104,
-	0xa09e, 0x1102, 0x00c0, 0x3790, 0x2001, 0x04fd, 0x2004, 0xa082,
-	0x0005, 0x0048, 0x378f, 0x2001, 0x1201, 0x0078, 0x3790, 0x2104,
-	0xa005, 0x007c, 0x1102, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404,
-	0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, 0x0c07, 0x0e07,
-	0x3202, 0x4202, 0x5202, 0x6202, 0x7202, 0x6605, 0x7605, 0x7805,
-	0x7a05, 0x7c05, 0x7e05, 0x7f05, 0x2202, 0x3202, 0x4202, 0x5202,
-	0x5404, 0x6404, 0x7404, 0x7604, 0x7804, 0x7a04, 0x7c04, 0x7e04,
-	0x7f04, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00, 0x800b,
-	0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e0,
-	0x5300, 0x007c, 0x79d8, 0x7adc, 0x78d0, 0x801b, 0x00c8, 0x37d1,
-	0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x007c, 0x0f7e,
-	0x2079, 0x0100, 0x2009, 0x5040, 0x2091, 0x8000, 0x2104, 0x0079,
-	0x37e1, 0x3817, 0x37eb, 0x37eb, 0x37eb, 0x37eb, 0x37eb, 0x37eb,
-	0x381b, 0x1078, 0x23ca, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004,
-	0x00c0, 0x37ed, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, 0x00c0,
-	0x37f4, 0x68b4, 0xa085, 0x4000, 0x68b6, 0x7858, 0xa085, 0x4000,
-	0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, 0x3817, 0x0018, 0x3817,
-	0x681c, 0xa084, 0x0020, 0x00c0, 0x3815, 0x0e7e, 0x2071, 0x5040,
-	0x1078, 0x3868, 0x0e7f, 0x0078, 0x3817, 0x781b, 0x00d2, 0x2091,
-	0x8001, 0x0f7f, 0x007c, 0x1078, 0x3a42, 0x0078, 0x3817, 0x0c7e,
-	0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0,
-	0x5280, 0x6004, 0xa084, 0x000a, 0x00c0, 0x3852, 0x6108, 0xa194,
-	0xff00, 0x0040, 0x3852, 0xa18c, 0x00ff, 0x2001, 0x0019, 0xa106,
-	0x0040, 0x3841, 0x2001, 0x0032, 0xa106, 0x0040, 0x3845, 0x0078,
-	0x3849, 0x2009, 0x0020, 0x0078, 0x384b, 0x2009, 0x003f, 0x0078,
-	0x384b, 0x2011, 0x0000, 0x2100, 0xa205, 0x600a, 0x6004, 0xa085,
-	0x0002, 0x6006, 0x0c7f, 0x007c, 0x781b, 0x0065, 0x0078, 0x2438,
-	0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x781b, 0x0058,
-	0x0078, 0x2438, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2438,
-	0x2009, 0x5020, 0x210c, 0xa186, 0x0000, 0x0040, 0x387c, 0xa186,
-	0x0001, 0x0040, 0x387f, 0x2009, 0x5038, 0x200b, 0x000b, 0x706f,
-	0x0001, 0x781b, 0x0048, 0x007c, 0x781b, 0x00cc, 0x007c, 0x2009,
-	0x5038, 0x200b, 0x000a, 0x007c, 0x2009, 0x5020, 0x210c, 0xa186,
-	0x0000, 0x0040, 0x389f, 0xa186, 0x0001, 0x0040, 0x3899, 0x2009,
-	0x5038, 0x200b, 0x000b, 0x706f, 0x0001, 0x781b, 0x0048, 0x0078,
-	0x2438, 0x2009, 0x5038, 0x200b, 0x000a, 0x0078, 0x2438, 0x782b,
-	0x3008, 0x781b, 0x00cc, 0x0078, 0x2438, 0x781b, 0x00d2, 0x0078,
-	0x2438, 0x782b, 0x3008, 0x781b, 0x00d2, 0x0078, 0x2438, 0x781b,
-	0x0093, 0x0078, 0x2438, 0x782b, 0x3008, 0x781b, 0x0093, 0x0078,
-	0x2438, 0x6818, 0xa084, 0x8000, 0x0040, 0x38c0, 0x681b, 0x001d,
-	0x706f, 0x0001, 0x781b, 0x0048, 0x0078, 0x2438, 0x007e, 0x7830,
-	0xa084, 0x00c0, 0x00c0, 0x38dc, 0x7808, 0xa084, 0xfffc, 0x780a,
-	0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040,
-	0x38dc, 0x7044, 0x780a, 0xa005, 0x007f, 0x007c, 0x7044, 0xa085,
-	0x0002, 0x7046, 0x780a, 0x007c, 0x007e, 0x7830, 0xa084, 0x0040,
-	0x00c0, 0x38e5, 0x0098, 0x38f0, 0x007f, 0x789a, 0x78ac, 0x007c,
-	0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005,
-	0x78ec, 0xa084, 0x0021, 0x0040, 0x38ff, 0x0098, 0x38fd, 0x007f,
-	0x789a, 0x78ac, 0x007e, 0x7044, 0x780a, 0x007f, 0x007c, 0x78ec,
-	0xa084, 0x0002, 0x00c0, 0x461d, 0xa784, 0x007d, 0x00c0, 0x3913,
-	0x2700, 0x1078, 0x23ca, 0xa784, 0x0001, 0x00c0, 0x2f43, 0xa784,
-	0x0070, 0x0040, 0x3923, 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x2375,
-	0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x3930, 0x784b,
-	0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2461, 0x0078, 0x3854,
-	0xa784, 0x0004, 0x0040, 0x3963, 0x78b8, 0xa084, 0x4001, 0x0040,
-	0x3963, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2461,
-	0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x3963, 0x78c0,
-	0xa085, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00d2, 0x0078, 0x2438,
-	0x784b, 0x0008, 0x6818, 0xa084, 0x8000, 0x0040, 0x395f, 0x681b,
-	0x0015, 0xa684, 0x4000, 0x0040, 0x395f, 0x681b, 0x0007, 0x1078,
-	0x3868, 0x0078, 0x2438, 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00,
-	0x681e, 0x682f, 0x0000, 0x6833, 0x0000, 0x784b, 0x0008, 0x78ec,
-	0xa084, 0x0003, 0x0040, 0x2944, 0x0018, 0x2438, 0x0078, 0x3673,
-	0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080,
-	0x5280, 0x2060, 0x2048, 0x7056, 0x6000, 0x705a, 0x6004, 0x705e,
-	0x2a60, 0x007c, 0x0079, 0x398c, 0x3994, 0x3995, 0x3994, 0x3997,
-	0x3994, 0x3994, 0x3994, 0x399c, 0x007c, 0x1078, 0x33c4, 0x1078,
-	0x4633, 0x7038, 0x600a, 0x007c, 0x70a0, 0xa005, 0x0040, 0x39a9,
-	0x2068, 0x1078, 0x1b45, 0x1078, 0x45b5, 0x1078, 0x45bc, 0x70a3,
-	0x0000, 0x007c, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x5040, 0x7000,
-	0xa086, 0x0007, 0x00c0, 0x39c0, 0x6110, 0x70bc, 0xa106, 0x00c0,
-	0x39c0, 0x0e7f, 0x1078, 0x1b52, 0x1078, 0x39c6, 0xa006, 0x007c,
-	0x2091, 0x8001, 0x0e7f, 0xa085, 0x0001, 0x007c, 0x0f7e, 0x0e7e,
-	0x2071, 0x5040, 0x0078, 0x21d9, 0x785b, 0x0000, 0x70af, 0x000e,
-	0x2009, 0x0100, 0x017e, 0x70a0, 0xa06d, 0x0040, 0x39db, 0x70a3,
-	0x0000, 0x0078, 0x39e1, 0x70b3, 0x0000, 0x1078, 0x1b6e, 0x0040,
-	0x39e7, 0x70ac, 0x6826, 0x1078, 0x3ac2, 0x0078, 0x39db, 0x017f,
-	0x157e, 0x0c7e, 0x0d7e, 0x20a9, 0x0008, 0x2061, 0x7410, 0x6000,
-	0xa105, 0x6002, 0x601c, 0xa06d, 0x0040, 0x39ff, 0x6800, 0x601e,
-	0x1078, 0x193d, 0x6008, 0x8000, 0x600a, 0x0078, 0x39f2, 0x6018,
-	0xa06d, 0x0040, 0x3a09, 0x6800, 0x601a, 0x1078, 0x193d, 0x0078,
-	0x39ff, 0xace0, 0x0008, 0x0070, 0x3a0f, 0x0078, 0x39ef, 0x709c,
-	0xa084, 0x8000, 0x0040, 0x3a16, 0x1078, 0x3b3c, 0x0d7f, 0x0c7f,
-	0x157f, 0x007c, 0x127e, 0x2091, 0x2300, 0x6804, 0xa084, 0x000f,
-	0x0079, 0x3a22, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a32,
-	0x3a34, 0x3a3a, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a3c,
-	0x3a32, 0x3a34, 0x1078, 0x23ca, 0x1078, 0x4466, 0x1078, 0x193d,
-	0x0078, 0x3a40, 0x6827, 0x000b, 0x1078, 0x4466, 0x1078, 0x3ac2,
-	0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x0098, 0x3a5e, 0x7830,
-	0xa084, 0x00c0, 0x00c0, 0x3a5e, 0x0d7e, 0x1078, 0x45c5, 0x2d00,
-	0x682e, 0x2009, 0x0004, 0x2001, 0x0000, 0x6827, 0x0084, 0x1078,
-	0x457e, 0x1078, 0x3ac2, 0x0d7f, 0x0078, 0x3a90, 0x7948, 0xa185,
-	0x4000, 0x784a, 0x0098, 0x3a67, 0x794a, 0x0078, 0x3a4c, 0x7828,
-	0xa086, 0x1834, 0x00c0, 0x3a70, 0xa185, 0x0004, 0x0078, 0x3a77,
-	0x7828, 0xa186, 0x1814, 0x00c0, 0x3a64, 0xa185, 0x000c, 0x784a,
-	0x789b, 0x000e, 0x78ab, 0x0002, 0x7858, 0xa084, 0x00ff, 0xa085,
-	0x0400, 0x785a, 0x70b4, 0xa080, 0x0091, 0x781a, 0x6827, 0x0002,
-	0x6827, 0x0084, 0x2009, 0x0004, 0x2001, 0x0000, 0x1078, 0x457e,
-	0x127f, 0x007c, 0x0d7e, 0x6b14, 0x1078, 0x1be0, 0x0040, 0x3a9f,
-	0x2068, 0x6827, 0x0002, 0x1078, 0x3ac2, 0x0078, 0x3a94, 0x0d7f,
-	0x007c, 0x0d7e, 0x6b14, 0x6c28, 0xa4a4, 0x00ff, 0x1078, 0x1b7e,
-	0x0040, 0x3aaf, 0x2068, 0x6827, 0x0002, 0x1078, 0x3ac2, 0x0d7f,
-	0x007c, 0x0d7e, 0x6b14, 0xa39c, 0x00ff, 0x1078, 0x1bb1, 0x0040,
-	0x3ac0, 0x2068, 0x6827, 0x0002, 0x1078, 0x3ac2, 0x0078, 0x3ab5,
-	0x0d7f, 0x007c, 0x0c7e, 0x6914, 0x1078, 0x3b33, 0x6904, 0xa18c,
-	0x00ff, 0xa186, 0x0006, 0x0040, 0x3add, 0xa186, 0x000d, 0x0040,
-	0x3afc, 0xa186, 0x0017, 0x00c0, 0x3ad9, 0x1078, 0x193d, 0x0078,
-	0x3adb, 0x1078, 0x1c55, 0x0c7f, 0x007c, 0x6004, 0x8001, 0x0048,
-	0x3afa, 0x6006, 0x2009, 0x0000, 0xa684, 0x0001, 0x00c0, 0x3aea,
-	0xa18d, 0x8000, 0xa684, 0x0004, 0x0040, 0x3af0, 0xa18d, 0x0002,
-	0x691e, 0x6823, 0x0000, 0x7104, 0x810f, 0x6818, 0xa105, 0x681a,
-	0x0078, 0x3ad9, 0x1078, 0x23ca, 0x6018, 0xa005, 0x00c0, 0x3b0b,
-	0x6008, 0x8001, 0x0048, 0x3b0b, 0x600a, 0x601c, 0x6802, 0x2d00,
-	0x601e, 0x0078, 0x3b21, 0xac88, 0x0006, 0x2104, 0xa005, 0x0040,
-	0x3b14, 0x2008, 0x0078, 0x3b0d, 0x6802, 0x2d0a, 0x6008, 0x8001,
-	0x0048, 0x3adb, 0x600a, 0x6018, 0x2068, 0x6800, 0x601a, 0x0078,
-	0x3b05, 0x157e, 0x137e, 0x147e, 0x0c7e, 0x0d7e, 0x1078, 0x191a,
-	0x2da0, 0x137f, 0x20a9, 0x0031, 0x53a3, 0x0c7f, 0x147f, 0x137f,
-	0x157f, 0x0078, 0x3ad9, 0xa184, 0x001f, 0x8003, 0x8003, 0x8003,
-	0xa080, 0x7410, 0x2060, 0x007c, 0x2019, 0x5051, 0x2304, 0xa085,
-	0x0001, 0x201a, 0x2019, 0x0102, 0x2304, 0xa085, 0x0001, 0x201a,
-	0x007c, 0x2019, 0x5051, 0x2304, 0xa084, 0xfffe, 0x201a, 0x2019,
-	0x0102, 0x2304, 0xa084, 0xfffe, 0x201a, 0x007c, 0x7990, 0xa18c,
-	0xfff8, 0x7992, 0x70b4, 0xa080, 0x00d8, 0x781a, 0x0078, 0x2438,
-	0x70a3, 0x0000, 0x7003, 0x0000, 0x7043, 0x0001, 0x7037, 0x0000,
-	0x0018, 0x23ef, 0x1078, 0x1b6e, 0x0040, 0x3b91, 0x2009, 0x500f,
-	0x200b, 0x0000, 0x68bc, 0x2060, 0x6100, 0xa184, 0x0300, 0x0040,
-	0x3b85, 0x6827, 0x000e, 0xa084, 0x0200, 0x0040, 0x3b81, 0x6827,
-	0x0017, 0x1078, 0x3ac2, 0x0078, 0x3b60, 0x7000, 0xa086, 0x0007,
-	0x00c0, 0x3be3, 0x2d00, 0x70a2, 0xad80, 0x000f, 0x7036, 0x0078,
-	0x3b98, 0x7040, 0xa086, 0x0001, 0x0040, 0x2471, 0x0078, 0x2438,
-	0x2031, 0x0000, 0x691c, 0xa184, 0x0002, 0x0040, 0x3ba1, 0xa6b5,
-	0x0004, 0xa184, 0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, 0x3c72,
-	0x2004, 0xa635, 0x6820, 0xa084, 0x0400, 0x0040, 0x3bb9, 0x789b,
-	0x0018, 0x78ab, 0x0003, 0x789b, 0x0081, 0x78ab, 0x0001, 0xa6b5,
-	0x1000, 0x6820, 0xa084, 0x8000, 0x0040, 0x3bc5, 0xa6b5, 0x0400,
-	0x789b, 0x000e, 0x6824, 0x8007, 0x78aa, 0xa684, 0x0200, 0x0040,
-	0x3bdf, 0x682c, 0x78d2, 0x6830, 0x78d6, 0xa684, 0x0100, 0x0040,
-	0x3bdd, 0x682c, 0xa084, 0x0001, 0x0040, 0x3bdd, 0x7888, 0xa084,
-	0x0040, 0x0040, 0x3bdd, 0xa6b5, 0x8000, 0x1078, 0x45ad, 0x7e5a,
-	0x6eb6, 0x0078, 0x45e4, 0x1078, 0x38c6, 0x00c0, 0x3c6c, 0x702c,
-	0x8004, 0x0048, 0x3bf1, 0x2019, 0x4cfd, 0x1078, 0x2255, 0x702f,
-	0x0001, 0x2011, 0x0001, 0x2031, 0x1000, 0x789b, 0x0018, 0x6814,
-	0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, 0x691c, 0xa184, 0x0002,
-	0x0040, 0x3c0a, 0xa6b5, 0x0004, 0x78ab, 0x0020, 0x6828, 0x78aa,
-	0xa290, 0x0002, 0x6820, 0xa084, 0x8000, 0x0040, 0x3c18, 0xa6b5,
-	0x0400, 0x789b, 0x000e, 0x6824, 0x8007, 0x78aa, 0x0078, 0x3c26,
-	0x681c, 0xa084, 0x8000, 0x00c0, 0x3c26, 0xa6b5, 0x0800, 0x6820,
-	0xa084, 0x0100, 0x0040, 0x3c26, 0xa6b5, 0x4000, 0x681c, 0xa084,
-	0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, 0x3c72, 0x2004, 0xa635,
-	0xa684, 0x0100, 0x0040, 0x3c40, 0x682c, 0xa084, 0x0001, 0x0040,
-	0x3c40, 0x7888, 0xa084, 0x0040, 0x0040, 0x3c40, 0xa6b5, 0x8000,
-	0x789b, 0x007e, 0x7eae, 0x6eb6, 0x6814, 0x8007, 0x78aa, 0x7882,
-	0x7aaa, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3c6c, 0x0018, 0x3c6c,
-	0x70b4, 0xa080, 0x00dd, 0x781a, 0x1078, 0x38de, 0xa684, 0x0200,
-	0x0040, 0x3c60, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x1078, 0x45ad,
-	0x2d00, 0x70a2, 0x704a, 0x6810, 0x70be, 0x7003, 0x0007, 0xad80,
-	0x000f, 0x7036, 0x0078, 0x2438, 0x1078, 0x1b45, 0x1078, 0x38de,
-	0x0078, 0x2438, 0x0000, 0x0300, 0x0200, 0x0000, 0x1078, 0x23ca,
-	0x2300, 0x0079, 0x3c7b, 0x3c7e, 0x3c7e, 0x3c80, 0x1078, 0x23ca,
-	0x1078, 0x45bc, 0x6924, 0xa184, 0x00ff, 0xa086, 0x000a, 0x0040,
-	0x3c92, 0xa184, 0xff00, 0xa085, 0x000a, 0x6826, 0x1078, 0x1b45,
-	0x0078, 0x3b60, 0x2001, 0x000a, 0x1078, 0x454c, 0x0078, 0x3b60,
-	0xa282, 0x0005, 0x0050, 0x3c9e, 0x1078, 0x23ca, 0x7000, 0xa084,
-	0x0007, 0x10c0, 0x398a, 0x1078, 0x191a, 0x00c0, 0x3cbd, 0xa684,
-	0x0004, 0x0040, 0x3caf, 0x2001, 0x2800, 0x0078, 0x3cb1, 0x2001,
-	0x0800, 0x71b4, 0xa188, 0x0091, 0x789b, 0x000e, 0x78aa, 0x2031,
-	0x0400, 0x7e5a, 0x791a, 0x0078, 0x2438, 0x6807, 0x0106, 0x680b,
-	0x0000, 0x689f, 0x0000, 0x6827, 0x0000, 0xa386, 0x0002, 0x00c0,
-	0x3cde, 0xa286, 0x0002, 0x00c0, 0x3cde, 0x78a0, 0xa005, 0x00c0,
-	0x3cde, 0xa484, 0x8000, 0x00c0, 0x3cde, 0x78e4, 0xa084, 0x0008,
-	0x0040, 0x3cde, 0xa6b5, 0x0008, 0x2019, 0x0000, 0x1078, 0x40d3,
-	0x2d00, 0x70a2, 0x704a, 0x7003, 0x0007, 0x7037, 0x0000, 0x6824,
-	0xa084, 0x0080, 0x0040, 0x3cf0, 0x1078, 0x4180, 0x0078, 0x2438,
-	0x2300, 0x0079, 0x3cf3, 0x3cf6, 0x3d77, 0x3d96, 0x2200, 0x0079,
-	0x3cf9, 0x3cfe, 0x3d0e, 0x3d34, 0x3d40, 0x3d63, 0x2029, 0x0001,
-	0xa026, 0x2011, 0x0000, 0x1078, 0x428d, 0x0079, 0x3d07, 0x3d0c,
-	0x2438, 0x3b60, 0x3d0c, 0x3d0c, 0x1078, 0x23ca, 0x7990, 0xa18c,
-	0x0007, 0x00c0, 0x3d15, 0x2009, 0x0008, 0x2011, 0x0001, 0xa684,
-	0x0004, 0x0040, 0x3d1d, 0x2011, 0x0003, 0x2220, 0xa12a, 0x2011,
-	0x0001, 0x1078, 0x428d, 0x0079, 0x3d25, 0x3d2a, 0x2438, 0x3b60,
-	0x3d32, 0x3d2c, 0x0078, 0x45ea, 0x70ab, 0x3d30, 0x0078, 0x2438,
-	0x0078, 0x3d2a, 0x1078, 0x23ca, 0xa684, 0x0010, 0x0040, 0x3d3e,
-	0x1078, 0x414f, 0x0040, 0x3d3e, 0x0078, 0x2438, 0x0078, 0x41bc,
-	0x6000, 0xa084, 0x0002, 0x0040, 0x3d5d, 0x70b4, 0xa080, 0x00cd,
-	0x781a, 0x0d7e, 0x1078, 0x45c5, 0x2d00, 0x682e, 0x6827, 0x0000,
-	0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x193d, 0x7003, 0x0000, 0x7037,
-	0x0000, 0x704b, 0x0000, 0x0078, 0x3b60, 0xa684, 0x0004, 0x00c0,
-	0x3d63, 0x0078, 0x45ea, 0x6000, 0xa084, 0x0004, 0x00c0, 0x3d75,
-	0x6000, 0xa084, 0x0001, 0x0040, 0x3d75, 0x70ab, 0x3d75, 0x2001,
-	0x0007, 0x1078, 0x4544, 0x0078, 0x45f0, 0x0078, 0x45ea, 0x2200,
-	0x0079, 0x3d7a, 0x3d7f, 0x3d7f, 0x3d7f, 0x3d81, 0x3d7f, 0x1078,
-	0x23ca, 0x70a7, 0x3d85, 0x0078, 0x45f6, 0x2011, 0x0018, 0x1078,
-	0x4287, 0x0079, 0x3d8b, 0x3d90, 0x2438, 0x3b60, 0x3d92, 0x3d94,
-	0x1078, 0x23ca, 0x1078, 0x23ca, 0x1078, 0x23ca, 0x2200, 0x0079,
-	0x3d99, 0x3d9e, 0x3da0, 0x3da0, 0x3d9e, 0x3d9e, 0x1078, 0x23ca,
-	0x78e4, 0xa084, 0x0008, 0x0040, 0x3db5, 0x70a7, 0x3da9, 0x0078,
-	0x45f6, 0x2011, 0x0004, 0x1078, 0x4287, 0x0079, 0x3daf, 0x3db5,
-	0x2438, 0x3b60, 0x3db5, 0x3dbf, 0x3dc3, 0x70ab, 0x3dbd, 0x2001,
-	0x0003, 0x1078, 0x4544, 0x0078, 0x45f0, 0x0078, 0x45ea, 0x70ab,
-	0x3db5, 0x0078, 0x2438, 0x70ab, 0x3dc7, 0x0078, 0x2438, 0x0078,
-	0x3dbd, 0xa282, 0x0003, 0x0050, 0x3dcf, 0x1078, 0x23ca, 0xa386,
-	0x0002, 0x00c0, 0x3de8, 0xa286, 0x0002, 0x00c0, 0x3dee, 0x78a0,
-	0xa005, 0x00c0, 0x3dee, 0xa484, 0x8000, 0x00c0, 0x3dee, 0x78e4,
-	0xa084, 0x0008, 0x0040, 0x3de8, 0xa6b5, 0x0008, 0x2019, 0x0000,
-	0xa684, 0x0008, 0x0040, 0x3dee, 0x1078, 0x412c, 0x6810, 0x70be,
-	0x7003, 0x0007, 0x2300, 0x0079, 0x3df5, 0x3df8, 0x3e25, 0x3e2d,
-	0x2200, 0x0079, 0x3dfb, 0x3e00, 0x3dfe, 0x3e19, 0x1078, 0x23ca,
-	0x7990, 0xa1ac, 0x0007, 0xa026, 0x2011, 0x0001, 0x1078, 0x428d,
-	0x0079, 0x3e0a, 0x3e0f, 0x2438, 0x3b60, 0x3e17, 0x3e11, 0x0078,
-	0x45ea, 0x70ab, 0x3e15, 0x0078, 0x2438, 0x0078, 0x3e0f, 0x1078,
-	0x23ca, 0xa684, 0x0010, 0x0040, 0x3e23, 0x1078, 0x414f, 0x0040,
-	0x3e23, 0x0078, 0x2438, 0x0078, 0x41bc, 0x2200, 0x0079, 0x3e28,
-	0x3e2b, 0x3e2b, 0x3e2b, 0x1078, 0x23ca, 0x2200, 0x0079, 0x3e30,
-	0x3e33, 0x3e35, 0x3e35, 0x1078, 0x23ca, 0x78e4, 0xa084, 0x0008,
-	0x0040, 0x3e4a, 0x70a7, 0x3e3e, 0x0078, 0x45f6, 0x2011, 0x0004,
-	0x1078, 0x4287, 0x0079, 0x3e44, 0x3e4a, 0x2438, 0x3b60, 0x3e4a,
-	0x3e54, 0x3e58, 0x70ab, 0x3e52, 0x2001, 0x0003, 0x1078, 0x4544,
-	0x0078, 0x45f0, 0x0078, 0x45ea, 0x70ab, 0x3e4a, 0x0078, 0x2438,
-	0x70ab, 0x3e5c, 0x0078, 0x2438, 0x0078, 0x3e52, 0x2300, 0x0079,
-	0x3e61, 0x3e66, 0x3e68, 0x3e64, 0x1078, 0x23ca, 0x70a4, 0x007a,
-	0x70a4, 0x007a, 0xa282, 0x0002, 0x0050, 0x3e70, 0x1078, 0x23ca,
-	0xa684, 0x0200, 0x0040, 0x3e7a, 0x1078, 0x45b5, 0x1078, 0x426f,
-	0x1078, 0x45bc, 0x2300, 0x0079, 0x3e7d, 0x3e80, 0x3ea4, 0x3f0a,
-	0xa286, 0x0001, 0x0040, 0x3e86, 0x1078, 0x23ca, 0xa684, 0x0200,
-	0x0040, 0x3e8e, 0x1078, 0x45b5, 0x1078, 0x45bc, 0x2001, 0x0001,
-	0x1078, 0x454c, 0x78b8, 0xa084, 0xc001, 0x0040, 0x3ea0, 0x7848,
-	0xa085, 0x0008, 0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3e9b,
-	0x7003, 0x0000, 0x0078, 0x3b60, 0x2200, 0x0079, 0x3ea7, 0x3ea9,
-	0x3eda, 0x70a7, 0x3ead, 0x0078, 0x45f6, 0x2011, 0x000d, 0x1078,
-	0x4287, 0x0079, 0x3eb3, 0x3eba, 0x2438, 0x3b60, 0x3ec2, 0x3eca,
-	0x3ed0, 0x3ed2, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
-	0x0078, 0x45e4, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
-	0x0078, 0x45e4, 0x70ab, 0x3ece, 0x0078, 0x2438, 0x0078, 0x3eba,
-	0x1078, 0x23ca, 0x70ab, 0x3ed6, 0x0078, 0x2438, 0x1078, 0x45fc,
-	0x0078, 0x2438, 0x70a7, 0x3ede, 0x0078, 0x45f6, 0x2011, 0x0012,
-	0x1078, 0x4287, 0x0079, 0x3ee4, 0x3eea, 0x2438, 0x3b60, 0x3ef6,
-	0x3efe, 0x3f04, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
-	0x70b4, 0xa080, 0x00a5, 0x781a, 0x0078, 0x2438, 0xa6b4, 0x00ff,
-	0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, 0x70ab, 0x3f02,
-	0x0078, 0x2438, 0x0078, 0x3eea, 0x70ab, 0x3f08, 0x0078, 0x2438,
-	0x0078, 0x3ef6, 0xa286, 0x0001, 0x0040, 0x3f10, 0x1078, 0x23ca,
-	0x70a7, 0x3f14, 0x0078, 0x45f6, 0x2011, 0x0015, 0x1078, 0x4287,
-	0x0079, 0x3f1a, 0x3f1f, 0x2438, 0x3b60, 0x3f2d, 0x3f39, 0xa6b4,
-	0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x783b, 0x1301, 0x70b4,
-	0xa080, 0x00b5, 0x781a, 0x0078, 0x2438, 0xa6b4, 0x00ff, 0xa6b5,
-	0x0400, 0x6eb6, 0x7e5a, 0x70b4, 0xa080, 0x00a5, 0x781a, 0x0078,
-	0x2438, 0x70ab, 0x3f3d, 0x0078, 0x2438, 0x0078, 0x3f1f, 0xa282,
-	0x0003, 0x0050, 0x3f45, 0x1078, 0x23ca, 0x2300, 0x0079, 0x3f48,
-	0x3f4b, 0x3f82, 0x3fdd, 0xa286, 0x0001, 0x0040, 0x3f51, 0x1078,
-	0x23ca, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x3f5e,
-	0x1078, 0x3ac2, 0x7003, 0x0000, 0x0078, 0x3b60, 0x683b, 0x0000,
-	0x6837, 0x0000, 0xa684, 0x0200, 0x0040, 0x3f6c, 0x1078, 0x45b5,
-	0x1078, 0x426f, 0x1078, 0x45bc, 0x2001, 0x0001, 0x1078, 0x454c,
-	0x78b8, 0xa084, 0xc001, 0x0040, 0x3f7e, 0x7848, 0xa085, 0x0008,
-	0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3f79, 0x7003, 0x0000,
-	0x0078, 0x3b60, 0x2200, 0x0079, 0x3f85, 0x3f87, 0x3fb8, 0x70a7,
-	0x3f8b, 0x0078, 0x45f6, 0x2011, 0x000d, 0x1078, 0x4287, 0x0079,
-	0x3f91, 0x3f98, 0x2438, 0x3b60, 0x3fa0, 0x3fa8, 0x3fae, 0x3fb0,
-	0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4,
-	0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4,
-	0x70ab, 0x3fac, 0x0078, 0x2438, 0x0078, 0x3f98, 0x1078, 0x23ca,
-	0x70ab, 0x3fb4, 0x0078, 0x2438, 0x1078, 0x45fc, 0x0078, 0x2438,
-	0x70a7, 0x3fbc, 0x0078, 0x45f6, 0x2011, 0x0005, 0x1078, 0x4287,
-	0x0079, 0x3fc2, 0x3fc7, 0x2438, 0x3b60, 0x3fcf, 0x3fd7, 0xa6b4,
-	0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, 0xa6b4,
-	0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, 0x70ab,
-	0x3fdb, 0x0078, 0x2438, 0x0078, 0x3fc7, 0xa286, 0x0001, 0x0040,
-	0x3fe3, 0x1078, 0x23ca, 0x70a7, 0x3fe7, 0x0078, 0x45f6, 0x2011,
-	0x0006, 0x1078, 0x4287, 0x0079, 0x3fed, 0x3ff2, 0x2438, 0x3b60,
-	0x3ff8, 0x4002, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4,
-	0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0xa6b5, 0x4000, 0x7e5a,
-	0x0078, 0x45e4, 0x70ab, 0x4006, 0x0078, 0x2438, 0x0078, 0x3ff2,
-	0x2300, 0x0079, 0x400b, 0x4010, 0x400e, 0x400e, 0x1078, 0x23ca,
-	0x1078, 0x23ca, 0x2300, 0x71a8, 0xa005, 0x017a, 0x6810, 0x70be,
-	0xa282, 0x0003, 0x0050, 0x401e, 0x1078, 0x23ca, 0x2300, 0x0079,
-	0x4021, 0x4024, 0x4037, 0x4059, 0x82ff, 0x00c0, 0x4029, 0x1078,
-	0x23ca, 0xa684, 0x0200, 0x0040, 0x4031, 0x1078, 0x45b5, 0x1078,
-	0x45bc, 0x2001, 0x0001, 0x1078, 0x454c, 0x0078, 0x2438, 0xa296,
-	0x0002, 0x0040, 0x4040, 0x82ff, 0x0040, 0x4040, 0x1078, 0x23ca,
-	0x70a7, 0x4044, 0x0078, 0x45f6, 0x2011, 0x0018, 0x1078, 0x4287,
-	0x0079, 0x404a, 0x404f, 0x2438, 0x3b60, 0x4051, 0x4053, 0x0078,
-	0x45e4, 0x0078, 0x45e4, 0x70ab, 0x4057, 0x0078, 0x2438, 0x0078,
-	0x404f, 0x2200, 0x0079, 0x405c, 0x405e, 0x4077, 0x70a7, 0x4062,
-	0x0078, 0x45f6, 0x2011, 0x0017, 0x1078, 0x4287, 0x0079, 0x4068,
-	0x406d, 0x2438, 0x3b60, 0x406f, 0x4071, 0x0078, 0x45e4, 0x0078,
-	0x45e4, 0x70ab, 0x4075, 0x0078, 0x2438, 0x0078, 0x406d, 0xa484,
-	0x8000, 0x00c0, 0x40c1, 0xa684, 0x0100, 0x0040, 0x408b, 0x1078,
-	0x45b5, 0x1078, 0x426f, 0x1078, 0x45bc, 0x7848, 0xa085, 0x000c,
-	0x784a, 0x0078, 0x408f, 0x78d8, 0x78d2, 0x78dc, 0x78d6, 0xa6b4,
-	0xefff, 0x7e5a, 0x70a7, 0x4096, 0x0078, 0x45f6, 0x2011, 0x000d,
-	0x1078, 0x4287, 0x0079, 0x409c, 0x40a3, 0x2438, 0x3b60, 0x40a3,
-	0x40b1, 0x40b7, 0x40b9, 0xa684, 0x0100, 0x0040, 0x40af, 0x1078,
-	0x4573, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x1078, 0x45ad, 0x0078,
-	0x45e4, 0x70ab, 0x40b5, 0x0078, 0x2438, 0x0078, 0x40a3, 0x1078,
-	0x23ca, 0x70ab, 0x40bd, 0x0078, 0x2438, 0x1078, 0x45fc, 0x0078,
-	0x2438, 0x1078, 0x45bc, 0x70ab, 0x40cb, 0x2001, 0x0003, 0x1078,
-	0x4544, 0x0078, 0x45f0, 0x1078, 0x45ad, 0x682c, 0x78d2, 0x6830,
-	0x78d6, 0x0078, 0x45e4, 0x70b8, 0x6812, 0x70be, 0x8000, 0x70ba,
-	0x681b, 0x0000, 0xa684, 0x0008, 0x0040, 0x40f6, 0x157e, 0x137e,
-	0x147e, 0x7890, 0x8004, 0x8004, 0x8004, 0x8004, 0xa084, 0x000f,
-	0x681a, 0x80ac, 0x789b, 0x0000, 0xaf80, 0x002b, 0x2098, 0xad80,
-	0x000b, 0x20a0, 0x53a5, 0x147f, 0x137f, 0x157f, 0xa6c4, 0x0f00,
-	0xa684, 0x0002, 0x00c0, 0x4102, 0x692c, 0x810d, 0x810d, 0x810d,
-	0x0078, 0x410f, 0x789b, 0x0010, 0x79ac, 0x0078, 0x410f, 0x017e,
-	0x2009, 0x0005, 0x2001, 0x3d00, 0x1078, 0x457e, 0x017f, 0xa184,
-	0x001f, 0xa805, 0x6816, 0x1078, 0x3b33, 0x68be, 0xa684, 0x0004,
-	0x0040, 0x4120, 0xa18c, 0xff00, 0x78a8, 0xa084, 0x00ff, 0xa105,
-	0x682a, 0xa6b4, 0x00ff, 0x6000, 0xa084, 0x0008, 0x0040, 0x412a,
-	0xa6b5, 0x4000, 0x6eb6, 0x007c, 0x157e, 0x137e, 0x147e, 0x6918,
-	0x7890, 0x8004, 0x8004, 0x8004, 0x8004, 0xa084, 0x000f, 0x007e,
-	0xa100, 0x681a, 0x007f, 0x8000, 0x8004, 0x0040, 0x414b, 0x20a8,
-	0x8104, 0xa080, 0x000b, 0xad00, 0x20a0, 0x789b, 0x0000, 0xaf80,
-	0x002b, 0x2098, 0x53a5, 0x147f, 0x137f, 0x157f, 0x007c, 0x682c,
-	0xa084, 0x0020, 0x00c0, 0x4157, 0x620c, 0x0078, 0x4158, 0x6210,
-	0x6b18, 0x2300, 0xa202, 0x0040, 0x4178, 0x2018, 0xa382, 0x000e,
-	0x0048, 0x4168, 0x0040, 0x4168, 0x2019, 0x000e, 0x0078, 0x416c,
-	0x7858, 0xa084, 0xffef, 0x785a, 0x783b, 0x1b01, 0x7893, 0x0000,
-	0x7ba2, 0x70b4, 0xa080, 0x008e, 0x781a, 0xa085, 0x0001, 0x007c,
-	0x7858, 0xa084, 0xffef, 0x785a, 0x7893, 0x0000, 0xa006, 0x007c,
-	0x6904, 0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x418d, 0xa196,
-	0x000f, 0x0040, 0x418d, 0x6807, 0x0117, 0x6914, 0x1078, 0x3b33,
-	0x6100, 0x8104, 0x00c8, 0x41a8, 0x601c, 0xa005, 0x0040, 0x419c,
-	0x2001, 0x0800, 0x0078, 0x41aa, 0x0d7e, 0x6824, 0x007e, 0x1078,
-	0x45c5, 0x007f, 0x6826, 0x2d00, 0x682e, 0x1078, 0x3ac2, 0x0d7f,
-	0x2001, 0x0200, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820,
-	0xa085, 0x8000, 0x6822, 0x2031, 0x0400, 0x6eb6, 0x7e5a, 0x71b4,
-	0xa188, 0x0091, 0x791a, 0x007c, 0xa6c4, 0x0f00, 0xa684, 0x0002,
-	0x00c0, 0x41cf, 0x692c, 0x810d, 0x810d, 0x810d, 0xa184, 0x001f,
-	0xa805, 0x6816, 0x1078, 0x3b33, 0x68be, 0x0078, 0x41d2, 0x6914,
-	0x1078, 0x3b33, 0x6100, 0x8104, 0x00c8, 0x421c, 0xa184, 0x0300,
-	0x0040, 0x41de, 0x6807, 0x0117, 0x0078, 0x41fc, 0x6004, 0xa005,
-	0x00c0, 0x4205, 0x6807, 0x0117, 0x601c, 0xa005, 0x00c0, 0x41f2,
-	0x0d7e, 0x1078, 0x45c5, 0x6827, 0x0034, 0x2d00, 0x682e, 0x1078,
-	0x3ac2, 0x0d7f, 0xa684, 0x0004, 0x0040, 0x41fc, 0x2031, 0x0400,
-	0x2001, 0x2800, 0x0078, 0x4200, 0x2031, 0x0400, 0x2001, 0x0800,
-	0x71b4, 0xa188, 0x0091, 0x0078, 0x424a, 0x6018, 0xa005, 0x00c0,
-	0x41f2, 0x601c, 0xa005, 0x00c0, 0x41f2, 0x689f, 0x0000, 0x6827,
-	0x003d, 0xa684, 0x0001, 0x0040, 0x4258, 0xa6b5, 0x0800, 0x71b4,
-	0xa188, 0x00ae, 0x0078, 0x4253, 0x6807, 0x0117, 0x2031, 0x0400,
-	0x692c, 0xa18c, 0x00ff, 0xa186, 0x0012, 0x00c0, 0x422d, 0x2001,
-	0x4265, 0x2009, 0x0001, 0x0078, 0x423e, 0xa186, 0x0003, 0x00c0,
-	0x4237, 0x2001, 0x4266, 0x2009, 0x0012, 0x0078, 0x423e, 0x2001,
-	0x0200, 0x71b4, 0xa188, 0x0091, 0x0078, 0x424a, 0x1078, 0x4598,
-	0x78a3, 0x0000, 0x681c, 0xa085, 0x0040, 0x681e, 0x71b4, 0xa188,
-	0x00da, 0xa006, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820,
-	0xa085, 0x8000, 0x6822, 0x6eb6, 0x7e5a, 0x791a, 0x0078, 0x2438,
-	0x6eb6, 0x1078, 0x3ac2, 0x6810, 0x70be, 0x7003, 0x0007, 0x70a3,
-	0x0000, 0x704b, 0x0000, 0x0078, 0x2438, 0x0023, 0x0070, 0x0005,
-	0x0000, 0x0a00, 0x0000, 0x0000, 0x0025, 0x0000, 0x0000, 0x683b,
-	0x0000, 0x6837, 0x0000, 0xa684, 0x0200, 0x0040, 0x4286, 0x78b8,
-	0xa08c, 0x001f, 0xa084, 0x8000, 0x0040, 0x427f, 0x8108, 0x78d8,
-	0xa100, 0x6836, 0x78dc, 0xa081, 0x0000, 0x683a, 0x007c, 0x7990,
-	0x810f, 0xa5ac, 0x0007, 0x2021, 0x0000, 0xa480, 0x0010, 0x789a,
-	0x79a8, 0xa18c, 0x00ff, 0xa184, 0x0080, 0x00c0, 0x42b5, 0xa182,
-	0x0020, 0x00c8, 0x42cf, 0xa182, 0x0012, 0x00c8, 0x4536, 0x2100,
-	0x1079, 0x42a3, 0x007c, 0x4536, 0x447e, 0x4536, 0x4536, 0x42dc,
-	0x42df, 0x4319, 0x434f, 0x4381, 0x4384, 0x4536, 0x4536, 0x433a,
-	0x43a8, 0x43e2, 0x4536, 0x4536, 0x4409, 0xa18c, 0x001f, 0x6814,
-	0xa084, 0x001f, 0xa106, 0x0040, 0x42cc, 0x70b4, 0xa080, 0x00cd,
-	0x781a, 0x2001, 0x0014, 0x1078, 0x454c, 0x1078, 0x45bc, 0x7003,
-	0x0000, 0x2001, 0x0002, 0x007c, 0x2001, 0x0000, 0x007c, 0xa182,
-	0x0024, 0x00c8, 0x4536, 0xa184, 0x0003, 0x1079, 0x42a3, 0x007c,
-	0x4536, 0x4536, 0x4536, 0x4536, 0x1078, 0x4536, 0x007c, 0x2200,
-	0x0079, 0x42e2, 0x440c, 0x440c, 0x4306, 0x4306, 0x4306, 0x4306,
-	0x4306, 0x4306, 0x4306, 0x4306, 0x4304, 0x4306, 0x42fb, 0x4306,
-	0x4306, 0x4306, 0x4306, 0x4306, 0x430e, 0x4311, 0x440c, 0x4311,
-	0x4306, 0x4306, 0x4306, 0x0c7e, 0x077e, 0x6f14, 0x1078, 0x36b0,
-	0x077f, 0x0c7f, 0x0078, 0x4306, 0x1078, 0x44d1, 0x6827, 0x02b3,
-	0x2009, 0x000b, 0x2001, 0x4800, 0x0078, 0x4440, 0x1078, 0x452b,
-	0x007c, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4800, 0x0078,
-	0x4428, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0,
-	0x4323, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078, 0x45c5, 0x6827,
-	0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3a92, 0x1078,
-	0x4466, 0x2b68, 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x3ac2, 0x2001,
-	0x0002, 0x007c, 0x1078, 0x4466, 0x2001, 0x0017, 0x1078, 0x454c,
-	0x70a3, 0x0000, 0x2009, 0x5038, 0x200b, 0x0006, 0x70af, 0x0017,
-	0x2009, 0x0200, 0x1078, 0x39d2, 0x2001, 0x0001, 0x007c, 0x2200,
-	0x0079, 0x4352, 0x440c, 0x443d, 0x443d, 0x443d, 0x4373, 0x444d,
-	0x4379, 0x444d, 0x444d, 0x4450, 0x4450, 0x4455, 0x4455, 0x436b,
-	0x436b, 0x443d, 0x443d, 0x444d, 0x443d, 0x4379, 0x440c, 0x4379,
-	0x4379, 0x4379, 0x4379, 0x6827, 0x0084, 0x2009, 0x000b, 0x2001,
-	0x4300, 0x0078, 0x445f, 0x2009, 0x000b, 0x2001, 0x4300, 0x0078,
-	0x4440, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4300, 0x0078,
-	0x4428, 0x2001, 0x0000, 0x007c, 0x2200, 0x0079, 0x4387, 0x440c,
-	0x43a0, 0x43a0, 0x43a0, 0x43a0, 0x444d, 0x444d, 0x444d, 0x444d,
-	0x444d, 0x444d, 0x444d, 0x444d, 0x43a0, 0x43a0, 0x43a0, 0x43a0,
-	0x444d, 0x43a0, 0x43a0, 0x444d, 0x444d, 0x444d, 0x444d, 0x440c,
-	0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4300, 0x0078, 0x4428,
-	0xa684, 0x0004, 0x00c0, 0x43bc, 0x6804, 0xa084, 0x00ff, 0xa086,
-	0x0006, 0x00c0, 0x4536, 0x1078, 0x4466, 0x6807, 0x0117, 0x1078,
-	0x3ac2, 0x2001, 0x0002, 0x007c, 0x6000, 0xa084, 0x0004, 0x0040,
-	0x4536, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0,
-	0x43cb, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078, 0x45c5, 0x6827,
-	0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3aa1, 0x1078,
-	0x4466, 0x2b68, 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x3ac2, 0x2001,
-	0x0002, 0x007c, 0x6000, 0xa084, 0x0004, 0x0040, 0x4536, 0x2d58,
-	0x6a04, 0xa294, 0x00ff, 0xa286, 0x0006, 0x00c0, 0x43f1, 0x6807,
-	0x0117, 0x6827, 0x0002, 0x2d58, 0x1078, 0x45c5, 0x6827, 0x0036,
-	0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3ab1, 0x1078, 0x4466,
-	0x2b68, 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x3ac2, 0x2001, 0x0002,
-	0x007c, 0x1078, 0x4536, 0x007c, 0x70b4, 0xa080, 0x00cd, 0x781a,
-	0x2001, 0x0001, 0x1078, 0x454c, 0x1078, 0x45bc, 0x7003, 0x0000,
-	0x2001, 0x0002, 0x007c, 0x1078, 0x457e, 0x1078, 0x45b5, 0x1078,
-	0x426f, 0x1078, 0x4180, 0x1078, 0x45bc, 0x2001, 0x0001, 0x007c,
-	0x1078, 0x457e, 0x1078, 0x45b5, 0x1078, 0x426f, 0x70b4, 0xa080,
-	0x00cd, 0x781a, 0x2001, 0x0013, 0x1078, 0x454c, 0x1078, 0x45bc,
-	0x7003, 0x0000, 0x2001, 0x0002, 0x007c, 0x1078, 0x4536, 0x007c,
-	0x1078, 0x457e, 0x1078, 0x45b5, 0x1078, 0x426f, 0x1078, 0x4180,
-	0x1078, 0x45bc, 0x2001, 0x0001, 0x007c, 0x2001, 0x0003, 0x007c,
-	0x1078, 0x44d1, 0x2001, 0x0000, 0x007c, 0x0c7e, 0x077e, 0x6f14,
-	0x1078, 0x36b0, 0x077f, 0x0c7f, 0x2001, 0x0000, 0x007c, 0x1078,
-	0x457e, 0x1078, 0x4536, 0x2001, 0x0006, 0x007c, 0x6904, 0xa18c,
-	0x00ff, 0xa186, 0x0007, 0x0040, 0x4471, 0xa186, 0x000f, 0x00c0,
-	0x4475, 0x1078, 0x45b5, 0x1078, 0x426f, 0x70b4, 0xa080, 0x00cd,
-	0x781a, 0x1078, 0x45bc, 0x7003, 0x0000, 0x007c, 0x7aa8, 0xa294,
-	0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x4536,
-	0x1079, 0x448b, 0x007c, 0x4536, 0x448f, 0x4536, 0x44df, 0xa282,
-	0x0003, 0x0040, 0x4496, 0x1078, 0x4536, 0x007c, 0x7da8, 0xa5ac,
-	0x00ff, 0x7ca8, 0xa4a4, 0x00ff, 0xa482, 0x000c, 0x0048, 0x44a4,
-	0x0040, 0x44a4, 0x2021, 0x000c, 0x701c, 0xa502, 0x00c8, 0x44a9,
-	0x751c, 0x1078, 0x451c, 0x852b, 0x852b, 0x1078, 0x372e, 0x0040,
-	0x44b5, 0x1078, 0x44c3, 0x0078, 0x44b9, 0x1078, 0x4518, 0x1078,
-	0x44d1, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9, 0x781a,
-	0x2001, 0x0004, 0x007c, 0x0c7e, 0x6914, 0x810f, 0xa18c, 0x000f,
-	0x810b, 0x810b, 0x810b, 0xa1e0, 0x5280, 0x1078, 0x3538, 0x0c7f,
-	0x007c, 0x0c7e, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003,
-	0x8003, 0xa0e0, 0x5280, 0x1078, 0x355f, 0x0c7f, 0x007c, 0xa282,
-	0x0002, 0x00c0, 0x4536, 0x7aa8, 0xa294, 0x00ff, 0xa284, 0xfffe,
-	0x0040, 0x44ec, 0x2011, 0x0001, 0x1078, 0x450a, 0x1078, 0x44fc,
-	0x1078, 0x44d1, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9,
-	0x781a, 0x2001, 0x0004, 0x007c, 0x0c7e, 0x6814, 0x8007, 0xa084,
-	0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0, 0x5280, 0x1078, 0x3604,
-	0x0c7f, 0x007c, 0x789b, 0x0018, 0x78ab, 0x0001, 0x78ab, 0x0002,
-	0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0081, 0x78ab, 0x0004, 0x007c,
-	0x2021, 0x0000, 0x2029, 0x0032, 0x789b, 0x0018, 0x78ab, 0x0001,
-	0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7caa, 0x789b, 0x0081,
-	0x78ab, 0x0005, 0x007c, 0x2001, 0x0003, 0x1078, 0x4544, 0x70b4,
-	0xa080, 0x00b9, 0x781a, 0x2001, 0x0005, 0x007c, 0x2001, 0x0007,
-	0x1078, 0x4544, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9,
-	0x781a, 0x2001, 0x0004, 0x007c, 0x789b, 0x0018, 0x78aa, 0x789b,
-	0x0081, 0x78ab, 0x0001, 0x007c, 0x6904, 0xa18c, 0x00ff, 0xa196,
-	0x0007, 0x0040, 0x455a, 0xa196, 0x000f, 0x0040, 0x455a, 0x1078,
-	0x193d, 0x007c, 0x6924, 0xa194, 0x003f, 0x00c0, 0x4563, 0xa18c,
-	0xffc0, 0xa105, 0x6826, 0x1078, 0x3ac2, 0x691c, 0xa184, 0x0100,
-	0x0040, 0x4572, 0x1078, 0x1b7e, 0x6914, 0x1078, 0x3b33, 0x6204,
-	0x8210, 0x6206, 0x007c, 0x692c, 0x6834, 0x682e, 0xa112, 0x6930,
-	0x6838, 0x6832, 0xa11b, 0xa200, 0xa301, 0x007c, 0x0c7e, 0xade0,
-	0x0018, 0x6003, 0x0070, 0x6106, 0x600b, 0x0000, 0x600f, 0x0a00,
-	0x6013, 0x0000, 0x6017, 0x0000, 0x8007, 0x601a, 0x601f, 0x0000,
-	0x6023, 0x0000, 0x0c7f, 0x6824, 0xa085, 0x0080, 0x6826, 0x007c,
-	0x157e, 0x137e, 0x147e, 0x2098, 0xaf80, 0x002d, 0x20a0, 0x81ac,
-	0x0040, 0x45a3, 0x53a6, 0xa184, 0x0001, 0x0040, 0x45a9, 0x3304,
-	0x78be, 0x147f, 0x137f, 0x157f, 0x007c, 0x70b0, 0xa005, 0x10c0,
-	0x23ca, 0x70b3, 0x8000, 0x0078, 0x48f7, 0x71b0, 0x81ff, 0x0040,
-	0x45bb, 0x1078, 0x49ed, 0x007c, 0x71b0, 0x81ff, 0x0040, 0x45c4,
-	0x70b3, 0x0000, 0x1078, 0x4633, 0x007c, 0x0c7e, 0x0d7e, 0x1078,
-	0x191a, 0x0c7f, 0x157e, 0x137e, 0x147e, 0x2da0, 0x2c98, 0x20a9,
-	0x0031, 0x53a3, 0x147f, 0x137f, 0x157f, 0x6807, 0x010d, 0x680b,
-	0x0000, 0x7004, 0x8007, 0x681a, 0x6823, 0x0000, 0x681f, 0x0000,
-	0x689f, 0x0000, 0x0c7f, 0x007c, 0x70b4, 0xa080, 0x0091, 0x781a,
-	0x0078, 0x2438, 0x70b4, 0xa080, 0x0081, 0x781a, 0x0078, 0x2438,
-	0x70b4, 0xa080, 0x00b9, 0x781a, 0x0078, 0x2438, 0x70b4, 0xa080,
-	0x00c3, 0x781a, 0x0078, 0x2438, 0x6904, 0xa18c, 0x00ff, 0xa196,
-	0x0007, 0x0040, 0x4609, 0xa196, 0x000f, 0x0040, 0x4609, 0x6807,
-	0x0117, 0x2001, 0x0200, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa,
-	0x6820, 0xa085, 0x8000, 0x6822, 0x2031, 0x0400, 0x6eb6, 0x7e5a,
-	0x71b4, 0xa188, 0x0091, 0x791a, 0x007c, 0x1078, 0x45bc, 0x7848,
-	0xa085, 0x000c, 0x784a, 0x70b4, 0xa080, 0x00cd, 0x781a, 0x2009,
-	0x000b, 0x2001, 0x4400, 0x1078, 0x457e, 0x2001, 0x0013, 0x1078,
-	0x454c, 0x0078, 0x3b60, 0x127e, 0x2091, 0x2200, 0x2049, 0x4633,
-	0x7000, 0x7204, 0xa205, 0x720c, 0xa215, 0x7008, 0xa084, 0xfff7,
-	0xa205, 0x0040, 0x4645, 0x0078, 0x464a, 0x7003, 0x0000, 0x127f,
-	0x2000, 0x007c, 0x7000, 0xa084, 0x0001, 0x00c0, 0x4678, 0x7108,
-	0x8103, 0x00c8, 0x4657, 0x1078, 0x477a, 0x0078, 0x464f, 0x700c,
-	0xa08c, 0x00ff, 0x0040, 0x4678, 0x7004, 0x8004, 0x00c8, 0x466f,
-	0x7014, 0xa005, 0x00c0, 0x466b, 0x7010, 0xa005, 0x0040, 0x466f,
-	0xa102, 0x00c8, 0x464f, 0x7007, 0x0010, 0x0078, 0x4678, 0x8aff,
-	0x0040, 0x4678, 0x1078, 0x49c4, 0x00c0, 0x4672, 0x0040, 0x464f,
-	0x1078, 0x4703, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x017e,
-	0x6104, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x468b, 0xa18e,
-	0x000f, 0x00c0, 0x468e, 0x6040, 0x0078, 0x468f, 0x6428, 0x017f,
-	0x84ff, 0x0040, 0x46b9, 0x2c70, 0x7004, 0xa0bc, 0x000f, 0xa7b8,
-	0x46c9, 0x273c, 0x87fb, 0x00c0, 0x46a7, 0x0048, 0x46a1, 0x1078,
-	0x23ca, 0x609c, 0xa075, 0x0040, 0x46b9, 0x0078, 0x4694, 0x2704,
-	0xae68, 0x6808, 0xa630, 0x680c, 0xa529, 0x8421, 0x0040, 0x46b9,
-	0x8738, 0x2704, 0xa005, 0x00c0, 0x46a8, 0x709c, 0xa075, 0x00c0,
-	0x4694, 0x007c, 0x0000, 0x0005, 0x0009, 0x000d, 0x0011, 0x0015,
-	0x0019, 0x001d, 0x0000, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b,
-	0x0000, 0x0000, 0x46be, 0x46bb, 0x0000, 0x0000, 0x8000, 0x0000,
-	0x46be, 0x0000, 0x46c6, 0x46c3, 0x0000, 0x0000, 0x0000, 0x0000,
-	0x46c6, 0x0000, 0x46c1, 0x46c1, 0x0000, 0x0000, 0x8000, 0x0000,
-	0x46c1, 0x0000, 0x46c7, 0x46c7, 0x0000, 0x0000, 0x0000, 0x0000,
-	0x46c7, 0x127e, 0x2091, 0x2200, 0x2079, 0x5000, 0x2071, 0x0010,
-	0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2071, 0x0020,
-	0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2049, 0x0000,
-	0x127f, 0x2000, 0x007c, 0x2049, 0x4703, 0x2019, 0x0000, 0x7004,
-	0x8004, 0x00c8, 0x4756, 0x7007, 0x0012, 0x7108, 0x7008, 0xa106,
-	0x00c0, 0x470d, 0xa184, 0x01e0, 0x0040, 0x4718, 0x1078, 0x23ca,
-	0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x4723, 0xa184,
-	0x4000, 0x00c0, 0x470d, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040,
-	0x4731, 0xa386, 0x0008, 0x0040, 0x473c, 0xa386, 0x200c, 0x00c0,
-	0x470d, 0x7200, 0x8204, 0x0048, 0x473c, 0x730c, 0xa384, 0x00ff,
-	0x0040, 0x473c, 0x1078, 0x23ca, 0x7007, 0x0012, 0x7000, 0xa084,
-	0x0001, 0x00c0, 0x4756, 0x7008, 0xa084, 0x01e0, 0x00c0, 0x4756,
-	0x7310, 0x7014, 0xa305, 0x0040, 0x4756, 0x710c, 0xa184, 0x0300,
-	0x00c0, 0x4756, 0xa184, 0x00ff, 0x00c0, 0x4703, 0x7007, 0x0012,
-	0x7007, 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0, 0x475a, 0x7007,
-	0x0012, 0x7108, 0x8103, 0x0048, 0x475f, 0x7003, 0x0000, 0x2049,
-	0x0000, 0x007c, 0x107e, 0x007e, 0x127e, 0x157e, 0x2091, 0x2200,
-	0x7108, 0x1078, 0x477a, 0x157f, 0x127f, 0x2091, 0x8001, 0x007f,
-	0x107f, 0x007c, 0x7204, 0x7500, 0x730c, 0xa384, 0x0300, 0x00c0,
-	0x47a1, 0xa184, 0x01e0, 0x00c0, 0x47c5, 0x7108, 0xa184, 0x01e0,
-	0x00c0, 0x47c5, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8,
-	0x4795, 0xa184, 0x4000, 0x00c0, 0x4785, 0xa184, 0x0007, 0x0079,
-	0x4799, 0x47a3, 0x47b5, 0x47a1, 0x47b5, 0x47a1, 0x4801, 0x47a1,
-	0x47ff, 0x1078, 0x23ca, 0x7004, 0xa084, 0x0010, 0xa085, 0x0002,
-	0x7006, 0x8aff, 0x00c0, 0x47b0, 0x2049, 0x0000, 0x0078, 0x47b4,
-	0x1078, 0x49c4, 0x00c0, 0x47b0, 0x007c, 0x7004, 0xa084, 0x0010,
-	0xa085, 0x0002, 0x7006, 0x8aff, 0x00c0, 0x47c0, 0x0078, 0x47c4,
-	0x1078, 0x49c4, 0x00c0, 0x47c0, 0x007c, 0x7007, 0x0012, 0x7108,
-	0x00e0, 0x47c8, 0x2091, 0x6000, 0x00e0, 0x47cc, 0x2091, 0x6000,
-	0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0,
-	0x47d4, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, 0x47d9, 0x7003,
-	0x0000, 0x7000, 0xa005, 0x00c0, 0x47ed, 0x7004, 0xa005, 0x00c0,
-	0x47ed, 0x700c, 0xa005, 0x0040, 0x47ef, 0x0078, 0x47d0, 0x2049,
-	0x0000, 0x1078, 0x37d7, 0x6818, 0xa084, 0x8000, 0x0040, 0x47fa,
-	0x681b, 0x0002, 0x007c, 0x1078, 0x23ca, 0x1078, 0x23ca, 0x1078,
-	0x485d, 0x7210, 0x7114, 0x700c, 0xa09c, 0x00ff, 0x2800, 0xa300,
-	0xa211, 0xa189, 0x0000, 0x1078, 0x485d, 0x2704, 0x2c58, 0xac60,
-	0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, 0x2400, 0xa305,
-	0x0040, 0x4824, 0x00c8, 0x4824, 0x8412, 0x8210, 0x830a, 0xa189,
-	0x0000, 0x2b60, 0x0078, 0x480b, 0x2b60, 0x8a07, 0x007e, 0x6004,
-	0xa084, 0x0008, 0x0040, 0x4830, 0xa7ba, 0x46c3, 0x0078, 0x4832,
-	0xa7ba, 0x46bb, 0x007f, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92,
-	0x6b8e, 0x7007, 0x0012, 0x1078, 0x4703, 0x007c, 0x8738, 0x2704,
-	0xa005, 0x00c0, 0x4851, 0x609c, 0xa005, 0x0040, 0x485a, 0x2060,
-	0x6004, 0xa084, 0x000f, 0xa080, 0x46c9, 0x203c, 0x87fb, 0x1040,
-	0x23ca, 0x8a51, 0x0040, 0x4859, 0x7008, 0xa084, 0x0003, 0xa086,
-	0x0003, 0x007c, 0x2051, 0x0000, 0x007c, 0x8a50, 0x8739, 0x2704,
-	0xa004, 0x00c0, 0x4871, 0x6000, 0xa064, 0x00c0, 0x4868, 0x2d60,
-	0x6004, 0xa084, 0x000f, 0xa080, 0x46d9, 0x203c, 0x87fb, 0x1040,
-	0x23ca, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x6884,
-	0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084,
-	0x00ff, 0x007e, 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x488c,
-	0xa0b8, 0x46c3, 0x0078, 0x488e, 0xa0b8, 0x46bb, 0x7e08, 0xa6b5,
-	0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x489c,
-	0xa18e, 0x000f, 0x00c0, 0x48a5, 0x681c, 0xa084, 0x0040, 0x0040,
-	0x48ac, 0xa6b5, 0x0001, 0x0078, 0x48ac, 0x681c, 0xa084, 0x0040,
-	0x0040, 0x48ac, 0xa6b5, 0x0001, 0x7007, 0x0004, 0x7004, 0xa084,
-	0x0004, 0x00c0, 0x48ae, 0x2400, 0xa305, 0x00c0, 0x48b9, 0x0078,
-	0x48df, 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a,
-	0x6004, 0xa301, 0x701e, 0xa184, 0x0008, 0x0040, 0x48cf, 0x6010,
-	0xa081, 0x0000, 0x7022, 0x6014, 0xa081, 0x0000, 0x7026, 0x6208,
-	0x2400, 0xa202, 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602,
-	0x7007, 0x0001, 0x2b60, 0x1078, 0x483e, 0x0078, 0x48e1, 0x1078,
-	0x49c4, 0x00c0, 0x48df, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e,
-	0x2091, 0x2200, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004,
-	0x00c0, 0x48ed, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e,
-	0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x48f7, 0x7007, 0x0004,
-	0x7004, 0xa084, 0x0004, 0x00c0, 0x4900, 0x7e08, 0xa6b5, 0x000c,
-	0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4913, 0xa18e,
-	0x000f, 0x00c0, 0x491e, 0x681c, 0xa084, 0x0040, 0x0040, 0x491a,
-	0xa6b5, 0x0001, 0x6840, 0x2050, 0x0078, 0x4927, 0x681c, 0xa084,
-	0x0020, 0x00c0, 0x4925, 0xa6b5, 0x0001, 0x6828, 0x2050, 0x2d60,
-	0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x46c9, 0x273c, 0x87fb, 0x00c0,
-	0x493b, 0x0048, 0x4935, 0x1078, 0x23ca, 0x689c, 0xa065, 0x0040,
-	0x493f, 0x0078, 0x4928, 0x1078, 0x49c4, 0x00c0, 0x493b, 0x127f,
-	0x2000, 0x007c, 0x127e, 0x007e, 0x017e, 0x0d7e, 0x2091, 0x2200,
-	0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5, 0x000c, 0x6904, 0xa18c,
-	0x00ff, 0xa186, 0x0007, 0x0040, 0x4959, 0xa18e, 0x000f, 0x00c0,
-	0x4962, 0x681c, 0xa084, 0x0040, 0x0040, 0x4969, 0xa6b5, 0x0001,
-	0x0078, 0x4969, 0x681c, 0xa084, 0x0040, 0x0040, 0x4969, 0xa6b5,
-	0x0001, 0x2049, 0x4942, 0x017e, 0x6904, 0xa18c, 0x00ff, 0xa186,
-	0x0007, 0x0040, 0x4977, 0xa18e, 0x000f, 0x00c0, 0x497a, 0x6840,
-	0x0078, 0x497b, 0x6828, 0x017f, 0xa055, 0x0040, 0x49c1, 0x2d70,
-	0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x46c9, 0x273c, 0x87fb,
-	0x00c0, 0x4995, 0x0048, 0x498e, 0x1078, 0x23ca, 0x709c, 0xa075,
-	0x2060, 0x0040, 0x49c1, 0x0078, 0x4981, 0x2704, 0xae68, 0x6808,
-	0xa422, 0x680c, 0xa31b, 0x0048, 0x49ae, 0x8a51, 0x00c0, 0x49a2,
-	0x1078, 0x23ca, 0x8738, 0x2704, 0xa005, 0x00c0, 0x4996, 0x709c,
-	0xa075, 0x2060, 0x0040, 0x49c1, 0x0078, 0x4981, 0x8422, 0x8420,
-	0x831a, 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300,
-	0xa11b, 0x00c8, 0x49bd, 0x1078, 0x23ca, 0x2071, 0x0020, 0x0078,
-	0x48ac, 0x127f, 0x2000, 0x007c, 0x7008, 0xa084, 0x0003, 0xa086,
-	0x0003, 0x0040, 0x49ec, 0x2704, 0xac08, 0x2104, 0x701a, 0x8108,
-	0x2104, 0x701e, 0x8108, 0x2104, 0x7012, 0x8108, 0x2104, 0x7016,
-	0x6004, 0xa084, 0x0008, 0x0040, 0x49e3, 0x8108, 0x2104, 0x7022,
-	0x8108, 0x2104, 0x7026, 0x7602, 0x7004, 0xa084, 0x0010, 0xa085,
-	0x0001, 0x7006, 0x1078, 0x483e, 0x007c, 0x127e, 0x007e, 0x0d7e,
-	0x2091, 0x2200, 0x2049, 0x49ed, 0x0d7f, 0x087f, 0x7108, 0xa184,
-	0x0003, 0x00c0, 0x4a17, 0x017e, 0x6904, 0xa18c, 0x00ff, 0xa186,
-	0x0007, 0x0040, 0x4a07, 0xa18e, 0x000f, 0x00c0, 0x4a0a, 0x6840,
-	0x0078, 0x4a0b, 0x6828, 0x017f, 0xa005, 0x0040, 0x4a25, 0x0078,
-	0x464a, 0x0020, 0x4a17, 0x1078, 0x4801, 0x0078, 0x4a25, 0x00a0,
-	0x4a1e, 0x7108, 0x1078, 0x477a, 0x0078, 0x49f6, 0x7007, 0x0010,
-	0x00a0, 0x4a20, 0x7108, 0x1078, 0x477a, 0x7008, 0xa086, 0x0008,
-	0x00c0, 0x49f6, 0x7000, 0xa005, 0x00c0, 0x49f6, 0x7003, 0x0000,
-	0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x127e, 0x147e, 0x137e,
-	0x157e, 0x0c7e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x4a35,
-	0xad80, 0x0011, 0x20a0, 0x2099, 0x0031, 0x700c, 0xa084, 0x00ff,
-	0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040,
-	0x4a54, 0x8000, 0x80ac, 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084,
-	0x0004, 0x00c0, 0x4a56, 0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000,
-	0x157f, 0x137f, 0x147f, 0x127f, 0x2000, 0x007c, 0x2091, 0x6000,
-	0x2091, 0x8000, 0x78cc, 0xa005, 0x0040, 0x4a7d, 0x7994, 0x70d0,
-	0xa106, 0x00c0, 0x4a7d, 0x7804, 0xa005, 0x0040, 0x4a7d, 0x7807,
-	0x0000, 0x0068, 0x4a7d, 0x2091, 0x4080, 0x7820, 0x8001, 0x7822,
-	0x00c0, 0x4ad8, 0x7824, 0x7822, 0x2069, 0x5040, 0x6800, 0xa084,
-	0x0007, 0x0040, 0x4a9b, 0xa086, 0x0002, 0x0040, 0x4a9b, 0x6834,
-	0xa00d, 0x0040, 0x4a9b, 0x2104, 0xa005, 0x0040, 0x4a9b, 0x8001,
-	0x200a, 0x0040, 0x4b80, 0x7848, 0xa005, 0x0040, 0x4aa9, 0x8001,
-	0x784a, 0x00c0, 0x4aa9, 0x2009, 0x0102, 0x6844, 0x200a, 0x1078,
-	0x21b1, 0x6890, 0xa005, 0x0040, 0x4ab5, 0x8001, 0x6892, 0x00c0,
-	0x4ab5, 0x686f, 0x0000, 0x6873, 0x0001, 0x2061, 0x5300, 0x20a9,
-	0x0100, 0x2009, 0x0002, 0x6034, 0xa005, 0x0040, 0x4acb, 0x8001,
-	0x6036, 0x00c0, 0x4acb, 0x6010, 0xa005, 0x0040, 0x4acb, 0x017e,
-	0x1078, 0x21b1, 0x017f, 0xace0, 0x0010, 0x0070, 0x4ad1, 0x0078,
-	0x4abb, 0x8109, 0x0040, 0x4ad8, 0x20a9, 0x0100, 0x0078, 0x4abb,
-	0x1078, 0x4ae5, 0x1078, 0x4b0a, 0x2009, 0x5051, 0x2104, 0x2009,
-	0x0102, 0x200a, 0x2091, 0x8001, 0x007c, 0x7834, 0x8001, 0x7836,
-	0x00c0, 0x4b09, 0x7838, 0x7836, 0x2091, 0x8000, 0x7844, 0xa005,
-	0x00c0, 0x4af4, 0x2001, 0x0101, 0x8001, 0x7846, 0xa080, 0x7300,
-	0x2040, 0x2004, 0xa065, 0x0040, 0x4b09, 0x6024, 0xa005, 0x0040,
-	0x4b05, 0x8001, 0x6026, 0x0040, 0x4b39, 0x6000, 0x2c40, 0x0078,
-	0x4afa, 0x007c, 0x7828, 0x8001, 0x782a, 0x00c0, 0x4b38, 0x782c,
-	0x782a, 0x7830, 0xa005, 0x00c0, 0x4b17, 0x2001, 0x0200, 0x8001,
-	0x7832, 0x8003, 0x8003, 0x8003, 0x8003, 0xa090, 0x5300, 0xa298,
-	0x0002, 0x2304, 0xa084, 0x0008, 0x0040, 0x4b38, 0xa290, 0x0009,
-	0x2204, 0xa005, 0x0040, 0x4b30, 0x8001, 0x2012, 0x00c0, 0x4b38,
-	0x2304, 0xa084, 0xfff7, 0xa085, 0x0080, 0x201a, 0x1078, 0x21b1,
-	0x007c, 0x2069, 0x5040, 0x6800, 0xa005, 0x0040, 0x4b43, 0x6848,
-	0xac06, 0x0040, 0x4b80, 0x601b, 0x0006, 0x60b4, 0xa084, 0x3f00,
-	0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, 0x6000,
-	0x2042, 0x6714, 0x6f82, 0x1078, 0x1956, 0x6818, 0xa005, 0x0040,
-	0x4b5b, 0x8001, 0x681a, 0x6808, 0xa084, 0xffef, 0x680a, 0x6810,
-	0x8001, 0x00d0, 0x4b65, 0x1078, 0x23ca, 0x6812, 0x602f, 0x0000,
-	0x6033, 0x0000, 0x2c68, 0x1078, 0x1c53, 0x2069, 0x5040, 0x7944,
-	0xa184, 0x0100, 0x2001, 0x0006, 0x686e, 0x00c0, 0x4b7b, 0x6986,
-	0x2001, 0x0004, 0x686e, 0x1078, 0x21ac, 0x2091, 0x8001, 0x007c,
-	0x2069, 0x0100, 0x2009, 0x5040, 0x2104, 0xa084, 0x0007, 0x0040,
-	0x4bdc, 0xa086, 0x0007, 0x00c0, 0x4b96, 0x0d7e, 0x2009, 0x5052,
-	0x216c, 0x1078, 0x3a1a, 0x0d7f, 0x0078, 0x4bdc, 0x2009, 0x5052,
-	0x2164, 0x1078, 0x2375, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00,
-	0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f,
-	0x0000, 0x6033, 0x0000, 0x6830, 0xa084, 0x0040, 0x0040, 0x4bd0,
-	0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004, 0x0040,
-	0x4bbd, 0x0070, 0x4bbd, 0x0078, 0x4bb4, 0x684b, 0x0009, 0x20a9,
-	0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x4bca, 0x0070, 0x4bca,
-	0x0078, 0x4bc1, 0x20a9, 0x00fa, 0x0070, 0x4bd0, 0x0078, 0x4bcc,
-	0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0048, 0x2009, 0x505b,
-	0x200b, 0x0007, 0x784c, 0x784a, 0x2091, 0x8001, 0x007c, 0x2079,
-	0x5000, 0x1078, 0x4c0a, 0x1078, 0x4bee, 0x1078, 0x4bfc, 0x7833,
-	0x0000, 0x7847, 0x0000, 0x784b, 0x0000, 0x007c, 0x2019, 0x0003,
-	0x2011, 0x5046, 0x2204, 0xa086, 0x003c, 0x0040, 0x4bf9, 0x2019,
-	0x0002, 0x7b2a, 0x7b2e, 0x007c, 0x2019, 0x0039, 0x2011, 0x5046,
-	0x2204, 0xa086, 0x003c, 0x0040, 0x4c07, 0x2019, 0x0027, 0x7b36,
-	0x7b3a, 0x007c, 0x2019, 0x3971, 0x2011, 0x5046, 0x2204, 0xa086,
-	0x003c, 0x0040, 0x4c15, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x783f,
-	0x0000, 0x7843, 0x000a, 0x007c, 0x0020, 0x002b, 0x0000, 0x0020,
-	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
-	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
-	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
-	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0014,
-	0x0014, 0x9849, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014,
-	0x0014, 0x0080, 0x000f, 0x0000, 0x0201, 0x0604, 0x0c08, 0x2120,
-	0x4022, 0xf880, 0x0018, 0x300b, 0xa201, 0x0014, 0xa200, 0x0014,
-	0xa200, 0x0214, 0x0000, 0x006c, 0x0002, 0x0014, 0x98d5, 0x009e,
-	0x009b, 0xa202, 0x8838, 0x3806, 0x8839, 0x20c3, 0x0864, 0x9889,
-	0x28c1, 0x9cb6, 0xa203, 0x300c, 0x2846, 0x8161, 0x846a, 0x8300,
-	0x1856, 0x883a, 0x9865, 0x28f2, 0x9c95, 0x9858, 0x300c, 0x28e1,
-	0x9c95, 0x2809, 0xa206, 0x64c0, 0x67a0, 0x6fc0, 0x1814, 0x883b,
-	0x782c, 0x786d, 0x9879, 0x282b, 0xa207, 0x64a0, 0x67a0, 0x6fc0,
-	0x1814, 0x883b, 0x7822, 0x883e, 0x987d, 0x8576, 0x8677, 0x206b,
-	0x28c1, 0x9cb6, 0x2044, 0x2103, 0x20a2, 0x2081, 0x9865, 0xa209,
-	0x2901, 0x9891, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a, 0x883c,
-	0x1fe2, 0xc601, 0xa20a, 0x856e, 0x0704, 0x9c95, 0x0014, 0xa204,
-	0xa300, 0x3009, 0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb, 0x872e,
-	0x87a9, 0x883f, 0x08e6, 0x9895, 0xf881, 0x9890, 0xc801, 0x0014,
-	0xf8c1, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2, 0x0014,
-	0x8532, 0xf241, 0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6, 0x0014,
-	0xa208, 0x6043, 0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160, 0x842a,
-	0xf041, 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d5,
-	0x8822, 0x0016, 0x8000, 0x2847, 0x1011, 0x98c8, 0x8000, 0xa000,
-	0x2802, 0x1011, 0x98ce, 0x9865, 0x283e, 0x1011, 0x98d2, 0xa20b,
-	0x0017, 0x300c, 0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210, 0x98df,
-	0x0014, 0x26e0, 0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014, 0xa20d,
-	0x3806, 0x0210, 0x9cbb, 0x0704, 0x0000, 0x006c, 0x0002, 0x984f,
-	0x0014, 0x009e, 0x00a0, 0x0017, 0x60ff, 0x300c, 0x8720, 0xa211,
-	0x9cd0, 0x8772, 0x8837, 0x2101, 0x987a, 0x10d2, 0x78e2, 0x9cd3,
-	0x9859, 0xd984, 0xf0e2, 0xf0a1, 0x98cd, 0x0014, 0x8831, 0xd166,
-	0x8830, 0x800f, 0x9401, 0xb520, 0xc802, 0x8820, 0x987a, 0x2301,
-	0x987a, 0x10d2, 0x78e4, 0x9cd3, 0x8821, 0x8820, 0x9859, 0xf123,
-	0xf142, 0xf101, 0x98c6, 0x10d2, 0x70f6, 0x8832, 0x8203, 0x870c,
-	0xd99e, 0x6001, 0x0014, 0x6845, 0x0214, 0xa21b, 0x9cd0, 0x2001,
-	0x98c5, 0x8201, 0x1852, 0xd184, 0xd163, 0x8834, 0x8001, 0x988d,
-	0x3027, 0x84a8, 0x1a56, 0x8833, 0x0014, 0xa218, 0x6981, 0x9cbc,
-	0x6b2a, 0x6902, 0x1834, 0x989d, 0x1814, 0x8010, 0x8592, 0x8026,
-	0x84b9, 0x7021, 0x0014, 0xa300, 0x69e1, 0x9ca9, 0x694b, 0xa213,
-	0x1462, 0xa213, 0x8000, 0x16e1, 0x98b5, 0x8023, 0x16e1, 0x8001,
-	0x10f1, 0x0016, 0x6969, 0xa214, 0x61c2, 0x8002, 0x14e1, 0x8004,
-	0x16e1, 0x0101, 0x300a, 0x8827, 0x0014, 0xa217, 0x9cbc, 0x0014,
-	0xa300, 0x8181, 0x842a, 0x84a8, 0x1ce6, 0x882c, 0x0016, 0xa212,
-	0x9cd0, 0x10d2, 0x70e4, 0x0004, 0x8007, 0x9424, 0xcc1a, 0x9cd3,
-	0x98c5, 0x8827, 0x300a, 0x0013, 0x8000, 0x84a4, 0x0016, 0x11c2,
-	0x211e, 0x870e, 0xa21d, 0x0014, 0x878e, 0x0016, 0xa21c, 0x1035,
-	0x9891, 0xa210, 0xa000, 0x8010, 0x8592, 0x853b, 0xd044, 0x8022,
-	0x3807, 0x84bb, 0x98ea, 0x8021, 0x3807, 0x84b9, 0x300c, 0x817e,
-	0x872b, 0x8772, 0x9891, 0x0000, 0x0020, 0x002b, 0x0000, 0x0020,
-	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
-	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
-	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
-	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0014,
-	0x0014, 0x9849, 0x0014, 0x0014, 0x98ea, 0x98d5, 0x0014, 0x0014,
-	0x0014, 0x0080, 0x013f, 0x0000, 0x0201, 0x0604, 0x0c08, 0x2120,
-	0x4022, 0xf880, 0x0018, 0x300b, 0xa201, 0x0014, 0xa200, 0x0014,
-	0xa200, 0x0214, 0xa202, 0x8838, 0x3806, 0x8839, 0x20c3, 0x0864,
-	0xa833, 0x28c1, 0x9cb6, 0xa203, 0x300c, 0x2846, 0x8161, 0x846a,
-	0x8300, 0x1856, 0x883a, 0xa804, 0x28f2, 0x9c95, 0xa8f4, 0x300c,
-	0x28e1, 0x9c95, 0x2809, 0xa206, 0x64c0, 0x67a0, 0x6fc0, 0x1814,
-	0x883b, 0x782c, 0x786d, 0xa808, 0x282b, 0xa207, 0x64a0, 0x67a0,
-	0x6fc0, 0x1814, 0x883b, 0x7822, 0x883e, 0xa802, 0x8576, 0x8677,
-	0x206b, 0x28c1, 0x9cb6, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8e0,
-	0xa209, 0x2901, 0xa809, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a,
-	0x883c, 0x1fe2, 0xc601, 0xa20a, 0x856e, 0x0704, 0x9c95, 0x0014,
-	0xa204, 0xa300, 0x3009, 0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb,
-	0x872e, 0x87a9, 0x883f, 0x08e6, 0xa8f3, 0xf881, 0xa8ec, 0xc801,
-	0x0014, 0xf8c1, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2,
-	0x0014, 0x8532, 0xf241, 0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6,
-	0x0014, 0xa208, 0x6043, 0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160,
-	0x842a, 0xf041, 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011,
-	0x20d5, 0x8822, 0x0016, 0x8000, 0x2847, 0x1011, 0xa8fc, 0x8000,
-	0xa000, 0x2802, 0x1011, 0xa8fd, 0xa893, 0x283e, 0x1011, 0xa8fd,
-	0xa20b, 0x0017, 0x300c, 0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210,
-	0xa801, 0x0014, 0x26e0, 0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014,
-	0xa20d, 0x3806, 0x0210, 0x9cbb, 0x0704, 0x0017, 0x60ff, 0x300c,
-	0x8720, 0xa211, 0x9d6b, 0x8772, 0x8837, 0x2101, 0xa821, 0x10d2,
-	0x78e2, 0x9d6e, 0xa8fc, 0xd984, 0xf0e2, 0xf0a1, 0xa86c, 0x0014,
-	0x8831, 0xd166, 0x8830, 0x800f, 0x9401, 0xb520, 0xc802, 0x8820,
-	0xa80f, 0x2301, 0xa80d, 0x10d2, 0x78e4, 0x9d6e, 0x8821, 0x8820,
-	0xa8e6, 0xf123, 0xf142, 0xf101, 0xa84f, 0x10d2, 0x70f6, 0x8832,
-	0x8203, 0x870c, 0xd99e, 0x6001, 0x0014, 0x6845, 0x0214, 0xa21b,
-	0x9d6b, 0x2001, 0xa840, 0x8201, 0x1852, 0xd184, 0xd163, 0x8834,
-	0x8001, 0xa801, 0x3027, 0x84a8, 0x1a56, 0x8833, 0x0014, 0xa218,
-	0x6981, 0x9d57, 0x6b2a, 0x6902, 0x1834, 0xa805, 0x1814, 0x8010,
-	0x8592, 0x8026, 0x84b9, 0x7021, 0x0014, 0xa300, 0x69e1, 0x9d44,
-	0x694b, 0xa213, 0x1462, 0xa213, 0x8000, 0x16e1, 0xa80c, 0x8023,
-	0x16e1, 0x8001, 0x10f1, 0x0016, 0x6969, 0xa214, 0x61c2, 0x8002,
-	0x14e1, 0x8004, 0x16e1, 0x0101, 0x300a, 0x8827, 0x0014, 0xa217,
-	0x9d57, 0x0014, 0xa300, 0x8181, 0x842a, 0x84a8, 0x1ce6, 0x882c,
-	0x0016, 0xa212, 0x9d6b, 0x10d2, 0x70e4, 0x0004, 0x8007, 0x9424,
-	0xcc1a, 0x9d6e, 0xa8f8, 0x8827, 0x300a, 0x0013, 0x8000, 0x84a4,
-	0x0016, 0x11c2, 0x211e, 0x870e, 0xa21d, 0x0014, 0x878e, 0x0016,
-	0xa21c, 0x1035, 0xa8b4, 0xa210, 0x3807, 0x300c, 0x817e, 0x872b,
-	0x8772, 0xa8ad, 0x0000, 0x8ec6
-};
-
-#endif /* RELOAD_FIRMWARE */
-
-static const unsigned short risc_code_length01 = 0x3f14;
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index caa0c36..5b1c120 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -1,5 +1,13 @@
 /*
- * RAID Attributes
+ * raid_class.c - implementation of a simple raid visualisation class
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com>
+ *
+ * This file is licensed under GPLv2
+ *
+ * This class is designed to allow raid attributes to be visualised and
+ * manipulated in a form independent of the underlying raid.  Ultimately this
+ * should work for both hardware and software raids.
  */
 #include <linux/init.h>
 #include <linux/module.h>
@@ -24,7 +32,7 @@
 
 struct raid_component {
 	struct list_head node;
-	struct device *dev;
+	struct class_device cdev;
 	int num;
 };
 
@@ -74,11 +82,10 @@
 
 	BUG_ON(class_get_devdata(cdev));
 
-	rd = kmalloc(sizeof(*rd), GFP_KERNEL);
+	rd = kzalloc(sizeof(*rd), GFP_KERNEL);
 	if (!rd)
 		return -ENOMEM;
 
-	memset(rd, 0, sizeof(*rd));
 	INIT_LIST_HEAD(&rd->component_list);
 	class_set_devdata(cdev, rd);
 		
@@ -90,15 +97,15 @@
 {
 	struct raid_data *rd = class_get_devdata(cdev);
 	struct raid_component *rc, *next;
+	dev_printk(KERN_ERR, dev, "RAID REMOVE\n");
 	class_set_devdata(cdev, NULL);
 	list_for_each_entry_safe(rc, next, &rd->component_list, node) {
-		char buf[40];
-		snprintf(buf, sizeof(buf), "component-%d", rc->num);
 		list_del(&rc->node);
-		sysfs_remove_link(&cdev->kobj, buf);
-		kfree(rc);
+		dev_printk(KERN_ERR, rc->cdev.dev, "RAID COMPONENT REMOVE\n");
+		class_device_unregister(&rc->cdev);
 	}
-	kfree(class_get_devdata(cdev));
+	dev_printk(KERN_ERR, dev, "RAID REMOVE DONE\n");
+	kfree(rd);
 	return 0;
 }
 
@@ -112,10 +119,11 @@
 	enum raid_state	value;
 	char		*name;
 } raid_states[] = {
-	{ RAID_ACTIVE, "active" },
-	{ RAID_DEGRADED, "degraded" },
-	{ RAID_RESYNCING, "resyncing" },
-	{ RAID_OFFLINE, "offline" },
+	{ RAID_STATE_UNKNOWN, "unknown" },
+	{ RAID_STATE_ACTIVE, "active" },
+	{ RAID_STATE_DEGRADED, "degraded" },
+	{ RAID_STATE_RESYNCING, "resyncing" },
+	{ RAID_STATE_OFFLINE, "offline" },
 };
 
 static const char *raid_state_name(enum raid_state state)
@@ -132,6 +140,33 @@
 	return name;
 }
 
+static struct {
+	enum raid_level value;
+	char *name;
+} raid_levels[] = {
+	{ RAID_LEVEL_UNKNOWN, "unknown" },
+	{ RAID_LEVEL_LINEAR, "linear" },
+	{ RAID_LEVEL_0, "raid0" },
+	{ RAID_LEVEL_1, "raid1" },
+	{ RAID_LEVEL_3, "raid3" },
+	{ RAID_LEVEL_4, "raid4" },
+	{ RAID_LEVEL_5, "raid5" },
+	{ RAID_LEVEL_6, "raid6" },
+};
+
+static const char *raid_level_name(enum raid_level level)
+{
+	int i;
+	char *name = NULL;
+
+	for (i = 0; i < sizeof(raid_levels)/sizeof(raid_levels[0]); i++) {
+		if (raid_levels[i].value == level) {
+			name = raid_levels[i].name;
+			break;
+		}
+	}
+	return name;
+}
 
 #define raid_attr_show_internal(attr, fmt, var, code)			\
 static ssize_t raid_show_##attr(struct class_device *cdev, char *buf)	\
@@ -161,11 +196,22 @@
 
 #define raid_attr_ro(attr)	raid_attr_ro_internal(attr, )
 #define raid_attr_ro_fn(attr)	raid_attr_ro_internal(attr, ATTR_CODE(attr))
-#define raid_attr_ro_state(attr)	raid_attr_ro_states(attr, attr, ATTR_CODE(attr))
+#define raid_attr_ro_state(attr)	raid_attr_ro_states(attr, attr, )
+#define raid_attr_ro_state_fn(attr)	raid_attr_ro_states(attr, attr, ATTR_CODE(attr))
 
-raid_attr_ro(level);
+
+raid_attr_ro_state(level);
 raid_attr_ro_fn(resync);
-raid_attr_ro_state(state);
+raid_attr_ro_state_fn(state);
+
+static void raid_component_release(struct class_device *cdev)
+{
+	struct raid_component *rc = container_of(cdev, struct raid_component,
+						 cdev);
+	dev_printk(KERN_ERR, rc->cdev.dev, "COMPONENT RELEASE\n");
+	put_device(rc->cdev.dev);
+	kfree(rc);
+}
 
 void raid_component_add(struct raid_template *r,struct device *raid_dev,
 			struct device *component_dev)
@@ -175,34 +221,36 @@
 						      raid_dev);
 	struct raid_component *rc;
 	struct raid_data *rd = class_get_devdata(cdev);
-	char buf[40];
 
-	rc = kmalloc(sizeof(*rc), GFP_KERNEL);
+	rc = kzalloc(sizeof(*rc), GFP_KERNEL);
 	if (!rc)
 		return;
 
 	INIT_LIST_HEAD(&rc->node);
-	rc->dev = component_dev;
+	class_device_initialize(&rc->cdev);
+	rc->cdev.release = raid_component_release;
+	rc->cdev.dev = get_device(component_dev);
 	rc->num = rd->component_count++;
 
-	snprintf(buf, sizeof(buf), "component-%d", rc->num);
+	snprintf(rc->cdev.class_id, sizeof(rc->cdev.class_id),
+		 "component-%d", rc->num);
 	list_add_tail(&rc->node, &rd->component_list);
-	sysfs_create_link(&cdev->kobj, &component_dev->kobj, buf);
+	rc->cdev.parent = cdev;
+	rc->cdev.class = &raid_class.class;
+	class_device_add(&rc->cdev);
 }
 EXPORT_SYMBOL(raid_component_add);
 
 struct raid_template *
 raid_class_attach(struct raid_function_template *ft)
 {
-	struct raid_internal *i = kmalloc(sizeof(struct raid_internal),
+	struct raid_internal *i = kzalloc(sizeof(struct raid_internal),
 					  GFP_KERNEL);
 	int count = 0;
 
 	if (unlikely(!i))
 		return NULL;
 
-	memset(i, 0, sizeof(*i));
-
 	i->f = ft;
 
 	i->r.raid_attrs.ac.class = &raid_class.class;
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index 0f469e3..257c128 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -30,8 +30,8 @@
 #include <linux/sched.h>
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
 #include <linux/libata.h>
 #include <asm/io.h>
 
@@ -270,7 +270,7 @@
 static void mv_eng_timeout(struct ata_port *ap);
 static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 
-static Scsi_Host_Template mv_sht = {
+static struct scsi_host_template mv_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
@@ -349,7 +349,7 @@
 	},
 };
 
-static struct pci_device_id mv_pci_tbl[] = {
+static const struct pci_device_id mv_pci_tbl[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_508x},
@@ -359,6 +359,8 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
 	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
+
+	{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x0241), 0, 0, chip_604x},
 	{}			/* terminate list */
 };
 
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index d573888..4954896 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -62,7 +62,6 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
@@ -138,7 +137,7 @@
 	CK804
 };
 
-static struct pci_device_id nv_pci_tbl[] = {
+static const struct pci_device_id nv_pci_tbl[] = {
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
@@ -219,7 +218,7 @@
 	.remove			= ata_pci_remove_one,
 };
 
-static Scsi_Host_Template nv_sht = {
+static struct scsi_host_template nv_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index b41c977..242d906 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -39,8 +39,8 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
 #include <linux/libata.h>
 #include <asm/io.h>
 #include "sata_promise.h"
@@ -94,7 +94,7 @@
 static int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
 
 
-static Scsi_Host_Template pdc_ata_sht = {
+static struct scsi_host_template pdc_ata_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
@@ -193,7 +193,7 @@
 	},
 };
 
-static struct pci_device_id pdc_ata_pci_tbl[] = {
+static const struct pci_device_id pdc_ata_pci_tbl[] = {
 	{ PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_2037x },
 	{ PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 65502c1..b2f6324 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -36,7 +36,6 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <asm/io.h>
 #include <linux/libata.h>
@@ -128,7 +127,7 @@
 static void qs_irq_clear(struct ata_port *ap);
 static void qs_eng_timeout(struct ata_port *ap);
 
-static Scsi_Host_Template qs_ata_sht = {
+static struct scsi_host_template qs_ata_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
@@ -185,7 +184,7 @@
 	},
 };
 
-static struct pci_device_id qs_ata_pci_tbl[] = {
+static const struct pci_device_id qs_ata_pci_tbl[] = {
 	{ PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_2068_idx },
 
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 435f7e0..3609186 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -42,7 +42,6 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
@@ -88,7 +87,7 @@
 static void sil_post_set_mode (struct ata_port *ap);
 
 
-static struct pci_device_id sil_pci_tbl[] = {
+static const struct pci_device_id sil_pci_tbl[] = {
 	{ 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
 	{ 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
 	{ 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
@@ -131,7 +130,7 @@
 	.remove			= ata_pci_remove_one,
 };
 
-static Scsi_Host_Template sil_sht = {
+static struct scsi_host_template sil_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index e6c8e89..d3198d9 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -37,7 +37,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
 #include <scsi/scsi_host.h>
-#include "scsi.h"
+#include <scsi/scsi_cmnd.h>
 #include <linux/libata.h>
 #include <asm/io.h>
 
@@ -240,7 +240,7 @@
 static void sil24_host_stop(struct ata_host_set *host_set);
 static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 
-static struct pci_device_id sil24_pci_tbl[] = {
+static const struct pci_device_id sil24_pci_tbl[] = {
 	{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
 	{ 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
 	{ 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
@@ -255,7 +255,7 @@
 	.remove			= ata_pci_remove_one, /* safe? */
 };
 
-static Scsi_Host_Template sil24_sht = {
+static struct scsi_host_template sil24_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
index 42288be..32e1262 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -39,7 +39,6 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
@@ -68,7 +67,7 @@
 static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
-static struct pci_device_id sis_pci_tbl[] = {
+static const struct pci_device_id sis_pci_tbl[] = {
 	{ PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
 	{ PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
 	{ PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
@@ -83,7 +82,7 @@
 	.remove			= ata_pci_remove_one,
 };
 
-static Scsi_Host_Template sis_sht = {
+static struct scsi_host_template sis_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index db615ff..57e5a9d 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -45,7 +45,6 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
@@ -284,7 +283,7 @@
 #endif /* CONFIG_PPC_OF */
 
 
-static Scsi_Host_Template k2_sata_sht = {
+static struct scsi_host_template k2_sata_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
@@ -467,7 +466,7 @@
  * 0x24a is device ID for BCM5785 (aka HT1000) HT southbridge integrated SATA
  * controller
  * */
-static struct pci_device_id k2_sata_pci_tbl[] = {
+static const struct pci_device_id k2_sata_pci_tbl[] = {
 	{ 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
 	{ 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
 	{ 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index f859bbd..b4bbe48 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -39,8 +39,8 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
 #include <linux/libata.h>
 #include <asm/io.h>
 #include "sata_promise.h"
@@ -177,7 +177,7 @@
 static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
 
 
-static Scsi_Host_Template pdc_sata_sht = {
+static struct scsi_host_template pdc_sata_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
@@ -229,7 +229,7 @@
 
 };
 
-static struct pci_device_id pdc_sata_pci_tbl[] = {
+static const struct pci_device_id pdc_sata_pci_tbl[] = {
 	{ PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_20621 },
 	{ }	/* terminate list */
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index a5e245c..b2422a0 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -33,7 +33,6 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
@@ -56,7 +55,7 @@
 static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
-static struct pci_device_id uli_pci_tbl[] = {
+static const struct pci_device_id uli_pci_tbl[] = {
 	{ PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
 	{ PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
 	{ PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
@@ -71,7 +70,7 @@
 	.remove			= ata_pci_remove_one,
 };
 
-static Scsi_Host_Template uli_sht = {
+static struct scsi_host_template uli_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index b3ecdbe..c762156 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -42,7 +42,6 @@
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 #include <asm/io.h>
@@ -76,7 +75,7 @@
 static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
-static struct pci_device_id svia_pci_tbl[] = {
+static const struct pci_device_id svia_pci_tbl[] = {
 	{ 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
 	{ 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
 
@@ -90,7 +89,7 @@
 	.remove			= ata_pci_remove_one,
 };
 
-static Scsi_Host_Template svia_sht = {
+static struct scsi_host_template svia_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index bb84ba0..77a6e4b9 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -43,7 +43,6 @@
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
-#include "scsi.h"
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
@@ -219,7 +218,7 @@
 }
 
 
-static Scsi_Host_Template vsc_sata_sht = {
+static struct scsi_host_template vsc_sata_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
 	.ioctl			= ata_scsi_ioctl,
@@ -401,7 +400,7 @@
  * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical
  * compatibility is untested as of yet
  */
-static struct pci_device_id vsc_sata_pci_tbl[] = {
+static const struct pci_device_id vsc_sata_pci_tbl[] = {
 	{ 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
 	{ 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
 	{ }
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index aadf051..3ded9da 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -48,10 +48,6 @@
 
 #include <linux/stat.h>
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
 #include "scsi_logging.h"
 #include "scsi_debug.h"
 
@@ -182,7 +178,7 @@
 };
 static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
 
-static Scsi_Host_Template sdebug_driver_template = {
+static struct scsi_host_template sdebug_driver_template = {
 	.proc_info =		scsi_debug_proc_info,
 	.name =			"SCSI DEBUG",
 	.info =			scsi_debug_info,
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 0c5b02d..18c5d25 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -417,43 +417,15 @@
 }
 
 /**
- * scsi_eh_times_out - timeout function for error handling.
- * @scmd:	Cmd that is timing out.
- *
- * Notes:
- *    During error handling, the kernel thread will be sleeping waiting
- *    for some action to complete on the device.  our only job is to
- *    record that it timed out, and to wake up the thread.
- **/
-static void scsi_eh_times_out(struct scsi_cmnd *scmd)
-{
-	scmd->eh_eflags |= SCSI_EH_REC_TIMEOUT;
-	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd:%p\n", __FUNCTION__,
-					  scmd));
-
-	up(scmd->device->host->eh_action);
-}
-
-/**
  * scsi_eh_done - Completion function for error handling.
  * @scmd:	Cmd that is done.
  **/
 static void scsi_eh_done(struct scsi_cmnd *scmd)
 {
-	/*
-	 * if the timeout handler is already running, then just set the
-	 * flag which says we finished late, and return.  we have no
-	 * way of stopping the timeout handler from running, so we must
-	 * always defer to it.
-	 */
-	if (del_timer(&scmd->eh_timeout)) {
-		scmd->request->rq_status = RQ_SCSI_DONE;
-
-		SCSI_LOG_ERROR_RECOVERY(3, printk("%s scmd: %p result: %x\n",
-					   __FUNCTION__, scmd, scmd->result));
-
-		up(scmd->device->host->eh_action);
-	}
+	SCSI_LOG_ERROR_RECOVERY(3,
+		printk("%s scmd: %p result: %x\n",
+			__FUNCTION__, scmd, scmd->result));
+	complete(scmd->device->host->eh_action);
 }
 
 /**
@@ -461,10 +433,6 @@
  * @scmd:	SCSI Cmd to send.
  * @timeout:	Timeout for cmd.
  *
- * Notes:
- *    The initialization of the structures is quite a bit different in
- *    this case, and furthermore, there is a different completion handler
- *    vs scsi_dispatch_cmd.
  * Return value:
  *    SUCCESS or FAILED or NEEDS_RETRY
  **/
@@ -472,24 +440,16 @@
 {
 	struct scsi_device *sdev = scmd->device;
 	struct Scsi_Host *shost = sdev->host;
-	DECLARE_MUTEX_LOCKED(sem);
+	DECLARE_COMPLETION(done);
+	unsigned long timeleft;
 	unsigned long flags;
-	int rtn = SUCCESS;
+	int rtn;
 
-	/*
-	 * we will use a queued command if possible, otherwise we will
-	 * emulate the queuing and calling of completion function ourselves.
-	 */
 	if (sdev->scsi_level <= SCSI_2)
 		scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
 			(sdev->lun << 5 & 0xe0);
 
-	scsi_add_timer(scmd, timeout, scsi_eh_times_out);
-
-	/*
-	 * set up the semaphore so we wait for the command to complete.
-	 */
-	shost->eh_action = &sem;
+	shost->eh_action = &done;
 	scmd->request->rq_status = RQ_SCSI_BUSY;
 
 	spin_lock_irqsave(shost->host_lock, flags);
@@ -497,47 +457,29 @@
 	shost->hostt->queuecommand(scmd, scsi_eh_done);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
-	down(&sem);
-	scsi_log_completion(scmd, SUCCESS);
+	timeleft = wait_for_completion_timeout(&done, timeout);
 
+	scmd->request->rq_status = RQ_SCSI_DONE;
 	shost->eh_action = NULL;
 
-	/*
-	 * see if timeout.  if so, tell the host to forget about it.
-	 * in other words, we don't want a callback any more.
-	 */
-	if (scmd->eh_eflags & SCSI_EH_REC_TIMEOUT) {
-		scmd->eh_eflags &= ~SCSI_EH_REC_TIMEOUT;
+	scsi_log_completion(scmd, SUCCESS);
 
-		/*
-		 * as far as the low level driver is
-		 * concerned, this command is still active, so
-		 * we must give the low level driver a chance
-		 * to abort it. (db) 
-		 *
-		 * FIXME(eric) - we are not tracking whether we could
-		 * abort a timed out command or not.  not sure how
-		 * we should treat them differently anyways.
-		 */
-		if (shost->hostt->eh_abort_handler)
-			shost->hostt->eh_abort_handler(scmd);
-			
-		scmd->request->rq_status = RQ_SCSI_DONE;
-		rtn = FAILED;
-	}
-
-	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n",
-					  __FUNCTION__, scmd, rtn));
+	SCSI_LOG_ERROR_RECOVERY(3,
+		printk("%s: scmd: %p, timeleft: %ld\n",
+			__FUNCTION__, scmd, timeleft));
 
 	/*
-	 * now examine the actual status codes to see whether the command
-	 * actually did complete normally.
+	 * If there is time left scsi_eh_done got called, and we will
+	 * examine the actual status codes to see whether the command
+	 * actually did complete normally, else tell the host to forget
+	 * about this command.
 	 */
-	if (rtn == SUCCESS) {
+	if (timeleft) {
 		rtn = scsi_eh_completed_normally(scmd);
 		SCSI_LOG_ERROR_RECOVERY(3,
 			printk("%s: scsi_eh_completed_normally %x\n",
 			       __FUNCTION__, rtn));
+
 		switch (rtn) {
 		case SUCCESS:
 		case NEEDS_RETRY:
@@ -547,6 +489,15 @@
 			rtn = FAILED;
 			break;
 		}
+	} else {
+		/*
+		 * FIXME(eric) - we are not tracking whether we could
+		 * abort a timed out command or not.  not sure how
+		 * we should treat them differently anyways.
+		 */
+		if (shost->hostt->eh_abort_handler)
+			shost->hostt->eh_abort_handler(scmd);
+		rtn = FAILED;
 	}
 
 	return rtn;
@@ -1571,50 +1522,41 @@
 }
 
 /**
- * scsi_error_handler - Handle errors/timeouts of SCSI cmds.
+ * scsi_error_handler - SCSI error handler thread
  * @data:	Host for which we are running.
  *
  * Notes:
- *    This is always run in the context of a kernel thread.  The idea is
- *    that we start this thing up when the kernel starts up (one per host
- *    that we detect), and it immediately goes to sleep and waits for some
- *    event (i.e. failure).  When this takes place, we have the job of
- *    trying to unjam the bus and restarting things.
+ *    This is the main error handling loop.  This is run as a kernel thread
+ *    for every SCSI host and handles all error handling activity.
  **/
 int scsi_error_handler(void *data)
 {
-	struct Scsi_Host *shost = (struct Scsi_Host *) data;
-	int rtn;
+	struct Scsi_Host *shost = data;
 
 	current->flags |= PF_NOFREEZE;
 
-	
 	/*
-	 * Note - we always use TASK_INTERRUPTIBLE even if the module
-	 * was loaded as part of the kernel.  The reason is that
-	 * UNINTERRUPTIBLE would cause this thread to be counted in
-	 * the load average as a running process, and an interruptible
-	 * wait doesn't.
+	 * We use TASK_INTERRUPTIBLE so that the thread is not
+	 * counted against the load average as a running process.
+	 * We never actually get interrupted because kthread_run
+	 * disables singal delivery for the created thread.
 	 */
 	set_current_state(TASK_INTERRUPTIBLE);
 	while (!kthread_should_stop()) {
 		if (shost->host_failed == 0 ||
 		    shost->host_failed != shost->host_busy) {
-			SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler"
-							  " scsi_eh_%d"
-							  " sleeping\n",
-							  shost->host_no));
+			SCSI_LOG_ERROR_RECOVERY(1,
+				printk("Error handler scsi_eh_%d sleeping\n",
+					shost->host_no));
 			schedule();
 			set_current_state(TASK_INTERRUPTIBLE);
 			continue;
 		}
 
 		__set_current_state(TASK_RUNNING);
-		SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler"
-						  " scsi_eh_%d waking"
-						  " up\n",shost->host_no));
-
-		shost->eh_active = 1;
+		SCSI_LOG_ERROR_RECOVERY(1,
+			printk("Error handler scsi_eh_%d waking up\n",
+				shost->host_no));
 
 		/*
 		 * We have a host that is failing for some reason.  Figure out
@@ -1622,12 +1564,10 @@
 		 * If we fail, we end up taking the thing offline.
 		 */
 		if (shost->hostt->eh_strategy_handler) 
-			rtn = shost->hostt->eh_strategy_handler(shost);
+			shost->hostt->eh_strategy_handler(shost);
 		else
 			scsi_unjam_host(shost);
 
-		shost->eh_active = 0;
-
 		/*
 		 * Note - if the above fails completely, the action is to take
 		 * individual devices offline and flush the queue of any
@@ -1638,15 +1578,10 @@
 		scsi_restart_operations(shost);
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
-
 	__set_current_state(TASK_RUNNING);
 
-	SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d"
-					  " exiting\n",shost->host_no));
-
-	/*
-	 * Make sure that nobody tries to wake us up again.
-	 */
+	SCSI_LOG_ERROR_RECOVERY(1,
+		printk("Error handler scsi_eh_%d exiting\n", shost->host_no));
 	shost->ehandler = NULL;
 	return 0;
 }
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index e40c8b6..ce9d73a 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -254,55 +254,6 @@
 }
 EXPORT_SYMBOL(scsi_do_req);
 
-/* This is the end routine we get to if a command was never attached
- * to the request.  Simply complete the request without changing
- * rq_status; this will cause a DRIVER_ERROR. */
-static void scsi_wait_req_end_io(struct request *req)
-{
-	BUG_ON(!req->waiting);
-
-	complete(req->waiting);
-}
-
-void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
-		   unsigned bufflen, int timeout, int retries)
-{
-	DECLARE_COMPLETION(wait);
-	int write = (sreq->sr_data_direction == DMA_TO_DEVICE);
-	struct request *req;
-
-	req = blk_get_request(sreq->sr_device->request_queue, write,
-			      __GFP_WAIT);
-	if (bufflen && blk_rq_map_kern(sreq->sr_device->request_queue, req,
-				       buffer, bufflen, __GFP_WAIT)) {
-		sreq->sr_result = DRIVER_ERROR << 24;
-		blk_put_request(req);
-		return;
-	}
-
-	req->flags |= REQ_NOMERGE;
-	req->waiting = &wait;
-	req->end_io = scsi_wait_req_end_io;
-	req->cmd_len = COMMAND_SIZE(((u8 *)cmnd)[0]);
-	req->sense = sreq->sr_sense_buffer;
-	req->sense_len = 0;
-	memcpy(req->cmd, cmnd, req->cmd_len);
-	req->timeout = timeout;
-	req->flags |= REQ_BLOCK_PC;
-	req->rq_disk = NULL;
-	blk_insert_request(sreq->sr_device->request_queue, req,
-			   sreq->sr_data_direction == DMA_TO_DEVICE, NULL);
-	wait_for_completion(&wait);
-	sreq->sr_request->waiting = NULL;
-	sreq->sr_result = req->errors;
-	if (req->errors)
-		sreq->sr_result |= (DRIVER_ERROR << 24);
-
-	blk_put_request(req);
-}
-
-EXPORT_SYMBOL(scsi_wait_req);
-
 /**
  * scsi_execute - insert request and wait for the result
  * @sdev:	scsi device
@@ -591,10 +542,17 @@
 
 void scsi_next_command(struct scsi_cmnd *cmd)
 {
-	struct request_queue *q = cmd->device->request_queue;
+	struct scsi_device *sdev = cmd->device;
+	struct request_queue *q = sdev->request_queue;
+
+	/* need to hold a reference on the device before we let go of the cmd */
+	get_device(&sdev->sdev_gendev);
 
 	scsi_put_command(cmd);
 	scsi_run_queue(q);
+
+	/* ok to remove device now */
+	put_device(&sdev->sdev_gendev);
 }
 
 void scsi_run_host_queues(struct Scsi_Host *shost)
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index d05f778..d632d9e 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -22,7 +22,6 @@
  * Scsi Error Handler Flags
  */
 #define SCSI_EH_CANCEL_CMD	0x0001	/* Cancel this cmd */
-#define SCSI_EH_REC_TIMEOUT	0x0002	/* EH retry timed out */
 
 #define SCSI_SENSE_VALID(scmd) \
 	(((scmd)->sense_buffer[0] & 0x70) == 0x70)
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 7eb3a2d..374853d 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -9,7 +9,7 @@
  * global variable (boot or module load time) settings.
  *
  * A specific LUN is scanned via an INQUIRY command; if the LUN has a
- * device attached, a Scsi_Device is allocated and setup for it.
+ * device attached, a scsi_device is allocated and setup for it.
  *
  * For every id of every channel on the given host:
  *
@@ -17,7 +17,7 @@
  * 	device or storage attached to LUN 0):
  *
  * 		If LUN 0 has a device attached, allocate and setup a
- * 		Scsi_Device for it.
+ * 		scsi_device for it.
  *
  * 		If target is SCSI-3 or up, issue a REPORT LUN, and scan
  * 		all of the LUNs returned by the REPORT LUN; else,
@@ -441,7 +441,7 @@
  *
  *     If the INQUIRY is successful, zero is returned and the
  *     INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
- *     are copied to the Scsi_Device any flags value is stored in *@bflags.
+ *     are copied to the scsi_device any flags value is stored in *@bflags.
  **/
 static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
 			  int result_len, int *bflags)
@@ -509,8 +509,8 @@
 		/*
 		 * Get any flags for this device.
 		 *
-		 * XXX add a bflags to Scsi_Device, and replace the
-		 * corresponding bit fields in Scsi_Device, so bflags
+		 * XXX add a bflags to scsi_device, and replace the
+		 * corresponding bit fields in scsi_device, so bflags
 		 * need not be passed as an argument.
 		 */
 		*bflags = scsi_get_device_flags(sdev, &inq_result[8],
@@ -592,21 +592,21 @@
 }
 
 /**
- * scsi_add_lun - allocate and fully initialze a Scsi_Device
- * @sdevscan:	holds information to be stored in the new Scsi_Device
- * @sdevnew:	store the address of the newly allocated Scsi_Device
+ * scsi_add_lun - allocate and fully initialze a scsi_device
+ * @sdevscan:	holds information to be stored in the new scsi_device
+ * @sdevnew:	store the address of the newly allocated scsi_device
  * @inq_result:	holds the result of a previous INQUIRY to the LUN
  * @bflags:	black/white list flag
  *
  * Description:
- *     Allocate and initialize a Scsi_Device matching sdevscan. Optionally
+ *     Allocate and initialize a scsi_device matching sdevscan. Optionally
  *     set fields based on values in *@bflags. If @sdevnew is not
- *     NULL, store the address of the new Scsi_Device in *@sdevnew (needed
+ *     NULL, store the address of the new scsi_device in *@sdevnew (needed
  *     when scanning a particular LUN).
  *
  * Return:
- *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
- *     SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
+ *     SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
  **/
 static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
 {
@@ -674,7 +674,7 @@
 	 *
 	 * The above is vague, as it implies that we could treat 001 and
 	 * 011 the same. Stay compatible with previous code, and create a
-	 * Scsi_Device for a PQ of 1
+	 * scsi_device for a PQ of 1
 	 *
 	 * Don't set the device offline here; rather let the upper
 	 * level drivers eval the PQ to decide whether they should
@@ -784,8 +784,8 @@
  * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
  * @starget:	pointer to target device structure
  * @lun:	LUN of target device
- * @sdevscan:	probe the LUN corresponding to this Scsi_Device
- * @sdevnew:	store the value of any new Scsi_Device allocated
+ * @sdevscan:	probe the LUN corresponding to this scsi_device
+ * @sdevnew:	store the value of any new scsi_device allocated
  * @bflagsp:	store bflags here if not NULL
  *
  * Description:
@@ -793,10 +793,10 @@
  *     allocate and set it up by calling scsi_add_lun.
  *
  * Return:
- *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
+ *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
  *     SCSI_SCAN_TARGET_PRESENT: target responded, but no device is
  *         attached at the LUN
- *     SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ *     SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
  **/
 static int scsi_probe_and_add_lun(struct scsi_target *starget,
 				  uint lun, int *bflagsp,
@@ -1046,7 +1046,7 @@
 
 /**
  * scsi_report_lun_scan - Scan using SCSI REPORT LUN results
- * @sdevscan:	scan the host, channel, and id of this Scsi_Device
+ * @sdevscan:	scan the host, channel, and id of this scsi_device
  *
  * Description:
  *     If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
@@ -1074,6 +1074,7 @@
 	struct scsi_sense_hdr sshdr;
 	struct scsi_device *sdev;
 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+	int ret = 0;
 
 	/*
 	 * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
@@ -1169,8 +1170,8 @@
 		/*
 		 * The device probably does not support a REPORT LUN command
 		 */
-		kfree(lun_data);
-		return 1;
+		ret = 1;
+		goto out_err;
 	}
 
 	/*
@@ -1238,6 +1239,7 @@
 		}
 	}
 
+ out_err:
 	kfree(lun_data);
  out:
 	scsi_device_put(sdev);
@@ -1246,7 +1248,7 @@
 		 * the sdev we used didn't appear in the report luns scan
 		 */
 		scsi_destroy_sdev(sdev);
-	return 0;
+	return ret;
 }
 
 struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
@@ -1472,16 +1474,16 @@
 /*
  * Function:    scsi_get_host_dev()
  *
- * Purpose:     Create a Scsi_Device that points to the host adapter itself.
+ * Purpose:     Create a scsi_device that points to the host adapter itself.
  *
- * Arguments:   SHpnt   - Host that needs a Scsi_Device
+ * Arguments:   SHpnt   - Host that needs a scsi_device
  *
  * Lock status: None assumed.
  *
- * Returns:     The Scsi_Device or NULL
+ * Returns:     The scsi_device or NULL
  *
  * Notes:
- *	Attach a single Scsi_Device to the Scsi_Host - this should
+ *	Attach a single scsi_device to the Scsi_Host - this should
  *	be made to look like a "pseudo-device" that points to the
  *	HA itself.
  *
@@ -1518,7 +1520,7 @@
  *
  * Purpose:     Free a scsi_device that points to the host adapter itself.
  *
- * Arguments:   SHpnt   - Host that needs a Scsi_Device
+ * Arguments:   SHpnt   - Host that needs a scsi_device
  *
  * Lock status: None assumed.
  *
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 72a6550..4634929 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -691,16 +691,19 @@
 
 void __scsi_remove_device(struct scsi_device *sdev)
 {
+	struct device *dev = &sdev->sdev_gendev;
+
 	if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
 		return;
 
 	class_device_unregister(&sdev->sdev_classdev);
-	device_del(&sdev->sdev_gendev);
+	transport_remove_device(dev);
+	device_del(dev);
 	scsi_device_set_state(sdev, SDEV_DEL);
 	if (sdev->host->hostt->slave_destroy)
 		sdev->host->hostt->slave_destroy(sdev);
-	transport_unregister_device(&sdev->sdev_gendev);
-	put_device(&sdev->sdev_gendev);
+	transport_destroy_device(dev);
+	put_device(dev);
 }
 
 /**
diff --git a/drivers/scsi/scsi_typedefs.h b/drivers/scsi/scsi_typedefs.h
index 6c43132..29f038b 100644
--- a/drivers/scsi/scsi_typedefs.h
+++ b/drivers/scsi/scsi_typedefs.h
@@ -1,6 +1,3 @@
 
-typedef struct scsi_host_template Scsi_Host_Template;
-typedef struct scsi_device Scsi_Device;
 typedef struct scsi_cmnd Scsi_Cmnd;
 typedef struct scsi_request Scsi_Request;
-typedef struct scsi_pointer Scsi_Pointer;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index bb5b242..8613a13 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -769,20 +769,16 @@
 static int sd_prepare_flush(request_queue_t *q, struct request *rq)
 {
 	struct scsi_device *sdev = q->queuedata;
-	struct scsi_disk *sdkp = scsi_disk_get_from_dev(&sdev->sdev_gendev);
-	int ret = 0;
+	struct scsi_disk *sdkp = dev_get_drvdata(&sdev->sdev_gendev);
 
-	if (sdkp) {
-		if (sdkp->WCE) {
-			memset(rq->cmd, 0, sizeof(rq->cmd));
-			rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
-			rq->timeout = SD_TIMEOUT;
-			rq->cmd[0] = SYNCHRONIZE_CACHE;
-			ret = 1;
-		}
-		scsi_disk_put(sdkp);
-	}
-	return ret;
+	if (!sdkp || !sdkp->WCE)
+		return 0;
+
+	memset(rq->cmd, 0, sizeof(rq->cmd));
+	rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+	rq->timeout = SD_TIMEOUT;
+	rq->cmd[0] = SYNCHRONIZE_CACHE;
+	return 1;
 }
 
 static void sd_rescan(struct device *dev)
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index a0cace9..0ff83dd 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -418,7 +418,7 @@
 #define ULOOP( i ) for (clock = i*8;;)
 #define TIMEOUT (!(clock--))
 
-int __init seagate_st0x_detect (Scsi_Host_Template * tpnt)
+int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
 {
 	struct Scsi_Host *instance;
 	int i, j;
@@ -1649,7 +1649,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.detect         	= seagate_st0x_detect,
 	.release        	= seagate_st0x_release,
 	.info           	= seagate_st0x_info,
diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
index 8889ff1a..fb5f380 100644
--- a/drivers/scsi/seagate.h
+++ b/drivers/scsi/seagate.h
@@ -9,7 +9,7 @@
 #ifndef _SEAGATE_H
 #define SEAGATE_H
 
-static int seagate_st0x_detect(Scsi_Host_Template *);
+static int seagate_st0x_detect(struct scsi_host_template *);
 static int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 
 static int seagate_st0x_abort(Scsi_Cmnd *);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 62e3f34..72ec594 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -68,10 +68,6 @@
 static void sg_proc_cleanup(void);
 #endif
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif				/* LINUX_VERSION_CODE */
-
 #define SG_ALLOW_DIO_DEF 0
 #define SG_ALLOW_DIO_CODE /* compile out by commenting this define */
 
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 09fd203..bf2ceb5 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -15,7 +15,6 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/blkdev.h>
-#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
@@ -218,7 +217,7 @@
 }
 
 static struct Scsi_Host * __init sgiwd93_setup_scsi(
-	Scsi_Host_Template *SGIblows, int unit, int irq,
+	struct scsi_host_template *SGIblows, int unit, int irq,
 	struct hpc3_scsiregs *hregs, unsigned char *wdregs)
 {
 	struct ip22_hostdata *hdata;
@@ -266,7 +265,7 @@
 	return NULL;
 }
 
-int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
+int __init sgiwd93_detect(struct scsi_host_template *SGIblows)
 {
 	int found = 0;
 
@@ -325,7 +324,7 @@
  * arguments not with pointers.  So this is going to blow up beautyfully
  * on 64-bit systems with memory outside the compat address spaces.
  */
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "SGIWD93",
 	.name			= "SGI WD93",
 	.detect			= sgiwd93_detect,
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 7e19589..c041bfd 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -257,7 +257,7 @@
  */
 
 static struct Scsi_Host *first_instance = NULL;
-static Scsi_Host_Template *the_template = NULL;
+static struct scsi_host_template *the_template = NULL;
 
 /* Macros ease life... :-) */
 #define	SETUP_HOSTDATA(in)				\
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index e3ea99f..8371734 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -185,7 +185,7 @@
 static struct Scsi_Host *default_instance;
 
 /*
- * Function : int sun3scsi_detect(Scsi_Host_Template * tpnt)
+ * Function : int sun3scsi_detect(struct scsi_host_template * tpnt)
  *
  * Purpose : initializes mac NCR5380 driver based on the
  *	command line / compile time port and irq definitions.
@@ -196,7 +196,7 @@
  *
  */
  
-int sun3scsi_detect(Scsi_Host_Template * tpnt)
+int sun3scsi_detect(struct scsi_host_template * tpnt)
 {
 	unsigned long ioaddr;
 	static int called = 0;
@@ -621,7 +621,7 @@
 	
 #include "sun3_NCR5380.c"
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name			= SUN3_SCSI_NAME,
 	.detect			= sun3scsi_detect,
 	.release		= sun3scsi_release,
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index 155282b..834dab4 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -48,7 +48,7 @@
 #define IOBASE_SUN3_VMESCSI 0xff200000
 
 static int sun3scsi_abort (Scsi_Cmnd *);
-static int sun3scsi_detect (Scsi_Host_Template *);
+static int sun3scsi_detect (struct scsi_host_template *);
 static const char *sun3scsi_info (struct Scsi_Host *);
 static int sun3scsi_bus_reset(Scsi_Cmnd *);
 static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
index 9acb5dd..008a82a 100644
--- a/drivers/scsi/sun3_scsi_vme.c
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -127,7 +127,7 @@
 static struct Scsi_Host *default_instance;
 
 /*
- * Function : int sun3scsi_detect(Scsi_Host_Template * tpnt)
+ * Function : int sun3scsi_detect(struct scsi_host_template * tpnt)
  *
  * Purpose : initializes mac NCR5380 driver based on the
  *	command line / compile time port and irq definitions.
@@ -138,7 +138,7 @@
  *
  */
  
-static int sun3scsi_detect(Scsi_Host_Template * tpnt)
+static int sun3scsi_detect(struct scsi_host_template * tpnt)
 {
 	unsigned long ioaddr, irq = 0;
 	static int called = 0;
@@ -564,7 +564,7 @@
 
 #include "sun3_NCR5380.c"
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name			= SUN3_SCSI_NAME,
 	.detect			= sun3scsi_detect,
 	.release		= sun3scsi_release,
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 09d7639..cc990be 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -47,7 +47,7 @@
 /* Detecting ESP chips on the machine.  This is the simple and easy
  * version.
  */
-int sun3x_esp_detect(Scsi_Host_Template *tpnt)
+int sun3x_esp_detect(struct scsi_host_template *tpnt)
 {
 	struct NCR_ESP *esp;
 	struct ConfigDev *esp_dev;
@@ -367,7 +367,7 @@
 
 }
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "sun3x_esp",
 	.proc_info		= &esp_proc_info,
 	.name			= "Sun ESP 100/100a/200",
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 93dc7b6..8640253 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -633,7 +633,7 @@
 	}
 }
 
-int __init sym53c416_detect(Scsi_Host_Template *tpnt)
+int __init sym53c416_detect(struct scsi_host_template *tpnt)
 {
 	unsigned long flags;
 	struct Scsi_Host * shpnt = NULL;
@@ -849,7 +849,7 @@
 
 #endif
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name =		"sym53c416",
 	.name =			"Symbios Logic 53c416",
 	.detect =		sym53c416_detect,
diff --git a/drivers/scsi/sym53c416.h b/drivers/scsi/sym53c416.h
index fd6b120..77860d0 100644
--- a/drivers/scsi/sym53c416.h
+++ b/drivers/scsi/sym53c416.h
@@ -22,7 +22,7 @@
 
 #define SYM53C416_SCSI_ID 7
 
-static int sym53c416_detect(Scsi_Host_Template *);
+static int sym53c416_detect(struct scsi_host_template *);
 static const char *sym53c416_info(struct Scsi_Host *);
 static int sym53c416_release(struct Scsi_Host *);
 static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index f4b780e..21305fc 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -183,7 +183,7 @@
 }
 
 /* 
- * Function : int t128_detect(Scsi_Host_Template * tpnt)
+ * Function : int t128_detect(struct scsi_host_template * tpnt)
  *
  * Purpose : detects and initializes T128,T128F, or T228 controllers
  *	that were autoprobed, overridden on the LILO command line, 
@@ -195,7 +195,7 @@
  *
  */
 
-int __init t128_detect(Scsi_Host_Template * tpnt){
+int __init t128_detect(struct scsi_host_template * tpnt){
     static int current_override = 0, current_base = 0;
     struct Scsi_Host *instance;
     unsigned long base;
@@ -430,7 +430,7 @@
 
 #include "NCR5380.c"
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name           = "Trantor T128/T128F/T228",
 	.detect         = t128_detect,
 	.release        = t128_release,
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index 596f3a3..646e840 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -95,7 +95,7 @@
 static int t128_abort(Scsi_Cmnd *);
 static int t128_biosparam(struct scsi_device *, struct block_device *,
 			  sector_t, int*);
-static int t128_detect(Scsi_Host_Template *);
+static int t128_detect(struct scsi_host_template *);
 static int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int t128_bus_reset(Scsi_Cmnd *);
 
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 1ce29ba..33cd90f 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -282,7 +282,7 @@
  *  clustering is enabled. ENABLE_CLUSTERING provides a performance increase
  *  up to 50% on sequential access.
  *
- *  Since the Scsi_Host_Template structure is shared among all 14F and 34F,
+ *  Since the struct scsi_host_template structure is shared among all 14F and 34F,
  *  the last setting of use_clustering is in effect for all of these boards.
  *
  *  Here a sample configuration using two U14F boards:
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 486551b..e681681 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -343,7 +343,7 @@
 }
 #endif
 
-static int ultrastor_14f_detect(Scsi_Host_Template * tpnt)
+static int ultrastor_14f_detect(struct scsi_host_template * tpnt)
 {
     size_t i;
     unsigned char in_byte, version_byte = 0;
@@ -525,7 +525,7 @@
     return FALSE;
 }
 
-static int ultrastor_24f_detect(Scsi_Host_Template * tpnt)
+static int ultrastor_24f_detect(struct scsi_host_template * tpnt)
 {
   int i;
   struct Scsi_Host * shpnt = NULL;
@@ -637,7 +637,7 @@
   return FALSE;
 }
 
-static int ultrastor_detect(Scsi_Host_Template * tpnt)
+static int ultrastor_detect(struct scsi_host_template * tpnt)
 {
 	tpnt->proc_name = "ultrastor";
 	return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt);
@@ -1184,7 +1184,7 @@
 
 MODULE_LICENSE("GPL");
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name              = "UltraStor 14F/24F/34F",
 	.detect            = ultrastor_detect,
 	.release	   = ultrastor_release,
diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
index 0a0f8df..da759a1 100644
--- a/drivers/scsi/ultrastor.h
+++ b/drivers/scsi/ultrastor.h
@@ -13,7 +13,7 @@
 #ifndef _ULTRASTOR_H
 #define _ULTRASTOR_H
 
-static int ultrastor_detect(Scsi_Host_Template *);
+static int ultrastor_detect(struct scsi_host_template *);
 static const char *ultrastor_info(struct Scsi_Host * shpnt);
 static int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int ultrastor_abort(Scsi_Cmnd *);
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 5754445..fd63add 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -77,7 +77,6 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <asm/irq.h>
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 9882060..3742753 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2381,9 +2381,9 @@
  * list is terminated with a zero flags entry, which means we expect
  * all entries to have at least UPF_BOOT_AUTOCONF set.
  */
-static int __devinit serial8250_probe(struct device *dev)
+static int __devinit serial8250_probe(struct platform_device *dev)
 {
-	struct plat_serial8250_port *p = dev->platform_data;
+	struct plat_serial8250_port *p = dev->dev.platform_data;
 	struct uart_port port;
 	int ret, i;
 
@@ -2399,12 +2399,12 @@
 		port.flags	= p->flags;
 		port.mapbase	= p->mapbase;
 		port.hub6	= p->hub6;
-		port.dev	= dev;
+		port.dev	= &dev->dev;
 		if (share_irqs)
 			port.flags |= UPF_SHARE_IRQ;
 		ret = serial8250_register_port(&port);
 		if (ret < 0) {
-			dev_err(dev, "unable to register port at index %d "
+			dev_err(&dev->dev, "unable to register port at index %d "
 				"(IO%lx MEM%lx IRQ%d): %d\n", i,
 				p->iobase, p->mapbase, p->irq, ret);
 		}
@@ -2415,54 +2415,55 @@
 /*
  * Remove serial ports registered against a platform device.
  */
-static int __devexit serial8250_remove(struct device *dev)
+static int __devexit serial8250_remove(struct platform_device *dev)
 {
 	int i;
 
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
 
-		if (up->port.dev == dev)
+		if (up->port.dev == &dev->dev)
 			serial8250_unregister_port(i);
 	}
 	return 0;
 }
 
-static int serial8250_suspend(struct device *dev, pm_message_t state)
+static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
 {
 	int i;
 
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
 
-		if (up->port.type != PORT_UNKNOWN && up->port.dev == dev)
+		if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
 			uart_suspend_port(&serial8250_reg, &up->port);
 	}
 
 	return 0;
 }
 
-static int serial8250_resume(struct device *dev)
+static int serial8250_resume(struct platform_device *dev)
 {
 	int i;
 
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
 
-		if (up->port.type != PORT_UNKNOWN && up->port.dev == dev)
+		if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
 			uart_resume_port(&serial8250_reg, &up->port);
 	}
 
 	return 0;
 }
 
-static struct device_driver serial8250_isa_driver = {
-	.name		= "serial8250",
-	.bus		= &platform_bus_type,
+static struct platform_driver serial8250_isa_driver = {
 	.probe		= serial8250_probe,
 	.remove		= __devexit_p(serial8250_remove),
 	.suspend	= serial8250_suspend,
 	.resume		= serial8250_resume,
+	.driver		= {
+		.name	= "serial8250",
+	},
 };
 
 /*
@@ -2608,7 +2609,7 @@
 
 	serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
 
-	ret = driver_register(&serial8250_isa_driver);
+	ret = platform_driver_register(&serial8250_isa_driver);
 	if (ret == 0)
 		goto out;
 
@@ -2630,7 +2631,7 @@
 	 */
 	serial8250_isa_devs = NULL;
 
-	driver_unregister(&serial8250_isa_driver);
+	platform_driver_unregister(&serial8250_isa_driver);
 	platform_device_unregister(isa_dev);
 
 	uart_unregister_driver(&serial8250_reg);
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 4a54ff5..355cd93 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -921,9 +921,9 @@
 	.cons           = IMX_CONSOLE,
 };
 
-static int serial_imx_suspend(struct device *_dev, pm_message_t state)
+static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
 {
-        struct imx_port *sport = dev_get_drvdata(_dev);
+        struct imx_port *sport = platform_get_drvdata(dev);
 
         if (sport)
                 uart_suspend_port(&imx_reg, &sport->port);
@@ -931,9 +931,9 @@
         return 0;
 }
 
-static int serial_imx_resume(struct device *_dev)
+static int serial_imx_resume(struct platform_device *dev)
 {
-        struct imx_port *sport = dev_get_drvdata(_dev);
+        struct imx_port *sport = platform_get_drvdata(dev);
 
         if (sport)
                 uart_resume_port(&imx_reg, &sport->port);
@@ -941,21 +941,19 @@
         return 0;
 }
 
-static int serial_imx_probe(struct device *_dev)
+static int serial_imx_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(_dev);
-
-	imx_ports[dev->id].port.dev = _dev;
+	imx_ports[dev->id].port.dev = &dev->dev;
 	uart_add_one_port(&imx_reg, &imx_ports[dev->id].port);
-	dev_set_drvdata(_dev, &imx_ports[dev->id]);
+	platform_set_drvdata(dev, &imx_ports[dev->id]);
 	return 0;
 }
 
-static int serial_imx_remove(struct device *_dev)
+static int serial_imx_remove(struct platform_device *dev)
 {
-	struct imx_port *sport = dev_get_drvdata(_dev);
+	struct imx_port *sport = platform_get_drvdata(dev);
 
-	dev_set_drvdata(_dev, NULL);
+	platform_set_drvdata(dev, NULL);
 
 	if (sport)
 		uart_remove_one_port(&imx_reg, &sport->port);
@@ -963,14 +961,15 @@
 	return 0;
 }
 
-static struct device_driver serial_imx_driver = {
-        .name           = "imx-uart",
-        .bus            = &platform_bus_type,
+static struct platform_driver serial_imx_driver = {
         .probe          = serial_imx_probe,
         .remove         = serial_imx_remove,
 
 	.suspend	= serial_imx_suspend,
 	.resume		= serial_imx_resume,
+	.driver		= {
+	        .name	= "imx-uart",
+	},
 };
 
 static int __init imx_serial_init(void)
@@ -985,7 +984,7 @@
 	if (ret)
 		return ret;
 
-	ret = driver_register(&serial_imx_driver);
+	ret = platform_driver_register(&serial_imx_driver);
 	if (ret != 0)
 		uart_unregister_driver(&imx_reg);
 
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 0dd08a0..5d3cb84 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -717,10 +717,9 @@
 /* ======================================================================== */
 
 static int __devinit
-mpc52xx_uart_probe(struct device *dev)
+mpc52xx_uart_probe(struct platform_device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct resource *res = pdev->resource;
+	struct resource *res = dev->resource;
 
 	struct uart_port *port = NULL;
 	int i, idx, ret;
@@ -761,17 +760,17 @@
 	/* Add the port to the uart sub-system */
 	ret = uart_add_one_port(&mpc52xx_uart_driver, port);
 	if (!ret)
-		dev_set_drvdata(dev, (void*)port);
+		platform_set_drvdata(dev, (void*)port);
 
 	return ret;
 }
 
 static int
-mpc52xx_uart_remove(struct device *dev)
+mpc52xx_uart_remove(struct platform_device *dev)
 {
-	struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev);
+	struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
 
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(dev, NULL);
 
 	if (port)
 		uart_remove_one_port(&mpc52xx_uart_driver, port);
@@ -781,9 +780,9 @@
 
 #ifdef CONFIG_PM
 static int
-mpc52xx_uart_suspend(struct device *dev, pm_message_t state)
+mpc52xx_uart_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev);
+	struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
 
 	if (sport)
 		uart_suspend_port(&mpc52xx_uart_driver, port);
@@ -792,9 +791,9 @@
 }
 
 static int
-mpc52xx_uart_resume(struct device *dev)
+mpc52xx_uart_resume(struct platform_device *dev)
 {
-	struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev);
+	struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
 
 	if (port)
 		uart_resume_port(&mpc52xx_uart_driver, port);
@@ -803,15 +802,16 @@
 }
 #endif
 
-static struct device_driver mpc52xx_uart_platform_driver = {
-	.name		= "mpc52xx-psc",
-	.bus		= &platform_bus_type,
+static struct platform_driver mpc52xx_uart_platform_driver = {
 	.probe		= mpc52xx_uart_probe,
 	.remove		= mpc52xx_uart_remove,
 #ifdef CONFIG_PM
 	.suspend	= mpc52xx_uart_suspend,
 	.resume		= mpc52xx_uart_resume,
 #endif
+	.driver		= {
+		.name	= "mpc52xx-psc",
+	},
 };
 
 
@@ -828,7 +828,7 @@
 
 	ret = uart_register_driver(&mpc52xx_uart_driver);
 	if (ret == 0) {
-		ret = driver_register(&mpc52xx_uart_platform_driver);
+		ret = platform_driver_register(&mpc52xx_uart_platform_driver);
 		if (ret)
 			uart_unregister_driver(&mpc52xx_uart_driver);
 	}
@@ -839,7 +839,7 @@
 static void __exit
 mpc52xx_uart_exit(void)
 {
-	driver_unregister(&mpc52xx_uart_platform_driver);
+	platform_driver_unregister(&mpc52xx_uart_platform_driver);
 	uart_unregister_driver(&mpc52xx_uart_driver);
 }
 
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index ba8838b..8f83e40 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -1551,15 +1551,14 @@
 }
 
 static int
-mpsc_shared_drv_probe(struct device *dev)
+mpsc_shared_drv_probe(struct platform_device *dev)
 {
-	struct platform_device		*pd = to_platform_device(dev);
 	struct mpsc_shared_pdata	*pdata;
 	int				 rc = -ENODEV;
 
-	if (pd->id == 0) {
-		if (!(rc = mpsc_shared_map_regs(pd)))  {
-			pdata = (struct mpsc_shared_pdata *)dev->platform_data;
+	if (dev->id == 0) {
+		if (!(rc = mpsc_shared_map_regs(dev)))  {
+			pdata = (struct mpsc_shared_pdata *)dev->dev.platform_data;
 
 			mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
 			mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
@@ -1577,12 +1576,11 @@
 }
 
 static int
-mpsc_shared_drv_remove(struct device *dev)
+mpsc_shared_drv_remove(struct platform_device *dev)
 {
-	struct platform_device	*pd = to_platform_device(dev);
 	int	rc = -ENODEV;
 
-	if (pd->id == 0) {
+	if (dev->id == 0) {
 		mpsc_shared_unmap_regs();
 		mpsc_shared_regs.MPSC_MRR_m = 0;
 		mpsc_shared_regs.MPSC_RCRR_m = 0;
@@ -1595,11 +1593,12 @@
 	return rc;
 }
 
-static struct device_driver mpsc_shared_driver = {
-	.name	= MPSC_SHARED_NAME,
-	.bus	= &platform_bus_type,
+static struct platform_driver mpsc_shared_driver = {
 	.probe	= mpsc_shared_drv_probe,
 	.remove	= mpsc_shared_drv_remove,
+	.driver	= {
+		.name = MPSC_SHARED_NAME,
+	},
 };
 
 /*
@@ -1732,19 +1731,18 @@
 }
 
 static int
-mpsc_drv_probe(struct device *dev)
+mpsc_drv_probe(struct platform_device *dev)
 {
-	struct platform_device	*pd = to_platform_device(dev);
 	struct mpsc_port_info	*pi;
 	int			rc = -ENODEV;
 
-	pr_debug("mpsc_drv_probe: Adding MPSC %d\n", pd->id);
+	pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);
 
-	if (pd->id < MPSC_NUM_CTLRS) {
-		pi = &mpsc_ports[pd->id];
+	if (dev->id < MPSC_NUM_CTLRS) {
+		pi = &mpsc_ports[dev->id];
 
-		if (!(rc = mpsc_drv_map_regs(pi, pd))) {
-			mpsc_drv_get_platform_data(pi, pd, pd->id);
+		if (!(rc = mpsc_drv_map_regs(pi, dev))) {
+			mpsc_drv_get_platform_data(pi, dev, dev->id);
 
 			if (!(rc = mpsc_make_ready(pi)))
 				if (!(rc = uart_add_one_port(&mpsc_reg,
@@ -1764,27 +1762,26 @@
 }
 
 static int
-mpsc_drv_remove(struct device *dev)
+mpsc_drv_remove(struct platform_device *dev)
 {
-	struct platform_device	*pd = to_platform_device(dev);
+	pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
 
-	pr_debug("mpsc_drv_exit: Removing MPSC %d\n", pd->id);
-
-	if (pd->id < MPSC_NUM_CTLRS) {
-		uart_remove_one_port(&mpsc_reg, &mpsc_ports[pd->id].port);
-		mpsc_release_port((struct uart_port *)&mpsc_ports[pd->id].port);
-		mpsc_drv_unmap_regs(&mpsc_ports[pd->id]);
+	if (dev->id < MPSC_NUM_CTLRS) {
+		uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
+		mpsc_release_port((struct uart_port *)&mpsc_ports[dev->id].port);
+		mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
 		return 0;
 	}
 	else
 		return -ENODEV;
 }
 
-static struct device_driver mpsc_driver = {
-	.name	= MPSC_CTLR_NAME,
-	.bus	= &platform_bus_type,
+static struct platform_driver mpsc_driver = {
 	.probe	= mpsc_drv_probe,
 	.remove	= mpsc_drv_remove,
+	.driver	= {
+		.name = MPSC_CTLR_NAME,
+	},
 };
 
 static int __init
@@ -1798,9 +1795,9 @@
 	memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
 
 	if (!(rc = uart_register_driver(&mpsc_reg))) {
-		if (!(rc = driver_register(&mpsc_shared_driver))) {
-			if ((rc = driver_register(&mpsc_driver))) {
-				driver_unregister(&mpsc_shared_driver);
+		if (!(rc = platform_driver_register(&mpsc_shared_driver))) {
+			if ((rc = platform_driver_register(&mpsc_driver))) {
+				platform_driver_unregister(&mpsc_shared_driver);
 				uart_unregister_driver(&mpsc_reg);
 			}
 		}
@@ -1815,8 +1812,8 @@
 static void __exit
 mpsc_drv_exit(void)
 {
-	driver_unregister(&mpsc_driver);
-	driver_unregister(&mpsc_shared_driver);
+	platform_driver_unregister(&mpsc_driver);
+	platform_driver_unregister(&mpsc_shared_driver);
 	uart_unregister_driver(&mpsc_reg);
 	memset(mpsc_ports, 0, sizeof(mpsc_ports));
 	memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index 16b2f94..ff5e630 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -805,9 +805,9 @@
 	.cons		= PXA_CONSOLE,
 };
 
-static int serial_pxa_suspend(struct device *_dev, pm_message_t state)
+static int serial_pxa_suspend(struct platform_device *dev, pm_message_t state)
 {
-        struct uart_pxa_port *sport = dev_get_drvdata(_dev);
+        struct uart_pxa_port *sport = platform_get_drvdata(dev);
 
         if (sport)
                 uart_suspend_port(&serial_pxa_reg, &sport->port);
@@ -815,9 +815,9 @@
         return 0;
 }
 
-static int serial_pxa_resume(struct device *_dev)
+static int serial_pxa_resume(struct platform_device *dev)
 {
-        struct uart_pxa_port *sport = dev_get_drvdata(_dev);
+        struct uart_pxa_port *sport = platform_get_drvdata(dev);
 
         if (sport)
                 uart_resume_port(&serial_pxa_reg, &sport->port);
@@ -825,21 +825,19 @@
         return 0;
 }
 
-static int serial_pxa_probe(struct device *_dev)
+static int serial_pxa_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(_dev);
-
-	serial_pxa_ports[dev->id].port.dev = _dev;
+	serial_pxa_ports[dev->id].port.dev = &dev->dev;
 	uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port);
-	dev_set_drvdata(_dev, &serial_pxa_ports[dev->id]);
+	platform_set_drvdata(dev, &serial_pxa_ports[dev->id]);
 	return 0;
 }
 
-static int serial_pxa_remove(struct device *_dev)
+static int serial_pxa_remove(struct platform_device *dev)
 {
-	struct uart_pxa_port *sport = dev_get_drvdata(_dev);
+	struct uart_pxa_port *sport = platform_get_drvdata(dev);
 
-	dev_set_drvdata(_dev, NULL);
+	platform_set_drvdata(dev, NULL);
 
 	if (sport)
 		uart_remove_one_port(&serial_pxa_reg, &sport->port);
@@ -847,14 +845,15 @@
 	return 0;
 }
 
-static struct device_driver serial_pxa_driver = {
-        .name           = "pxa2xx-uart",
-        .bus            = &platform_bus_type,
+static struct platform_driver serial_pxa_driver = {
         .probe          = serial_pxa_probe,
         .remove         = serial_pxa_remove,
 
 	.suspend	= serial_pxa_suspend,
 	.resume		= serial_pxa_resume,
+	.driver		= {
+	        .name	= "pxa2xx-uart",
+	},
 };
 
 int __init serial_pxa_init(void)
@@ -865,7 +864,7 @@
 	if (ret != 0)
 		return ret;
 
-	ret = driver_register(&serial_pxa_driver);
+	ret = platform_driver_register(&serial_pxa_driver);
 	if (ret != 0)
 		uart_unregister_driver(&serial_pxa_reg);
 
@@ -874,7 +873,7 @@
 
 void __exit serial_pxa_exit(void)
 {
-        driver_unregister(&serial_pxa_driver);
+	platform_driver_unregister(&serial_pxa_driver);
 	uart_unregister_driver(&serial_pxa_reg);
 }
 
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 0367923..47681c4 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1092,14 +1092,13 @@
 
 static int probe_index = 0;
 
-static int s3c24xx_serial_probe(struct device *_dev,
+static int s3c24xx_serial_probe(struct platform_device *dev,
 				struct s3c24xx_uart_info *info)
 {
 	struct s3c24xx_uart_port *ourport;
-	struct platform_device *dev = to_platform_device(_dev);
 	int ret;
 
-	dbg("s3c24xx_serial_probe(%p, %p) %d\n", _dev, info, probe_index);
+	dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
 
 	ourport = &s3c24xx_serial_ports[probe_index];
 	probe_index++;
@@ -1112,7 +1111,7 @@
 
 	dbg("%s: adding port\n", __FUNCTION__);
 	uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
-	dev_set_drvdata(_dev, &ourport->port);
+	platform_set_drvdata(dev, &ourport->port);
 
 	return 0;
 
@@ -1120,9 +1119,9 @@
 	return ret;
 }
 
-static int s3c24xx_serial_remove(struct device *_dev)
+static int s3c24xx_serial_remove(struct platform_device *dev)
 {
-	struct uart_port *port = s3c24xx_dev_to_port(_dev);
+	struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
 
 	if (port)
 		uart_remove_one_port(&s3c24xx_uart_drv, port);
@@ -1134,9 +1133,9 @@
 
 #ifdef CONFIG_PM
 
-static int s3c24xx_serial_suspend(struct device *dev, pm_message_t state)
+static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct uart_port *port = s3c24xx_dev_to_port(dev);
+	struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
 
 	if (port)
 		uart_suspend_port(&s3c24xx_uart_drv, port);
@@ -1144,9 +1143,9 @@
 	return 0;
 }
 
-static int s3c24xx_serial_resume(struct device *dev)
+static int s3c24xx_serial_resume(struct platform_device *dev)
 {
-	struct uart_port *port = s3c24xx_dev_to_port(dev);
+	struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
 
 	if (port) {
@@ -1165,11 +1164,11 @@
 #define s3c24xx_serial_resume  NULL
 #endif
 
-static int s3c24xx_serial_init(struct device_driver *drv,
+static int s3c24xx_serial_init(struct platform_driver *drv,
 			       struct s3c24xx_uart_info *info)
 {
 	dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
-	return driver_register(drv);
+	return platform_driver_register(drv);
 }
 
 
@@ -1228,19 +1227,20 @@
 	.reset_port	= s3c2400_serial_resetport,
 };
 
-static int s3c2400_serial_probe(struct device *dev)
+static int s3c2400_serial_probe(struct platform_device *dev)
 {
 	return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
 }
 
-static struct device_driver s3c2400_serial_drv = {
-	.name		= "s3c2400-uart",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2400_serial_drv = {
 	.probe		= s3c2400_serial_probe,
 	.remove		= s3c24xx_serial_remove,
 	.suspend	= s3c24xx_serial_suspend,
 	.resume		= s3c24xx_serial_resume,
+	.driver		= {
+		.name	= "s3c2400-uart",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static inline int s3c2400_serial_init(void)
@@ -1250,7 +1250,7 @@
 
 static inline void s3c2400_serial_exit(void)
 {
-	driver_unregister(&s3c2400_serial_drv);
+	platform_driver_unregister(&s3c2400_serial_drv);
 }
 
 #define s3c2400_uart_inf_at &s3c2400_uart_inf
@@ -1332,19 +1332,20 @@
 
 /* device management */
 
-static int s3c2410_serial_probe(struct device *dev)
+static int s3c2410_serial_probe(struct platform_device *dev)
 {
 	return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
 }
 
-static struct device_driver s3c2410_serial_drv = {
-	.name		= "s3c2410-uart",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2410_serial_drv = {
 	.probe		= s3c2410_serial_probe,
 	.remove		= s3c24xx_serial_remove,
 	.suspend	= s3c24xx_serial_suspend,
 	.resume		= s3c24xx_serial_resume,
+	.driver		= {
+		.name	= "s3c2410-uart",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static inline int s3c2410_serial_init(void)
@@ -1354,7 +1355,7 @@
 
 static inline void s3c2410_serial_exit(void)
 {
-	driver_unregister(&s3c2410_serial_drv);
+	platform_driver_unregister(&s3c2410_serial_drv);
 }
 
 #define s3c2410_uart_inf_at &s3c2410_uart_inf
@@ -1493,20 +1494,21 @@
 
 /* device management */
 
-static int s3c2440_serial_probe(struct device *dev)
+static int s3c2440_serial_probe(struct platform_device *dev)
 {
 	dbg("s3c2440_serial_probe: dev=%p\n", dev);
 	return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
 }
 
-static struct device_driver s3c2440_serial_drv = {
-	.name		= "s3c2440-uart",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2440_serial_drv = {
 	.probe		= s3c2440_serial_probe,
 	.remove		= s3c24xx_serial_remove,
 	.suspend	= s3c24xx_serial_suspend,
 	.resume		= s3c24xx_serial_resume,
+	.driver		= {
+		.name	= "s3c2440-uart",
+		.owner	= THIS_MODULE,
+	},
 };
 
 
@@ -1517,7 +1519,7 @@
 
 static inline void s3c2440_serial_exit(void)
 {
-	driver_unregister(&s3c2440_serial_drv);
+	platform_driver_unregister(&s3c2440_serial_drv);
 }
 
 #define s3c2440_uart_inf_at &s3c2440_uart_inf
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index ed618cc..fd9deee 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -834,9 +834,9 @@
 	.cons			= SA1100_CONSOLE,
 };
 
-static int sa1100_serial_suspend(struct device *_dev, pm_message_t state)
+static int sa1100_serial_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct sa1100_port *sport = dev_get_drvdata(_dev);
+	struct sa1100_port *sport = platform_get_drvdata(dev);
 
 	if (sport)
 		uart_suspend_port(&sa1100_reg, &sport->port);
@@ -844,9 +844,9 @@
 	return 0;
 }
 
-static int sa1100_serial_resume(struct device *_dev)
+static int sa1100_serial_resume(struct platform_device *dev)
 {
-	struct sa1100_port *sport = dev_get_drvdata(_dev);
+	struct sa1100_port *sport = platform_get_drvdata(dev);
 
 	if (sport)
 		uart_resume_port(&sa1100_reg, &sport->port);
@@ -854,9 +854,8 @@
 	return 0;
 }
 
-static int sa1100_serial_probe(struct device *_dev)
+static int sa1100_serial_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(_dev);
 	struct resource *res = dev->resource;
 	int i;
 
@@ -869,9 +868,9 @@
 			if (sa1100_ports[i].port.mapbase != res->start)
 				continue;
 
-			sa1100_ports[i].port.dev = _dev;
+			sa1100_ports[i].port.dev = &dev->dev;
 			uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
-			dev_set_drvdata(_dev, &sa1100_ports[i]);
+			platform_set_drvdata(dev, &sa1100_ports[i]);
 			break;
 		}
 	}
@@ -879,11 +878,11 @@
 	return 0;
 }
 
-static int sa1100_serial_remove(struct device *_dev)
+static int sa1100_serial_remove(struct platform_device *pdev)
 {
-	struct sa1100_port *sport = dev_get_drvdata(_dev);
+	struct sa1100_port *sport = platform_get_drvdata(pdev);
 
-	dev_set_drvdata(_dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	if (sport)
 		uart_remove_one_port(&sa1100_reg, &sport->port);
@@ -891,13 +890,14 @@
 	return 0;
 }
 
-static struct device_driver sa11x0_serial_driver = {
-	.name		= "sa11x0-uart",
-	.bus		= &platform_bus_type,
+static struct platform_driver sa11x0_serial_driver = {
 	.probe		= sa1100_serial_probe,
 	.remove		= sa1100_serial_remove,
 	.suspend	= sa1100_serial_suspend,
 	.resume		= sa1100_serial_resume,
+	.driver		= {
+		.name	= "sa11x0-uart",
+	},
 };
 
 static int __init sa1100_serial_init(void)
@@ -910,7 +910,7 @@
 
 	ret = uart_register_driver(&sa1100_reg);
 	if (ret == 0) {
-		ret = driver_register(&sa11x0_serial_driver);
+		ret = platform_driver_register(&sa11x0_serial_driver);
 		if (ret)
 			uart_unregister_driver(&sa1100_reg);
 	}
@@ -919,7 +919,7 @@
 
 static void __exit sa1100_serial_exit(void)
 {
-	driver_unregister(&sa11x0_serial_driver);
+	platform_driver_unregister(&sa11x0_serial_driver);
 	uart_unregister_driver(&sa1100_reg);
 }
 
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index 01696b3..865d4de 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -924,7 +924,7 @@
 	.cons		= SERIAL_VR41XX_CONSOLE,
 };
 
-static int siu_probe(struct device *dev)
+static int siu_probe(struct platform_device *dev)
 {
 	struct uart_port *port;
 	int num, i, retval;
@@ -941,7 +941,7 @@
 	for (i = 0; i < num; i++) {
 		port = &siu_uart_ports[i];
 		port->ops = &siu_uart_ops;
-		port->dev = dev;
+		port->dev = &dev->dev;
 
 		retval = uart_add_one_port(&siu_uart_driver, port);
 		if (retval < 0) {
@@ -958,14 +958,14 @@
 	return 0;
 }
 
-static int siu_remove(struct device *dev)
+static int siu_remove(struct platform_device *dev)
 {
 	struct uart_port *port;
 	int i;
 
 	for (i = 0; i < siu_uart_driver.nr; i++) {
 		port = &siu_uart_ports[i];
-		if (port->dev == dev) {
+		if (port->dev == &dev->dev) {
 			uart_remove_one_port(&siu_uart_driver, port);
 			port->dev = NULL;
 		}
@@ -976,7 +976,7 @@
 	return 0;
 }
 
-static int siu_suspend(struct device *dev, pm_message_t state)
+static int siu_suspend(struct platform_device *dev, pm_message_t state)
 {
 	struct uart_port *port;
 	int i;
@@ -984,7 +984,7 @@
 	for (i = 0; i < siu_uart_driver.nr; i++) {
 		port = &siu_uart_ports[i];
 		if ((port->type == PORT_VR41XX_SIU ||
-		     port->type == PORT_VR41XX_DSIU) && port->dev == dev)
+		     port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
 			uart_suspend_port(&siu_uart_driver, port);
 
 	}
@@ -992,7 +992,7 @@
 	return 0;
 }
 
-static int siu_resume(struct device *dev)
+static int siu_resume(struct platform_device *dev)
 {
 	struct uart_port *port;
 	int i;
@@ -1000,7 +1000,7 @@
 	for (i = 0; i < siu_uart_driver.nr; i++) {
 		port = &siu_uart_ports[i];
 		if ((port->type == PORT_VR41XX_SIU ||
-		     port->type == PORT_VR41XX_DSIU) && port->dev == dev)
+		     port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
 			uart_resume_port(&siu_uart_driver, port);
 	}
 
@@ -1009,13 +1009,14 @@
 
 static struct platform_device *siu_platform_device;
 
-static struct device_driver siu_device_driver = {
-	.name		= "SIU",
-	.bus		= &platform_bus_type,
+static struct platform_driver siu_device_driver = {
 	.probe		= siu_probe,
 	.remove		= siu_remove,
 	.suspend	= siu_suspend,
 	.resume		= siu_resume,
+	.driver		= {
+		.name	= "SIU",
+	},
 };
 
 static int __devinit vr41xx_siu_init(void)
@@ -1026,7 +1027,7 @@
 	if (IS_ERR(siu_platform_device))
 		return PTR_ERR(siu_platform_device);
 
-	retval = driver_register(&siu_device_driver);
+	retval = platform_driver_register(&siu_device_driver);
 	if (retval < 0)
 		platform_device_unregister(siu_platform_device);
 
@@ -1035,7 +1036,7 @@
 
 static void __devexit vr41xx_siu_exit(void)
 {
-	driver_unregister(&siu_device_driver);
+	platform_driver_unregister(&siu_device_driver);
 
 	platform_device_unregister(siu_platform_device);
 }
diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h
index 51e3f7f..fbea454 100644
--- a/drivers/telephony/ixj.h
+++ b/drivers/telephony/ixj.h
@@ -40,7 +40,6 @@
  *****************************************************************************/
 #define IXJ_VERSION 3031
 
-#include <linux/version.h>
 #include <linux/types.h>
 
 #include <linux/ixjuser.h>
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 975ace3..1e40774 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -49,7 +49,6 @@
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/version.h>
 #include <linux/platform_device.h>
 #include <linux/usb.h>
 #include <linux/usb_gadget.h>
@@ -897,7 +896,7 @@
 #endif
 }
 
-static int dummy_udc_probe (struct device *dev)
+static int dummy_udc_probe (struct platform_device *dev)
 {
 	struct dummy	*dum = the_controller;
 	int		rc;
@@ -910,7 +909,7 @@
 	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
 
 	strcpy (dum->gadget.dev.bus_id, "gadget");
-	dum->gadget.dev.parent = dev;
+	dum->gadget.dev.parent = &dev->dev;
 	dum->gadget.dev.release = dummy_gadget_release;
 	rc = device_register (&dum->gadget.dev);
 	if (rc < 0)
@@ -920,26 +919,26 @@
 	usb_bus_get (&dummy_to_hcd (dum)->self);
 #endif
 
-	dev_set_drvdata (dev, dum);
+	platform_set_drvdata (dev, dum);
 	device_create_file (&dum->gadget.dev, &dev_attr_function);
 	return rc;
 }
 
-static int dummy_udc_remove (struct device *dev)
+static int dummy_udc_remove (struct platform_device *dev)
 {
-	struct dummy	*dum = dev_get_drvdata (dev);
+	struct dummy	*dum = platform_get_drvdata (dev);
 
-	dev_set_drvdata (dev, NULL);
+	platform_set_drvdata (dev, NULL);
 	device_remove_file (&dum->gadget.dev, &dev_attr_function);
 	device_unregister (&dum->gadget.dev);
 	return 0;
 }
 
-static int dummy_udc_suspend (struct device *dev, pm_message_t state)
+static int dummy_udc_suspend (struct platform_device *dev, pm_message_t state)
 {
-	struct dummy	*dum = dev_get_drvdata(dev);
+	struct dummy	*dum = platform_get_drvdata(dev);
 
-	dev_dbg (dev, "%s\n", __FUNCTION__);
+	dev_dbg (&dev->dev, "%s\n", __FUNCTION__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 1;
 	set_link_state (dum);
@@ -950,29 +949,30 @@
 	return 0;
 }
 
-static int dummy_udc_resume (struct device *dev)
+static int dummy_udc_resume (struct platform_device *dev)
 {
-	struct dummy	*dum = dev_get_drvdata(dev);
+	struct dummy	*dum = platform_get_drvdata(dev);
 
-	dev_dbg (dev, "%s\n", __FUNCTION__);
+	dev_dbg (&dev->dev, "%s\n", __FUNCTION__);
 	spin_lock_irq (&dum->lock);
 	dum->udc_suspended = 0;
 	set_link_state (dum);
 	spin_unlock_irq (&dum->lock);
 
-	dev->power.power_state = PMSG_ON;
+	dev->dev.power.power_state = PMSG_ON;
 	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
 	return 0;
 }
 
-static struct device_driver dummy_udc_driver = {
-	.name		= (char *) gadget_name,
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver dummy_udc_driver = {
 	.probe		= dummy_udc_probe,
 	.remove		= dummy_udc_remove,
 	.suspend	= dummy_udc_suspend,
 	.resume		= dummy_udc_resume,
+	.driver		= {
+		.name	= (char *) gadget_name,
+		.owner	= THIS_MODULE,
+	},
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1899,14 +1899,14 @@
 	.bus_resume =		dummy_bus_resume,
 };
 
-static int dummy_hcd_probe (struct device *dev)
+static int dummy_hcd_probe (struct platform_device *dev)
 {
 	struct usb_hcd		*hcd;
 	int			retval;
 
 	dev_info (dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
 
-	hcd = usb_create_hcd (&dummy_hcd, dev, dev->bus_id);
+	hcd = usb_create_hcd (&dummy_hcd, &dev->dev, dev->dev.bus_id);
 	if (!hcd)
 		return -ENOMEM;
 	the_controller = hcd_to_dummy (hcd);
@@ -1919,48 +1919,49 @@
 	return retval;
 }
 
-static int dummy_hcd_remove (struct device *dev)
+static int dummy_hcd_remove (struct platform_device *dev)
 {
 	struct usb_hcd		*hcd;
 
-	hcd = dev_get_drvdata (dev);
+	hcd = platform_get_drvdata (dev);
 	usb_remove_hcd (hcd);
 	usb_put_hcd (hcd);
 	the_controller = NULL;
 	return 0;
 }
 
-static int dummy_hcd_suspend (struct device *dev, pm_message_t state)
+static int dummy_hcd_suspend (struct platform_device *dev, pm_message_t state)
 {
 	struct usb_hcd		*hcd;
 
-	dev_dbg (dev, "%s\n", __FUNCTION__);
-	hcd = dev_get_drvdata (dev);
+	dev_dbg (&dev->dev, "%s\n", __FUNCTION__);
+	hcd = platform_get_drvdata (dev);
 
 	hcd->state = HC_STATE_SUSPENDED;
 	return 0;
 }
 
-static int dummy_hcd_resume (struct device *dev)
+static int dummy_hcd_resume (struct platform_device *dev)
 {
 	struct usb_hcd		*hcd;
 
-	dev_dbg (dev, "%s\n", __FUNCTION__);
-	hcd = dev_get_drvdata (dev);
+	dev_dbg (&dev->dev, "%s\n", __FUNCTION__);
+	hcd = platform_get_drvdata (dev);
 	hcd->state = HC_STATE_RUNNING;
 
 	usb_hcd_poll_rh_status (hcd);
 	return 0;
 }
 
-static struct device_driver dummy_hcd_driver = {
-	.name		= (char *) driver_name,
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver dummy_hcd_driver = {
 	.probe		= dummy_hcd_probe,
 	.remove		= dummy_hcd_remove,
 	.suspend	= dummy_hcd_suspend,
 	.resume		= dummy_hcd_resume,
+	.driver		= {
+		.name	= (char *) driver_name,
+		.owner	= THIS_MODULE,
+	},
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1996,11 +1997,11 @@
 	if (usb_disabled ())
 		return -ENODEV;
 
-	retval = driver_register (&dummy_hcd_driver);
+	retval = platform_driver_register (&dummy_hcd_driver);
 	if (retval < 0)
 		return retval;
 
-	retval = driver_register (&dummy_udc_driver);
+	retval = platform_driver_register (&dummy_udc_driver);
 	if (retval < 0)
 		goto err_register_udc_driver;
 
@@ -2016,9 +2017,9 @@
 err_register_udc:
 	platform_device_unregister (&the_hcd_pdev);
 err_register_hcd:
-	driver_unregister (&dummy_udc_driver);
+	platform_driver_unregister (&dummy_udc_driver);
 err_register_udc_driver:
-	driver_unregister (&dummy_hcd_driver);
+	platform_driver_unregister (&dummy_hcd_driver);
 	return retval;
 }
 module_init (init);
@@ -2027,7 +2028,7 @@
 {
 	platform_device_unregister (&the_udc_pdev);
 	platform_device_unregister (&the_hcd_pdev);
-	driver_unregister (&dummy_udc_driver);
-	driver_unregister (&dummy_hcd_driver);
+	platform_driver_unregister (&dummy_udc_driver);
+	platform_driver_unregister (&dummy_hcd_driver);
 }
 module_exit (cleanup);
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 6544697..b0f3cd6 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -1970,7 +1970,6 @@
 static struct pci_driver goku_pci_driver = {
 	.name =		(char *) driver_name,
 	.id_table =	pci_ids,
-	.owner =	THIS_MODULE,
 
 	.probe =	goku_probe,
 	.remove =	goku_remove,
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index bc6269f..e02fea5 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -2085,21 +2085,21 @@
 /*
  * 	probe - binds to the platform device
  */
-static int lh7a40x_udc_probe(struct device *_dev)
+static int lh7a40x_udc_probe(struct platform_device *pdev)
 {
 	struct lh7a40x_udc *dev = &memory;
 	int retval;
 
-	DEBUG("%s: %p\n", __FUNCTION__, _dev);
+	DEBUG("%s: %p\n", __FUNCTION__, pdev);
 
 	spin_lock_init(&dev->lock);
-	dev->dev = _dev;
+	dev->dev = &pdev->dev;
 
 	device_initialize(&dev->gadget.dev);
-	dev->gadget.dev.parent = _dev;
+	dev->gadget.dev.parent = &pdev->dev;
 
 	the_controller = dev;
-	dev_set_drvdata(_dev, dev);
+	platform_set_drvdata(pdev, dev);
 
 	udc_disable(dev);
 	udc_reinit(dev);
@@ -2119,11 +2119,11 @@
 	return retval;
 }
 
-static int lh7a40x_udc_remove(struct device *_dev)
+static int lh7a40x_udc_remove(struct platform_device *pdev)
 {
-	struct lh7a40x_udc *dev = _dev->driver_data;
+	struct lh7a40x_udc *dev = platform_get_drvdata(pdev);
 
-	DEBUG("%s: %p\n", __FUNCTION__, dev);
+	DEBUG("%s: %p\n", __FUNCTION__, pdev);
 
 	udc_disable(dev);
 	remove_proc_files();
@@ -2131,7 +2131,7 @@
 
 	free_irq(IRQ_USBINTR, dev);
 
-	dev_set_drvdata(_dev, 0);
+	platform_set_drvdata(pdev, 0);
 
 	the_controller = 0;
 
@@ -2140,26 +2140,27 @@
 
 /*-------------------------------------------------------------------------*/
 
-static struct device_driver udc_driver = {
-	.name = (char *)driver_name,
-	.owner = THIS_MODULE,
-	.bus = &platform_bus_type,
+static struct platform_driver udc_driver = {
 	.probe = lh7a40x_udc_probe,
 	.remove = lh7a40x_udc_remove
 	    /* FIXME power management support */
 	    /* .suspend = ... disable UDC */
 	    /* .resume = ... re-enable UDC */
+	.driver	= {
+		.name = (char *)driver_name,
+		.owner = THIS_MODULE,
+	},
 };
 
 static int __init udc_init(void)
 {
 	DEBUG("%s: %s version %s\n", __FUNCTION__, driver_name, DRIVER_VERSION);
-	return driver_register(&udc_driver);
+	return platform_driver_register(&udc_driver);
 }
 
 static void __exit udc_exit(void)
 {
-	driver_unregister(&udc_driver);
+	platform_driver_unregister(&udc_driver);
 }
 
 module_init(udc_init);
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index 1bb455c..9b2e6f7 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -29,7 +29,6 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/types.h>
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 0dc6bb0..c32e1f7 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -2948,7 +2948,6 @@
 static struct pci_driver net2280_pci_driver = {
 	.name =		(char *) driver_name,
 	.id_table =	pci_ids,
-	.owner =	THIS_MODULE,
 
 	.probe =	net2280_probe,
 	.remove =	net2280_remove,
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 387692a..a8972d7 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2707,18 +2707,17 @@
 	return 0;
 }
 
-static int __init omap_udc_probe(struct device *dev)
+static int __init omap_udc_probe(struct platform_device *pdev)
 {
-	struct platform_device	*odev = to_platform_device(dev);
 	int			status = -ENODEV;
 	int			hmc;
 	struct otg_transceiver	*xceiv = NULL;
 	const char		*type = NULL;
-	struct omap_usb_config	*config = dev->platform_data;
+	struct omap_usb_config	*config = pdev->dev.platform_data;
 
 	/* NOTE:  "knows" the order of the resources! */
-	if (!request_mem_region(odev->resource[0].start, 
-			odev->resource[0].end - odev->resource[0].start + 1,
+	if (!request_mem_region(pdev->resource[0].start, 
+			pdev->resource[0].end - pdev->resource[0].start + 1,
 			driver_name)) {
 		DBG("request_mem_region failed\n");
 		return -EBUSY;
@@ -2803,7 +2802,7 @@
 	INFO("hmc mode %d, %s transceiver\n", hmc, type);
 
 	/* a "gadget" abstracts/virtualizes the controller */
-	status = omap_udc_setup(odev, xceiv);
+	status = omap_udc_setup(pdev, xceiv);
 	if (status) {
 		goto cleanup0;
 	}
@@ -2821,28 +2820,28 @@
 		udc->clr_halt = UDC_RESET_EP;
 
 	/* USB general purpose IRQ:  ep0, state changes, dma, etc */
-	status = request_irq(odev->resource[1].start, omap_udc_irq,
+	status = request_irq(pdev->resource[1].start, omap_udc_irq,
 			SA_SAMPLE_RANDOM, driver_name, udc);
 	if (status != 0) {
 		ERR( "can't get irq %ld, err %d\n",
-			odev->resource[1].start, status);
+			pdev->resource[1].start, status);
 		goto cleanup1;
 	}
 
 	/* USB "non-iso" IRQ (PIO for all but ep0) */
-	status = request_irq(odev->resource[2].start, omap_udc_pio_irq,
+	status = request_irq(pdev->resource[2].start, omap_udc_pio_irq,
 			SA_SAMPLE_RANDOM, "omap_udc pio", udc);
 	if (status != 0) {
 		ERR( "can't get irq %ld, err %d\n",
-			odev->resource[2].start, status);
+			pdev->resource[2].start, status);
 		goto cleanup2;
 	}
 #ifdef	USE_ISO
-	status = request_irq(odev->resource[3].start, omap_udc_iso_irq,
+	status = request_irq(pdev->resource[3].start, omap_udc_iso_irq,
 			SA_INTERRUPT, "omap_udc iso", udc);
 	if (status != 0) {
 		ERR("can't get irq %ld, err %d\n",
-			odev->resource[3].start, status);
+			pdev->resource[3].start, status);
 		goto cleanup3;
 	}
 #endif
@@ -2853,11 +2852,11 @@
 
 #ifdef	USE_ISO
 cleanup3:
-	free_irq(odev->resource[2].start, udc);
+	free_irq(pdev->resource[2].start, udc);
 #endif
 
 cleanup2:
-	free_irq(odev->resource[1].start, udc);
+	free_irq(pdev->resource[1].start, udc);
 
 cleanup1:
 	kfree (udc);
@@ -2866,14 +2865,13 @@
 cleanup0:
 	if (xceiv)
 		put_device(xceiv->dev);
-	release_mem_region(odev->resource[0].start,
-			odev->resource[0].end - odev->resource[0].start + 1);
+	release_mem_region(pdev->resource[0].start,
+			pdev->resource[0].end - pdev->resource[0].start + 1);
 	return status;
 }
 
-static int __exit omap_udc_remove(struct device *dev)
+static int __exit omap_udc_remove(struct platform_device *pdev)
 {
-	struct platform_device	*odev = to_platform_device(dev);
 	DECLARE_COMPLETION(done);
 
 	if (!udc)
@@ -2891,13 +2889,13 @@
 	remove_proc_file();
 
 #ifdef	USE_ISO
-	free_irq(odev->resource[3].start, udc);
+	free_irq(pdev->resource[3].start, udc);
 #endif
-	free_irq(odev->resource[2].start, udc);
-	free_irq(odev->resource[1].start, udc);
+	free_irq(pdev->resource[2].start, udc);
+	free_irq(pdev->resource[1].start, udc);
 
-	release_mem_region(odev->resource[0].start,
-			odev->resource[0].end - odev->resource[0].start + 1);
+	release_mem_region(pdev->resource[0].start,
+			pdev->resource[0].end - pdev->resource[0].start + 1);
 
 	device_unregister(&udc->gadget.dev);
 	wait_for_completion(&done);
@@ -2915,7 +2913,7 @@
  * may involve talking to an external transceiver (e.g. isp1301).
  */
 
-static int omap_udc_suspend(struct device *dev, pm_message_t message)
+static int omap_udc_suspend(struct platform_device *dev, pm_message_t message)
 {
 	u32	devstat;
 
@@ -2935,7 +2933,7 @@
 	return 0;
 }
 
-static int omap_udc_resume(struct device *dev)
+static int omap_udc_resume(struct platform_device *dev)
 {
 	DBG("resume + wakeup/SRP\n");
 	omap_pullup(&udc->gadget, 1);
@@ -2947,14 +2945,15 @@
 
 /*-------------------------------------------------------------------------*/
 
-static struct device_driver udc_driver = {
-	.name		= (char *) driver_name,
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver udc_driver = {
 	.probe		= omap_udc_probe,
 	.remove		= __exit_p(omap_udc_remove),
 	.suspend	= omap_udc_suspend,
 	.resume		= omap_udc_resume,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= (char *) driver_name,
+	},
 };
 
 static int __init udc_init(void)
@@ -2965,13 +2964,13 @@
 #endif
 		"%s\n", driver_desc,
 		use_dma ?  " (dma)" : "");
-	return driver_register(&udc_driver);
+	return platform_driver_register(&udc_driver);
 }
 module_init(udc_init);
 
 static void __exit udc_exit(void)
 {
-	driver_unregister(&udc_driver);
+	platform_driver_unregister(&udc_driver);
 }
 module_exit(udc_exit);
 
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index ee9cd78..bb028c5 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -32,7 +32,6 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/types.h>
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
@@ -2433,7 +2432,7 @@
 /*
  * 	probe - binds to the platform device
  */
-static int __init pxa2xx_udc_probe(struct device *_dev)
+static int __init pxa2xx_udc_probe(struct platform_device *pdev)
 {
 	struct pxa2xx_udc *dev = &memory;
 	int retval, out_dma = 1;
@@ -2496,19 +2495,19 @@
 #endif
 
 	/* other non-static parts of init */
-	dev->dev = _dev;
-	dev->mach = _dev->platform_data;
+	dev->dev = &pdev->dev;
+	dev->mach = pdev->dev.platform_data;
 
 	init_timer(&dev->timer);
 	dev->timer.function = udc_watchdog;
 	dev->timer.data = (unsigned long) dev;
 
 	device_initialize(&dev->gadget.dev);
-	dev->gadget.dev.parent = _dev;
-	dev->gadget.dev.dma_mask = _dev->dma_mask;
+	dev->gadget.dev.parent = &pdev->dev;
+	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
 
 	the_controller = dev;
-	dev_set_drvdata(_dev, dev);
+	platform_set_drvdata(pdev, dev);
 
 	udc_disable(dev);
 	udc_reinit(dev);
@@ -2560,14 +2559,14 @@
 	return 0;
 }
 
-static void pxa2xx_udc_shutdown(struct device *_dev)
+static void pxa2xx_udc_shutdown(struct platform_device *_dev)
 {
 	pullup_off();
 }
 
-static int __exit pxa2xx_udc_remove(struct device *_dev)
+static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
 {
-	struct pxa2xx_udc *dev = dev_get_drvdata(_dev);
+	struct pxa2xx_udc *dev = platform_get_drvdata(pdev);
 
 	udc_disable(dev);
 	remove_proc_files();
@@ -2581,7 +2580,7 @@
 		free_irq(LUBBOCK_USB_DISC_IRQ, dev);
 		free_irq(LUBBOCK_USB_IRQ, dev);
 	}
-	dev_set_drvdata(_dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 	the_controller = NULL;
 	return 0;
 }
@@ -2602,9 +2601,9 @@
  * VBUS IRQs should probably be ignored so that the PXA device just acts
  * "dead" to USB hosts until system resume.
  */
-static int pxa2xx_udc_suspend(struct device *dev, pm_message_t state)
+static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct pxa2xx_udc	*udc = dev_get_drvdata(dev);
+	struct pxa2xx_udc	*udc = platform_get_drvdata(dev);
 
 	if (!udc->mach->udc_command)
 		WARN("USB host won't detect disconnect!\n");
@@ -2613,9 +2612,9 @@
 	return 0;
 }
 
-static int pxa2xx_udc_resume(struct device *dev)
+static int pxa2xx_udc_resume(struct platform_device *dev)
 {
-	struct pxa2xx_udc	*udc = dev_get_drvdata(dev);
+	struct pxa2xx_udc	*udc = platform_get_drvdata(dev);
 
 	pullup(udc, 1);
 
@@ -2629,27 +2628,28 @@
 
 /*-------------------------------------------------------------------------*/
 
-static struct device_driver udc_driver = {
-	.name		= "pxa2xx-udc",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver udc_driver = {
 	.probe		= pxa2xx_udc_probe,
 	.shutdown	= pxa2xx_udc_shutdown,
 	.remove		= __exit_p(pxa2xx_udc_remove),
 	.suspend	= pxa2xx_udc_suspend,
 	.resume		= pxa2xx_udc_resume,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "pxa2xx-udc",
+	},
 };
 
 static int __init udc_init(void)
 {
 	printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
-	return driver_register(&udc_driver);
+	return platform_driver_register(&udc_driver);
 }
 module_init(udc_init);
 
 static void __exit udc_exit(void)
 {
-	driver_unregister(&udc_driver);
+	platform_driver_unregister(&udc_driver);
 }
 module_exit(udc_exit);
 
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 06b6eba..9689efe 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -28,7 +28,6 @@
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/proc_fs.h>
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 1450088..dfd9bd0 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -383,7 +383,6 @@
 static struct pci_driver ehci_pci_driver = {
 	.name =		(char *) hcd_name,
 	.id_table =	pci_ids,
-	.owner = 	THIS_MODULE,
 
 	.probe =	usb_hcd_pci_probe,
 	.remove =	usb_hcd_pci_remove,
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index a8267cf..0eaabeb 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -14,7 +14,6 @@
 #include <linux/unistd.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index f9c3f5b..82f6498 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1633,17 +1633,15 @@
 
 /*----------------------------------------------------------------*/
 
-static int __init_or_module isp116x_remove(struct device *dev)
+static int __init_or_module isp116x_remove(struct platform_device *pdev)
 {
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct isp116x *isp116x;
-	struct platform_device *pdev;
 	struct resource *res;
 
 	if (!hcd)
 		return 0;
 	isp116x = hcd_to_isp116x(hcd);
-	pdev = container_of(dev, struct platform_device, dev);
 	remove_debug_file(isp116x);
 	usb_remove_hcd(hcd);
 
@@ -1660,18 +1658,16 @@
 
 #define resource_len(r) (((r)->end - (r)->start) + 1)
 
-static int __init isp116x_probe(struct device *dev)
+static int __init isp116x_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
 	struct isp116x *isp116x;
-	struct platform_device *pdev;
 	struct resource *addr, *data;
 	void __iomem *addr_reg;
 	void __iomem *data_reg;
 	int irq;
 	int ret = 0;
 
-	pdev = container_of(dev, struct platform_device, dev);
 	if (pdev->num_resources < 3) {
 		ret = -ENODEV;
 		goto err1;
@@ -1685,7 +1681,7 @@
 		goto err1;
 	}
 
-	if (dev->dma_mask) {
+	if (pdev->dev.dma_mask) {
 		DBG("DMA not supported\n");
 		ret = -EINVAL;
 		goto err1;
@@ -1711,7 +1707,7 @@
 	}
 
 	/* allocate and initialize hcd */
-	hcd = usb_create_hcd(&isp116x_hc_driver, dev, dev->bus_id);
+	hcd = usb_create_hcd(&isp116x_hc_driver, &pdev->dev, pdev->dev.bus_id);
 	if (!hcd) {
 		ret = -ENOMEM;
 		goto err5;
@@ -1723,7 +1719,7 @@
 	isp116x->addr_reg = addr_reg;
 	spin_lock_init(&isp116x->lock);
 	INIT_LIST_HEAD(&isp116x->async);
-	isp116x->board = dev->platform_data;
+	isp116x->board = pdev->dev.platform_data;
 
 	if (!isp116x->board) {
 		ERR("Platform data structure not initialized\n");
@@ -1764,13 +1760,13 @@
 /*
   Suspend of platform device
 */
-static int isp116x_suspend(struct device *dev, pm_message_t state)
+static int isp116x_suspend(struct platform_device *dev, pm_message_t state)
 {
 	int ret = 0;
 
 	VDBG("%s: state %x\n", __func__, state);
 
-	dev->power.power_state = state;
+	dev->dev.power.power_state = state;
 
 	return ret;
 }
@@ -1778,13 +1774,13 @@
 /*
   Resume platform device
 */
-static int isp116x_resume(struct device *dev)
+static int isp116x_resume(struct platform_device *dev)
 {
 	int ret = 0;
 
-	VDBG("%s:  state %x\n", __func__, dev->power.power_state);
+	VDBG("%s:  state %x\n", __func__, dev->dev.power.power_state);
 
-	dev->power.power_state = PMSG_ON;
+	dev->dev.power.power_state = PMSG_ON;
 
 	return ret;
 }
@@ -1796,13 +1792,14 @@
 
 #endif
 
-static struct device_driver isp116x_driver = {
-	.name = (char *)hcd_name,
-	.bus = &platform_bus_type,
+static struct platform_driver isp116x_driver = {
 	.probe = isp116x_probe,
 	.remove = isp116x_remove,
 	.suspend = isp116x_suspend,
 	.resume = isp116x_resume,
+	.driver	= {
+		.name = (char *)hcd_name,
+	},
 };
 
 /*-----------------------------------------------------------------*/
@@ -1813,14 +1810,14 @@
 		return -ENODEV;
 
 	INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
-	return driver_register(&isp116x_driver);
+	return platform_driver_register(&isp116x_driver);
 }
 
 module_init(isp116x_init);
 
 static void __exit isp116x_cleanup(void)
 {
-	driver_unregister(&isp116x_driver);
+	platform_driver_unregister(&isp116x_driver);
 }
 
 module_exit(isp116x_cleanup);
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index f0c78cf..d9cf3b3 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -225,9 +225,8 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int ohci_hcd_au1xxx_drv_probe(struct device *dev)
+static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	int ret;
 
 	pr_debug ("In ohci_hcd_au1xxx_drv_probe");
@@ -239,39 +238,37 @@
 	return ret;
 }
 
-static int ohci_hcd_au1xxx_drv_remove(struct device *dev)
+static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_hcd_au1xxx_remove(hcd, pdev);
 	return 0;
 }
 	/*TBD*/
-/*static int ohci_hcd_au1xxx_drv_suspend(struct device *dev)
+/*static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
 
 	return 0;
 }
-static int ohci_hcd_au1xxx_drv_resume(struct device *dev)
+static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
 
 	return 0;
 }
 */
 
-static struct device_driver ohci_hcd_au1xxx_driver = {
-	.name		= "au1xxx-ohci",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver ohci_hcd_au1xxx_driver = {
 	.probe		= ohci_hcd_au1xxx_drv_probe,
 	.remove		= ohci_hcd_au1xxx_drv_remove,
 	/*.suspend	= ohci_hcd_au1xxx_drv_suspend, */
 	/*.resume	= ohci_hcd_au1xxx_drv_resume, */
+	.driver		= {
+		.name	= "au1xxx-ohci",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static int __init ohci_hcd_au1xxx_init (void)
@@ -280,12 +277,12 @@
 	pr_debug ("block sizes: ed %d td %d\n",
 		sizeof (struct ed), sizeof (struct td));
 
-	return driver_register(&ohci_hcd_au1xxx_driver);
+	return platform_driver_register(&ohci_hcd_au1xxx_driver);
 }
 
 static void __exit ohci_hcd_au1xxx_cleanup (void)
 {
-	driver_unregister(&ohci_hcd_au1xxx_driver);
+	platform_driver_unregister(&ohci_hcd_au1xxx_driver);
 }
 
 module_init (ohci_hcd_au1xxx_init);
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index 336c766..081ec3f 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -204,9 +204,8 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int ohci_hcd_lh7a404_drv_probe(struct device *dev)
+static int ohci_hcd_lh7a404_drv_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	int ret;
 
 	pr_debug ("In ohci_hcd_lh7a404_drv_probe");
@@ -218,40 +217,38 @@
 	return ret;
 }
 
-static int ohci_hcd_lh7a404_drv_remove(struct device *dev)
+static int ohci_hcd_lh7a404_drv_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
 
 	usb_hcd_lh7a404_remove(hcd, pdev);
 	return 0;
 }
 	/*TBD*/
-/*static int ohci_hcd_lh7a404_drv_suspend(struct device *dev)
+/*static int ohci_hcd_lh7a404_drv_suspend(struct platform_device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
 
 	return 0;
 }
-static int ohci_hcd_lh7a404_drv_resume(struct device *dev)
+static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
 
 
 	return 0;
 }
 */
 
-static struct device_driver ohci_hcd_lh7a404_driver = {
-	.name		= "lh7a404-ohci",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver ohci_hcd_lh7a404_driver = {
 	.probe		= ohci_hcd_lh7a404_drv_probe,
 	.remove		= ohci_hcd_lh7a404_drv_remove,
 	/*.suspend	= ohci_hcd_lh7a404_drv_suspend, */
 	/*.resume	= ohci_hcd_lh7a404_drv_resume, */
+	.driver		= {
+		.name	= "lh7a404-ohci",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static int __init ohci_hcd_lh7a404_init (void)
@@ -260,12 +257,12 @@
 	pr_debug ("block sizes: ed %d td %d\n",
 		sizeof (struct ed), sizeof (struct td));
 
-	return driver_register(&ohci_hcd_lh7a404_driver);
+	return platform_driver_register(&ohci_hcd_lh7a404_driver);
 }
 
 static void __exit ohci_hcd_lh7a404_cleanup (void)
 {
-	driver_unregister(&ohci_hcd_lh7a404_driver);
+	platform_driver_unregister(&ohci_hcd_lh7a404_driver);
 }
 
 module_init (ohci_hcd_lh7a404_init);
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index e46cc54..c9e29d8 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -433,24 +433,22 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int ohci_hcd_omap_drv_probe(struct device *dev)
+static int ohci_hcd_omap_drv_probe(struct platform_device *dev)
 {
-	return usb_hcd_omap_probe(&ohci_omap_hc_driver,
-				to_platform_device(dev));
+	return usb_hcd_omap_probe(&ohci_omap_hc_driver, dev);
 }
 
-static int ohci_hcd_omap_drv_remove(struct device *dev)
+static int ohci_hcd_omap_drv_remove(struct platform_device *dev)
 {
-	struct platform_device	*pdev = to_platform_device(dev);
-	struct usb_hcd		*hcd = dev_get_drvdata(dev);
+	struct usb_hcd		*hcd = platform_get_drvdata(dev);
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
-	usb_hcd_omap_remove(hcd, pdev);
+	usb_hcd_omap_remove(hcd, dev);
 	if (ohci->transceiver) {
 		(void) otg_set_host(ohci->transceiver, 0);
 		put_device(ohci->transceiver->dev);
 	}
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(dev, NULL);
 
 	return 0;
 }
@@ -459,9 +457,9 @@
 
 #ifdef	CONFIG_PM
 
-static int ohci_omap_suspend(struct device *dev, pm_message_t message)
+static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)
 {
-	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
+	struct ohci_hcd	*ohci = hcd_to_ohci(platform_get_drvdata(dev));
 
 	if (time_before(jiffies, ohci->next_statechange))
 		msleep(5);
@@ -473,9 +471,9 @@
 	return 0;
 }
 
-static int ohci_omap_resume(struct device *dev)
+static int ohci_omap_resume(struct platform_device *dev)
 {
-	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
+	struct ohci_hcd	*ohci = hcd_to_ohci(platform_get_drvdata(dev));
 
 	if (time_before(jiffies, ohci->next_statechange))
 		msleep(5);
@@ -494,16 +492,17 @@
 /*
  * Driver definition to register with the OMAP bus
  */
-static struct device_driver ohci_hcd_omap_driver = {
-	.name		= "ohci",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver ohci_hcd_omap_driver = {
 	.probe		= ohci_hcd_omap_drv_probe,
 	.remove		= ohci_hcd_omap_drv_remove,
 #ifdef	CONFIG_PM
 	.suspend	= ohci_omap_suspend,
 	.resume		= ohci_omap_resume,
 #endif
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "ohci",
+	},
 };
 
 static int __init ohci_hcd_omap_init (void)
@@ -515,12 +514,12 @@
 	pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
 		sizeof (struct ed), sizeof (struct td));
 
-	return driver_register(&ohci_hcd_omap_driver);
+	return platform_driver_register(&ohci_hcd_omap_driver);
 }
 
 static void __exit ohci_hcd_omap_cleanup (void)
 {
-	driver_unregister(&ohci_hcd_omap_driver);
+	platform_driver_unregister(&ohci_hcd_omap_driver);
 }
 
 module_init (ohci_hcd_omap_init);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 7ce1d9e..a59e536 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -218,7 +218,6 @@
 static struct pci_driver ohci_pci_driver = {
 	.name =		(char *) hcd_name,
 	.id_table =	pci_ids,
-	.owner =	THIS_MODULE,
 
 	.probe =	usb_hcd_pci_probe,
 	.remove =	usb_hcd_pci_remove,
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 92cf6f4..1875576 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -172,9 +172,8 @@
 	.start_port_reset =	ohci_start_port_reset,
 };
 
-static int ohci_hcd_ppc_soc_drv_probe(struct device *dev)
+static int ohci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	int ret;
 
 	if (usb_disabled())
@@ -184,25 +183,25 @@
 	return ret;
 }
 
-static int ohci_hcd_ppc_soc_drv_remove(struct device *dev)
+static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
 
 	usb_hcd_ppc_soc_remove(hcd, pdev);
 	return 0;
 }
 
-static struct device_driver ohci_hcd_ppc_soc_driver = {
-	.name		= "ppc-soc-ohci",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver ohci_hcd_ppc_soc_driver = {
 	.probe		= ohci_hcd_ppc_soc_drv_probe,
 	.remove		= ohci_hcd_ppc_soc_drv_remove,
 #ifdef	CONFIG_PM
 	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
 	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
 #endif
+	.driver		= {
+		.name	= "ppc-soc-ohci",
+		.owner	= THIS_MODULE,
+	},
 };
 
 static int __init ohci_hcd_ppc_soc_init(void)
@@ -211,12 +210,12 @@
 	pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
 							sizeof(struct td));
 
-	return driver_register(&ohci_hcd_ppc_soc_driver);
+	return platform_driver_register(&ohci_hcd_ppc_soc_driver);
 }
 
 static void __exit ohci_hcd_ppc_soc_cleanup(void)
 {
-	driver_unregister(&ohci_hcd_ppc_soc_driver);
+	platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
 }
 
 module_init(ohci_hcd_ppc_soc_init);
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 59e2056..9d65ec3 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -290,9 +290,8 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int ohci_hcd_pxa27x_drv_probe(struct device *dev)
+static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	int ret;
 
 	pr_debug ("In ohci_hcd_pxa27x_drv_probe");
@@ -304,41 +303,39 @@
 	return ret;
 }
 
-static int ohci_hcd_pxa27x_drv_remove(struct device *dev)
+static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_hcd_pxa27x_remove(hcd, pdev);
 	return 0;
 }
 
-static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, pm_message_t state)
+static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *dev, pm_message_t state)
 {
-//	struct platform_device *pdev = to_platform_device(dev);
-//	struct usb_hcd *hcd = dev_get_drvdata(dev);
+//	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	printk("%s: not implemented yet\n", __FUNCTION__);
 
 	return 0;
 }
 
-static int ohci_hcd_pxa27x_drv_resume(struct device *dev)
+static int ohci_hcd_pxa27x_drv_resume(struct platform_device *dev)
 {
-//	struct platform_device *pdev = to_platform_device(dev);
-//	struct usb_hcd *hcd = dev_get_drvdata(dev);
+//	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	printk("%s: not implemented yet\n", __FUNCTION__);
 
 	return 0;
 }
 
 
-static struct device_driver ohci_hcd_pxa27x_driver = {
-	.name		= "pxa27x-ohci",
-	.bus		= &platform_bus_type,
+static struct platform_driver ohci_hcd_pxa27x_driver = {
 	.probe		= ohci_hcd_pxa27x_drv_probe,
 	.remove		= ohci_hcd_pxa27x_drv_remove,
 	.suspend	= ohci_hcd_pxa27x_drv_suspend, 
-	.resume		= ohci_hcd_pxa27x_drv_resume, 
+	.resume		= ohci_hcd_pxa27x_drv_resume,
+	.driver		= {
+		.name	= "pxa27x-ohci",
+	},
 };
 
 static int __init ohci_hcd_pxa27x_init (void)
@@ -347,12 +344,12 @@
 	pr_debug ("block sizes: ed %d td %d\n",
 		sizeof (struct ed), sizeof (struct td));
 
-	return driver_register(&ohci_hcd_pxa27x_driver);
+	return platform_driver_register(&ohci_hcd_pxa27x_driver);
 }
 
 static void __exit ohci_hcd_pxa27x_cleanup (void)
 {
-	driver_unregister(&ohci_hcd_pxa27x_driver);
+	platform_driver_unregister(&ohci_hcd_pxa27x_driver);
 }
 
 module_init (ohci_hcd_pxa27x_init);
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index ee1fc60..35cc940 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -459,39 +459,38 @@
 
 /* device driver */
 
-static int ohci_hcd_s3c2410_drv_probe(struct device *dev)
+static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev);
 }
 
-static int ohci_hcd_s3c2410_drv_remove(struct device *dev)
+static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 	usb_hcd_s3c2410_remove(hcd, pdev);
 	return 0;
 }
 
-static struct device_driver ohci_hcd_s3c2410_driver = {
-	.name		= "s3c2410-ohci",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver ohci_hcd_s3c2410_driver = {
 	.probe		= ohci_hcd_s3c2410_drv_probe,
 	.remove		= ohci_hcd_s3c2410_drv_remove,
 	/*.suspend	= ohci_hcd_s3c2410_drv_suspend, */
 	/*.resume	= ohci_hcd_s3c2410_drv_resume, */
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "s3c2410-ohci",
+	},
 };
 
 static int __init ohci_hcd_s3c2410_init (void)
 {
-	return driver_register(&ohci_hcd_s3c2410_driver);
+	return platform_driver_register(&ohci_hcd_s3c2410_driver);
 }
 
 static void __exit ohci_hcd_s3c2410_cleanup (void)
 {
-	driver_unregister(&ohci_hcd_s3c2410_driver);
+	platform_driver_unregister(&ohci_hcd_s3c2410_driver);
 }
 
 module_init (ohci_hcd_s3c2410_init);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 5607c0a..a7722a6 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1631,24 +1631,21 @@
 /*-------------------------------------------------------------------------*/
 
 static int __devexit
-sl811h_remove(struct device *dev)
+sl811h_remove(struct platform_device *dev)
 {
-	struct usb_hcd		*hcd = dev_get_drvdata(dev);
+	struct usb_hcd		*hcd = platform_get_drvdata(dev);
 	struct sl811		*sl811 = hcd_to_sl811(hcd);
-	struct platform_device	*pdev;
 	struct resource		*res;
 
-	pdev = container_of(dev, struct platform_device, dev);
-
 	remove_debug_file(sl811);
 	usb_remove_hcd(hcd);
 
 	/* some platforms may use IORESOURCE_IO */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource(dev, IORESOURCE_MEM, 1);
 	if (res)
 		iounmap(sl811->data_reg);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	if (res)
 		iounmap(sl811->addr_reg);
 
@@ -1657,11 +1654,10 @@
 }
 
 static int __devinit
-sl811h_probe(struct device *dev)
+sl811h_probe(struct platform_device *dev)
 {
 	struct usb_hcd		*hcd;
 	struct sl811		*sl811;
-	struct platform_device	*pdev;
 	struct resource		*addr, *data;
 	int			irq;
 	void __iomem		*addr_reg;
@@ -1674,24 +1670,23 @@
 	 * specific platform_data.  we don't probe for IRQs, and do only
 	 * minimal sanity checking.
 	 */
-	pdev = container_of(dev, struct platform_device, dev);
-	irq = platform_get_irq(pdev, 0);
-	if (pdev->num_resources < 3 || irq < 0)
+	irq = platform_get_irq(dev, 0);
+	if (dev->num_resources < 3 || irq < 0)
 		return -ENODEV;
 
 	/* refuse to confuse usbcore */
-	if (dev->dma_mask) {
+	if (dev->dev.dma_mask) {
 		DBG("no we won't dma\n");
 		return -EINVAL;
 	}
 
 	/* the chip may be wired for either kind of addressing */
-	addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	addr = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	data = platform_get_resource(dev, IORESOURCE_MEM, 1);
 	retval = -EBUSY;
 	if (!addr || !data) {
-		addr = platform_get_resource(pdev, IORESOURCE_IO, 0);
-		data = platform_get_resource(pdev, IORESOURCE_IO, 1);
+		addr = platform_get_resource(dev, IORESOURCE_IO, 0);
+		data = platform_get_resource(dev, IORESOURCE_IO, 1);
 		if (!addr || !data)
 			return -ENODEV;
 		ioaddr = 1;
@@ -1713,7 +1708,7 @@
 	}
 
 	/* allocate and initialize hcd */
-	hcd = usb_create_hcd(&sl811h_hc_driver, dev, dev->bus_id);
+	hcd = usb_create_hcd(&sl811h_hc_driver, &dev->dev, dev->dev.bus_id);
 	if (!hcd) {
 		retval = -ENOMEM;
 		goto err5;
@@ -1723,7 +1718,7 @@
 
 	spin_lock_init(&sl811->lock);
 	INIT_LIST_HEAD(&sl811->async);
-	sl811->board = dev->platform_data;
+	sl811->board = dev->dev.platform_data;
 	init_timer(&sl811->timer);
 	sl811->timer.function = sl811h_timer;
 	sl811->timer.data = (unsigned long) sl811;
@@ -1785,9 +1780,9 @@
  */
 
 static int
-sl811h_suspend(struct device *dev, pm_message_t state)
+sl811h_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct usb_hcd	*hcd = dev_get_drvdata(dev);
+	struct usb_hcd	*hcd = platform_get_drvdata(dev);
 	struct sl811	*sl811 = hcd_to_sl811(hcd);
 	int		retval = 0;
 
@@ -1796,27 +1791,27 @@
 	else if (state.event == PM_EVENT_SUSPEND)
 		port_power(sl811, 0);
 	if (retval == 0)
-		dev->power.power_state = state;
+		dev->dev.power.power_state = state;
 	return retval;
 }
 
 static int
-sl811h_resume(struct device *dev)
+sl811h_resume(struct platform_device *dev)
 {
-	struct usb_hcd	*hcd = dev_get_drvdata(dev);
+	struct usb_hcd	*hcd = platform_get_drvdata(dev);
 	struct sl811	*sl811 = hcd_to_sl811(hcd);
 
 	/* with no "check to see if VBUS is still powered" board hook,
 	 * let's assume it'd only be powered to enable remote wakeup.
 	 */
-	if (dev->power.power_state.event == PM_EVENT_SUSPEND
+	if (dev->dev.power.power_state.event == PM_EVENT_SUSPEND
 			|| !hcd->can_wakeup) {
 		sl811->port1 = 0;
 		port_power(sl811, 1);
 		return 0;
 	}
 
-	dev->power.power_state = PMSG_ON;
+	dev->dev.power.power_state = PMSG_ON;
 	return sl811h_bus_resume(hcd);
 }
 
@@ -1829,16 +1824,16 @@
 
 
 /* this driver is exported so sl811_cs can depend on it */
-struct device_driver sl811h_driver = {
-	.name =		(char *) hcd_name,
-	.bus =		&platform_bus_type,
-	.owner =	THIS_MODULE,
-
+struct platform_driver sl811h_driver = {
 	.probe =	sl811h_probe,
 	.remove =	__devexit_p(sl811h_remove),
 
 	.suspend =	sl811h_suspend,
 	.resume =	sl811h_resume,
+	.driver = {
+		.name =	(char *) hcd_name,
+		.owner = THIS_MODULE,
+	},
 };
 EXPORT_SYMBOL(sl811h_driver);
 
@@ -1850,12 +1845,12 @@
 		return -ENODEV;
 
 	INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
-	return driver_register(&sl811h_driver);
+	return platform_driver_register(&sl811h_driver);
 }
 module_init(sl811h_init);
 
 static void __exit sl811h_cleanup(void)
 {
-	driver_unregister(&sl811h_driver);
+	platform_driver_unregister(&sl811h_driver);
 }
 module_exit(sl811h_cleanup);
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 15e0a51..d33ce39 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -831,7 +831,6 @@
 static struct pci_driver uhci_pci_driver = {
 	.name =		(char *)hcd_name,
 	.id_table =	uhci_pci_ids,
-	.owner =	THIS_MODULE,
 
 	.probe =	usb_hcd_pci_probe,
 	.remove =	usb_hcd_pci_remove,
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index c89d076..61a2604 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -632,7 +632,7 @@
 	return err;
 }
 
-static Scsi_Host_Template mts_scsi_host_template = {
+static struct scsi_host_template mts_scsi_host_template = {
 	.module			= THIS_MODULE,
 	.name			= "microtekX6",
 	.proc_name		= "microtekX6",
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c
index b77e65c..5524fd7 100644
--- a/drivers/usb/media/pwc/pwc-if.c
+++ b/drivers/usb/media/pwc/pwc-if.c
@@ -62,6 +62,7 @@
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/version.h>
 #include <asm/io.h>
 
 #include "pwc.h"
diff --git a/drivers/usb/media/pwc/pwc.h b/drivers/usb/media/pwc/pwc.h
index 267869d..6dd76bb 100644
--- a/drivers/usb/media/pwc/pwc.h
+++ b/drivers/usb/media/pwc/pwc.h
@@ -25,8 +25,6 @@
 #ifndef PWC_H
 #define PWC_H
 
-#include <linux/version.h>
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/usb.h>
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
index f36c0b6..67612c8 100644
--- a/drivers/usb/media/w9968cf.c
+++ b/drivers/usb/media/w9968cf.c
@@ -25,7 +25,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
  ***************************************************************************/
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/kmod.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index c946c9a..41ef2b6 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -37,7 +37,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index 401ff21..1d7a77c 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -37,6 +37,7 @@
 #ifndef _SISUSB_H_
 #define _SISUSB_H_
 
+#include <linux/version.h>
 #ifdef CONFIG_COMPAT
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
 #include <linux/ioctl32.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 2458446..be5c1a2 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -48,7 +48,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
index f28bc24..044fa44 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -37,7 +37,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 44b6ca2..25b6ca6 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -593,38 +593,6 @@
 	  framebuffer.  Product specs at
 	  <http://www.erd.epson.com/vdc/html/products.htm>.
 
-config FB_E1356
-	tristate "Epson SED1356 framebuffer support"
-	depends on FB && EXPERIMENTAL && PCI && MIPS
-
-config PB1000_CRT
-	bool "Use CRT on Pb1000 (J65)"
-	depends on MIPS_PB1000=y && FB_E1356
-
-config PB1000_NTSC
-	bool "Use Compsite NTSC on Pb1000 (J63)"
-	depends on MIPS_PB1000=y && FB_E1356
-
-config PB1000_TFT
-	bool "Use TFT Panel on Pb1000 (J64)"
-	depends on MIPS_PB1000=y && FB_E1356
-
-config PB1500_CRT
-	bool "Use CRT on Pb1500 " if MIPS_PB1500=y
-	depends on FB_E1356
-
-config PB1500_CRT
-	prompt "Use CRT on Pb1100 "
-	depends on FB_E1356 && MIPS_PB1100=y
-
-config PB1500_TFT
-	bool "Use TFT Panel on Pb1500 " if MIPS_PB1500=y
-	depends on FB_E1356
-
-config PB1500_TFT
-	prompt "Use TFT Panel on Pb1100 "
-	depends on FB_E1356 && MIPS_PB1100=y
-
 config FB_S1D13XXX
 	tristate "Epson S1D13XXX framebuffer support"
 	depends on FB
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 193b482..750cebb 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -1279,7 +1279,7 @@
 	printk("acornfb: freed %dK memory\n", mb_freed);
 }
 
-static int __init acornfb_probe(struct device *dev)
+static int __init acornfb_probe(struct platform_device *dev)
 {
 	unsigned long size;
 	u_int h_sync, v_sync;
@@ -1292,7 +1292,7 @@
 
 	acornfb_init_fbinfo();
 
-	current_par.dev = dev;
+	current_par.dev = &dev->dev;
 
 	if (current_par.montype == -1)
 		current_par.montype = acornfb_detect_monitortype();
@@ -1453,15 +1453,16 @@
 	return 0;
 }
 
-static struct device_driver acornfb_driver = {
-	.name	= "acornfb",
-	.bus	= &platform_bus_type,
+static struct platform_driver acornfb_driver = {
 	.probe	= acornfb_probe,
+	.driver	= {
+		.name	= "acornfb",
+	},
 };
 
 static int __init acornfb_init(void)
 {
-	return driver_register(&acornfb_driver);
+	return platform_driver_register(&acornfb_driver);
 }
 
 module_init(acornfb_init);
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 467a1d7..a3c2c45 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -518,7 +518,7 @@
 	.id_table	= clcdfb_id_table,
 };
 
-int __init amba_clcdfb_init(void)
+static int __init amba_clcdfb_init(void)
 {
 	if (fb_get_options("ambafb", NULL))
 		return -ENODEV;
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index a1fc8bb..080db81 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -514,9 +514,8 @@
 	.fb_ioctl 	= arcfb_ioctl,
 };
 
-static int __init arcfb_probe(struct device *device)
+static int __init arcfb_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(device);
 	struct fb_info *info;
 	int retval = -ENOMEM;
 	int videomemorysize;
@@ -559,7 +558,7 @@
 	retval = register_framebuffer(info);
 	if (retval < 0)
 		goto err1;
-	dev_set_drvdata(&dev->dev, info);
+	platform_set_drvdata(dev, info);
 	if (irq) {
 		par->irq = irq;
 		if (request_irq(par->irq, &arcfb_interrupt, SA_SHIRQ,
@@ -600,9 +599,9 @@
 	return retval;
 }
 
-static int arcfb_remove(struct device *device)
+static int arcfb_remove(struct platform_device *dev)
 {
-	struct fb_info *info = dev_get_drvdata(device);
+	struct fb_info *info = platform_get_drvdata(dev);
 
 	if (info) {
 		unregister_framebuffer(info);
@@ -612,11 +611,12 @@
 	return 0;
 }
 
-static struct device_driver arcfb_driver = {
-	.name	= "arcfb",
-	.bus	= &platform_bus_type,
+static struct platform_driver arcfb_driver = {
 	.probe	= arcfb_probe,
 	.remove = arcfb_remove,
+	.driver	= {
+		.name	= "arcfb",
+	},
 };
 
 static struct platform_device *arcfb_device;
@@ -628,7 +628,7 @@
 	if (!arcfb_enable)
 		return -ENXIO;
 
-	ret = driver_register(&arcfb_driver);
+	ret = platform_driver_register(&arcfb_driver);
 	if (!ret) {
 		arcfb_device = platform_device_alloc("arcfb", 0);
 		if (arcfb_device) {
@@ -638,7 +638,7 @@
 		}
 		if (ret) {
 			platform_device_put(arcfb_device);
-			driver_unregister(&arcfb_driver);
+			platform_driver_unregister(&arcfb_driver);
 		}
 	}
 	return ret;
@@ -648,7 +648,7 @@
 static void __exit arcfb_exit(void)
 {
 	platform_device_unregister(arcfb_device);
-	driver_unregister(&arcfb_driver);
+	platform_driver_unregister(&arcfb_driver);
 }
 
 module_param(num_cols, ulong, 0);
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index acc81cb..9d5015e 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -5,7 +5,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index 4867498..6a219b2 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -48,6 +48,12 @@
 	corgibl_mach_set_intensity(intensity);
 
 	spin_unlock_irqrestore(&bl_lock, flags);
+
+ 	corgi_kick_batt = symbol_get(sharpsl_battery_kick);
+ 	if (corgi_kick_batt) {
+ 		corgi_kick_batt();
+ 		symbol_put(sharpsl_battery_kick);
+ 	}
 }
 
 static void corgibl_blank(int blank)
@@ -73,13 +79,13 @@
 }
 
 #ifdef CONFIG_PM
-static int corgibl_suspend(struct device *dev, pm_message_t state)
+static int corgibl_suspend(struct platform_device *dev, pm_message_t state)
 {
 	corgibl_blank(FB_BLANK_POWERDOWN);
 	return 0;
 }
 
-static int corgibl_resume(struct device *dev)
+static int corgibl_resume(struct platform_device *dev)
 {
 	corgibl_blank(FB_BLANK_UNBLANK);
 	return 0;
@@ -137,9 +143,9 @@
 
 static struct backlight_device *corgi_backlight_device;
 
-static int __init corgibl_probe(struct device *dev)
+static int __init corgibl_probe(struct platform_device *pdev)
 {
-	struct corgibl_machinfo *machinfo = dev->platform_data;
+	struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
 
 	corgibl_data.max_brightness = machinfo->max_intensity;
 	corgibl_mach_set_intensity = machinfo->set_bl_intensity;
@@ -156,7 +162,7 @@
 	return 0;
 }
 
-static int corgibl_remove(struct device *dev)
+static int corgibl_remove(struct platform_device *dev)
 {
 	backlight_device_unregister(corgi_backlight_device);
 
@@ -166,23 +172,24 @@
 	return 0;
 }
 
-static struct device_driver corgibl_driver = {
-	.name		= "corgi-bl",
-	.bus		= &platform_bus_type,
+static struct platform_driver corgibl_driver = {
 	.probe		= corgibl_probe,
 	.remove		= corgibl_remove,
 	.suspend	= corgibl_suspend,
 	.resume		= corgibl_resume,
+	.driver		= {
+		.name	= "corgi-bl",
+	},
 };
 
 static int __init corgibl_init(void)
 {
-	return driver_register(&corgibl_driver);
+	return platform_driver_register(&corgibl_driver);
 }
 
 static void __exit corgibl_exit(void)
 {
- 	driver_unregister(&corgibl_driver);
+	platform_driver_unregister(&corgibl_driver);
 }
 
 module_init(corgibl_init);
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 470e6f0..68c6906 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -5,7 +5,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index da664ce..a7770c4 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -80,10 +80,12 @@
 #define LEFT_POS(bpp)          (32 - bpp)
 #define SHIFT_HIGH(val, bits)  ((val) >> (bits))
 #define SHIFT_LOW(val, bits)   ((val) << (bits))
+#define BIT_NR(b)              (7 - (b))
 #else
 #define LEFT_POS(bpp)          (0)
 #define SHIFT_HIGH(val, bits)  ((val) << (bits))
 #define SHIFT_LOW(val, bits)   ((val) >> (bits))
+#define BIT_NR(b)              (b)
 #endif
 
 static inline void color_imageblit(const struct fb_image *image, 
@@ -177,7 +179,7 @@
 
 		while (j--) {
 			l--;
-			color = (*s & (1 << l)) ? fgcolor : bgcolor;
+			color = (*s & 1 << (BIT_NR(l))) ? fgcolor : bgcolor;
 			color <<= LEFT_POS(bpp);
 			val |= SHIFT_HIGH(color, shift);
 			
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index fadf7c5..94c5f13 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -101,6 +101,16 @@
 	help
 	  Low-level framebuffer-based console driver.
 
+config FRAMEBUFFER_CONSOLE_ROTATION
+       bool "Framebuffer Console Rotation"
+       depends on FRAMEBUFFER_CONSOLE
+       help
+         Enable display rotation for the framebuffer console.  This is done
+         in software and may be significantly slower than a normally oriented
+         display.  Note that the rotation is done at the console level only
+         such that other users of the framebuffer will remain normally
+         oriented.
+
 config STI_CONSOLE
         tristate "STI text console" 
         depends on PARISC
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index 5222628..fed600c 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -31,6 +31,10 @@
 ifeq ($(CONFIG_FB_TILEBLITTING),y)
 obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += tileblit.o
 endif
+ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION),y)
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \
+                                         fbcon_ccw.o
+endif
 
 obj-$(CONFIG_FB_STI)              += sticore.o font.o
 
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
index 67857b3..e65fc3e 100644
--- a/drivers/video/console/bitblit.c
+++ b/drivers/video/console/bitblit.c
@@ -22,35 +22,6 @@
 /*
  * Accelerated handlers.
  */
-#define FBCON_ATTRIBUTE_UNDERLINE 1
-#define FBCON_ATTRIBUTE_REVERSE   2
-#define FBCON_ATTRIBUTE_BOLD      4
-
-static inline int real_y(struct display *p, int ypos)
-{
-	int rows = p->vrows;
-
-	ypos += p->yscroll;
-	return ypos < rows ? ypos : ypos - rows;
-}
-
-
-static inline int get_attribute(struct fb_info *info, u16 c)
-{
-	int attribute = 0;
-
-	if (fb_get_color_depth(&info->var, &info->fix) == 1) {
-		if (attr_underline(c))
-			attribute |= FBCON_ATTRIBUTE_UNDERLINE;
-		if (attr_reverse(c))
-			attribute |= FBCON_ATTRIBUTE_REVERSE;
-		if (attr_bold(c))
-			attribute |= FBCON_ATTRIBUTE_BOLD;
-	}
-
-	return attribute;
-}
-
 static inline void update_attr(u8 *dst, u8 *src, int attribute,
 			       struct vc_data *vc)
 {
@@ -418,6 +389,18 @@
 	ops->cursor_reset = 0;
 }
 
+static int bit_update_start(struct fb_info *info)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	int err;
+
+	err = fb_pan_display(info, &ops->var);
+	ops->var.xoffset = info->var.xoffset;
+	ops->var.yoffset = info->var.yoffset;
+	ops->var.vmode = info->var.vmode;
+	return err;
+}
+
 void fbcon_set_bitops(struct fbcon_ops *ops)
 {
 	ops->bmove = bit_bmove;
@@ -425,6 +408,11 @@
 	ops->putcs = bit_putcs;
 	ops->clear_margins = bit_clear_margins;
 	ops->cursor = bit_cursor;
+	ops->update_start = bit_update_start;
+	ops->rotate_font = NULL;
+
+	if (ops->rotate)
+		fbcon_set_rotate(ops);
 }
 
 EXPORT_SYMBOL(fbcon_set_bitops);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 3cf1b61..e7802ff 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -107,6 +107,8 @@
 };
 
 struct display fb_display[MAX_NR_CONSOLES];
+EXPORT_SYMBOL(fb_display);
+
 static signed char con2fb_map[MAX_NR_CONSOLES];
 static signed char con2fb_map_boot[MAX_NR_CONSOLES];
 static int logo_height;
@@ -130,6 +132,9 @@
 /* current fb_info */
 static int info_idx = -1;
 
+/* console rotation */
+static int rotate;
+
 static const struct consw fb_con;
 
 #define CM_SOFTBACK	(8)
@@ -176,7 +181,6 @@
 /*
  *  Internal routines
  */
-static __inline__ int real_y(struct display *p, int ypos);
 static __inline__ void ywrap_up(struct vc_data *vc, int count);
 static __inline__ void ywrap_down(struct vc_data *vc, int count);
 static __inline__ void ypan_up(struct vc_data *vc, int count);
@@ -189,6 +193,8 @@
 			      int unit);
 static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
 			      int line, int count, int dy);
+static void fbcon_modechanged(struct fb_info *info);
+static void fbcon_set_all_vcs(struct fb_info *info);
 
 #ifdef CONFIG_MAC
 /*
@@ -203,6 +209,88 @@
 }
 #endif
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+static inline void fbcon_set_rotation(struct fb_info *info, struct display *p)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	if (!(info->flags & FBINFO_MISC_TILEBLITTING) &&
+	    p->con_rotate < 4)
+		ops->rotate = p->con_rotate;
+	else
+		ops->rotate = 0;
+}
+
+static void fbcon_rotate(struct fb_info *info, u32 rotate)
+{
+	struct fbcon_ops *ops= info->fbcon_par;
+	struct fb_info *fb_info;
+
+	if (!ops || ops->currcon == -1)
+		return;
+
+	fb_info = registered_fb[con2fb_map[ops->currcon]];
+
+	if (info == fb_info) {
+		struct display *p = &fb_display[ops->currcon];
+
+		if (rotate < 4)
+			p->con_rotate = rotate;
+		else
+			p->con_rotate = 0;
+
+		fbcon_modechanged(info);
+	}
+}
+
+static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct vc_data *vc;
+	struct display *p;
+	int i;
+
+	if (!ops || ops->currcon < 0 || rotate > 3)
+		return;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		vc = vc_cons[i].d;
+		if (!vc || vc->vc_mode != KD_TEXT ||
+		    registered_fb[con2fb_map[i]] != info)
+			continue;
+
+		p = &fb_display[vc->vc_num];
+		p->con_rotate = rotate;
+	}
+
+	fbcon_set_all_vcs(info);
+}
+#else
+static inline void fbcon_set_rotation(struct fb_info *info, struct display *p)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	ops->rotate = FB_ROTATE_UR;
+}
+
+static void fbcon_rotate(struct fb_info *info, u32 rotate)
+{
+	return;
+}
+
+static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+{
+	return;
+}
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
+
+static int fbcon_get_rotate(struct fb_info *info)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	return (ops) ? ops->rotate : 0;
+}
+
 static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
 {
 	struct fbcon_ops *ops = info->fbcon_par;
@@ -422,6 +510,14 @@
 				last_fb_vc = simple_strtoul(options, &options, 10) - 1;
 			fbcon_is_default = 0; 
 		}	
+
+		if (!strncmp(options, "rotate:", 7)) {
+			options += 7;
+			if (*options)
+				rotate = simple_strtoul(options, &options, 0);
+			if (rotate > 3)
+				rotate = 0;
+		}
 	}
 	return 0;
 }
@@ -480,6 +576,7 @@
 			       int cols, int rows, int new_cols, int new_rows)
 {
 	/* Need to make room for the logo */
+	struct fbcon_ops *ops = info->fbcon_par;
 	int cnt, erase = vc->vc_video_erase_char, step;
 	unsigned short *save = NULL, *r, *q;
 
@@ -489,7 +586,7 @@
 	 */
 	if (fb_get_color_depth(&info->var, &info->fix) == 1)
 		erase &= ~0x400;
-	logo_height = fb_prepare_logo(info);
+	logo_height = fb_prepare_logo(info, ops->rotate);
 	logo_lines = (logo_height + vc->vc_font.height - 1) /
 		vc->vc_font.height;
 	q = (unsigned short *) (vc->vc_origin +
@@ -558,16 +655,24 @@
 
 	if ((info->flags & FBINFO_MISC_TILEBLITTING))
 		fbcon_set_tileops(vc, info, p, ops);
-	else
+	else {
+		struct display *disp;
+
+		disp = (p) ? p : &fb_display[vc->vc_num];
+		fbcon_set_rotation(info, disp);
 		fbcon_set_bitops(ops);
+	}
 }
 #else
 static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
 			      struct display *p)
 {
 	struct fbcon_ops *ops = info->fbcon_par;
+	struct display *disp;
 
 	info->flags &= ~FBINFO_MISC_TILEBLITTING;
+	disp = (p) ? p : &fb_display[vc->vc_num];
+	fbcon_set_rotation(info, disp);
 	fbcon_set_bitops(ops);
 }
 #endif /* CONFIG_MISC_TILEBLITTING */
@@ -627,6 +732,7 @@
 		fbcon_del_cursor_timer(oldinfo);
 		kfree(ops->cursor_state.mask);
 		kfree(ops->cursor_data);
+		kfree(ops->fontbuffer);
 		kfree(oldinfo->fbcon_par);
 		oldinfo->fbcon_par = NULL;
 		module_put(oldinfo->fbops->owner);
@@ -827,7 +933,9 @@
 	memset(ops, 0, sizeof(struct fbcon_ops));
 	ops->currcon = -1;
 	ops->graphics = 1;
+	ops->cur_rotate = -1;
 	info->fbcon_par = ops;
+	p->con_rotate = rotate;
 	set_blitting_type(vc, info, NULL);
 
 	if (info->fix.type != FB_TYPE_TEXT) {
@@ -866,8 +974,10 @@
 		vc->vc_font.charcount = 256; /* FIXME  Need to support more fonts */
 	}
 
-	cols = info->var.xres / vc->vc_font.width;
-	rows = info->var.yres / vc->vc_font.height;
+	cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+	rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+	cols /= vc->vc_font.width;
+	rows /= vc->vc_font.height;
 	vc_resize(vc, cols, rows);
 
 	DPRINTK("mode:   %s\n", info->fix.id);
@@ -953,8 +1063,6 @@
 	    (info->fix.type == FB_TYPE_TEXT))
 		logo = 0;
 
-	info->var.xoffset = info->var.yoffset = p->yscroll = 0;	/* reset wrap/pan */
-
 	if (var_to_display(p, &info->var, info))
 		return;
 
@@ -986,13 +1094,18 @@
 	if (!*vc->vc_uni_pagedir_loc)
 		con_copy_unimap(vc, svc);
 
+	ops = info->fbcon_par;
+	p->con_rotate = rotate;
+	set_blitting_type(vc, info, NULL);
+
 	cols = vc->vc_cols;
 	rows = vc->vc_rows;
-	new_cols = info->var.xres / vc->vc_font.width;
-	new_rows = info->var.yres / vc->vc_font.height;
+	new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+	new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+	new_cols /= vc->vc_font.width;
+	new_rows /= vc->vc_font.height;
 	vc_resize(vc, new_cols, new_rows);
 
-	ops = info->fbcon_par;
 	/*
 	 * We must always set the mode. The mode of the previous console
 	 * driver could be in the same resolution but we are using different
@@ -1030,6 +1143,12 @@
 
 	if (vc == svc && softback_buf)
 		fbcon_update_softback(vc);
+
+	if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
+		ops->rotate = FB_ROTATE_UR;
+		set_blitting_type(vc, info, p);
+	}
+
 }
 
 static void fbcon_deinit(struct vc_data *vc)
@@ -1066,15 +1185,6 @@
  *  restriction is simplicity & efficiency at the moment.
  */
 
-static __inline__ int real_y(struct display *p, int ypos)
-{
-	int rows = p->vrows;
-
-	ypos += p->yscroll;
-	return ypos < rows ? ypos : ypos - rows;
-}
-
-
 static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
 			int width)
 {
@@ -1162,13 +1272,6 @@
 static int scrollback_max = 0;
 static int scrollback_current = 0;
 
-static int update_var(int con, struct fb_info *info)
-{
-	if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon)
-		return fb_pan_display(info, &info->var);
-	return 0;
-}
-
 /*
  * If no vc is existent yet, just set struct display
  */
@@ -1178,7 +1281,6 @@
 	struct display *p = &fb_display[unit];
 	struct display *t = &fb_display[fg_console];
 
-	var->xoffset = var->yoffset = p->yscroll = 0;
 	if (var_to_display(p, var, info))
 		return;
 
@@ -1194,9 +1296,9 @@
 	struct display *p = &fb_display[vc->vc_num], *t;
 	struct vc_data **default_mode = vc->vc_display_fg;
 	struct vc_data *svc = *default_mode;
+	struct fbcon_ops *ops = info->fbcon_par;
 	int rows, cols, charcnt = 256;
 
-	var->xoffset = var->yoffset = p->yscroll = 0;
 	if (var_to_display(p, var, info))
 		return;
 	t = &fb_display[svc->vc_num];
@@ -1213,9 +1315,10 @@
 
 	var->activate = FB_ACTIVATE_NOW;
 	info->var.activate = var->activate;
-	info->var.yoffset = info->var.xoffset = 0;
+	var->yoffset = info->var.yoffset;
+	var->xoffset = info->var.xoffset;
 	fb_set_var(info, var);
-
+	ops->var = info->var;
 	vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
 	if (charcnt == 256) {
@@ -1231,9 +1334,12 @@
 	if (!*vc->vc_uni_pagedir_loc)
 		con_copy_unimap(vc, svc);
 
-	cols = var->xres / vc->vc_font.width;
-	rows = var->yres / vc->vc_font.height;
+	cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+	rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+	cols /= vc->vc_font.width;
+	rows /= vc->vc_font.height;
 	vc_resize(vc, cols, rows);
+
 	if (CON_IS_VISIBLE(vc)) {
 		update_screen(vc);
 		if (softback_buf)
@@ -1244,15 +1350,16 @@
 static __inline__ void ywrap_up(struct vc_data *vc, int count)
 {
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct display *p = &fb_display[vc->vc_num];
 	
 	p->yscroll += count;
 	if (p->yscroll >= p->vrows)	/* Deal with wrap */
 		p->yscroll -= p->vrows;
-	info->var.xoffset = 0;
-	info->var.yoffset = p->yscroll * vc->vc_font.height;
-	info->var.vmode |= FB_VMODE_YWRAP;
-	update_var(vc->vc_num, info);
+	ops->var.xoffset = 0;
+	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+	ops->var.vmode |= FB_VMODE_YWRAP;
+	ops->update_start(info);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
 		scrollback_max = scrollback_phys_max;
@@ -1262,15 +1369,16 @@
 static __inline__ void ywrap_down(struct vc_data *vc, int count)
 {
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct display *p = &fb_display[vc->vc_num];
 	
 	p->yscroll -= count;
 	if (p->yscroll < 0)	/* Deal with wrap */
 		p->yscroll += p->vrows;
-	info->var.xoffset = 0;
-	info->var.yoffset = p->yscroll * vc->vc_font.height;
-	info->var.vmode |= FB_VMODE_YWRAP;
-	update_var(vc->vc_num, info);
+	ops->var.xoffset = 0;
+	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+	ops->var.vmode |= FB_VMODE_YWRAP;
+	ops->update_start(info);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
 		scrollback_max = 0;
@@ -1289,10 +1397,11 @@
 			    0, 0, 0, vc->vc_rows, vc->vc_cols);
 		p->yscroll -= p->vrows - vc->vc_rows;
 	}
-	info->var.xoffset = 0;
-	info->var.yoffset = p->yscroll * vc->vc_font.height;
-	info->var.vmode &= ~FB_VMODE_YWRAP;
-	update_var(vc->vc_num, info);
+
+	ops->var.xoffset = 0;
+	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+	ops->var.vmode &= ~FB_VMODE_YWRAP;
+	ops->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
@@ -1303,6 +1412,7 @@
 static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
 {
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct display *p = &fb_display[vc->vc_num];
 	int redraw = 0;
 
@@ -1312,12 +1422,13 @@
 		redraw = 1;
 	}
 
-	info->var.xoffset = 0;
-	info->var.yoffset = p->yscroll * vc->vc_font.height;
-	info->var.vmode &= ~FB_VMODE_YWRAP;
 	if (redraw)
 		fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
-	update_var(vc->vc_num, info);
+
+	ops->var.xoffset = 0;
+	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+	ops->var.vmode &= ~FB_VMODE_YWRAP;
+	ops->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max += count;
 	if (scrollback_max > scrollback_phys_max)
@@ -1337,10 +1448,11 @@
 			    0, vc->vc_rows, vc->vc_cols);
 		p->yscroll += p->vrows - vc->vc_rows;
 	}
-	info->var.xoffset = 0;
-	info->var.yoffset = p->yscroll * vc->vc_font.height;
-	info->var.vmode &= ~FB_VMODE_YWRAP;
-	update_var(vc->vc_num, info);
+
+	ops->var.xoffset = 0;
+	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+	ops->var.vmode &= ~FB_VMODE_YWRAP;
+	ops->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
@@ -1351,6 +1463,7 @@
 static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
 {
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct display *p = &fb_display[vc->vc_num];
 	int redraw = 0;
 
@@ -1359,12 +1472,14 @@
 		p->yscroll += p->vrows - vc->vc_rows;
 		redraw = 1;
 	}
-	info->var.xoffset = 0;
-	info->var.yoffset = p->yscroll * vc->vc_font.height;
-	info->var.vmode &= ~FB_VMODE_YWRAP;
+
 	if (redraw)
 		fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
-	update_var(vc->vc_num, info);
+
+	ops->var.xoffset = 0;
+	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+	ops->var.vmode &= ~FB_VMODE_YWRAP;
+	ops->update_start(info);
 	fbcon_clear_margins(vc, 1);
 	scrollback_max -= count;
 	if (scrollback_max < 0)
@@ -1838,31 +1953,41 @@
 		   height, width);
 }
 
-static __inline__ void updatescrollmode(struct display *p, struct fb_info *info,
+static __inline__ void updatescrollmode(struct display *p,
+					struct fb_info *info,
 					struct vc_data *vc)
 {
+	struct fbcon_ops *ops = info->fbcon_par;
 	int fh = vc->vc_font.height;
 	int cap = info->flags;
-	int good_pan = (cap & FBINFO_HWACCEL_YPAN)
-		 && divides(info->fix.ypanstep, vc->vc_font.height)
-		 && info->var.yres_virtual > info->var.yres;
-	int good_wrap = (cap & FBINFO_HWACCEL_YWRAP)
-		 && divides(info->fix.ywrapstep, vc->vc_font.height)
-		 && divides(vc->vc_font.height, info->var.yres_virtual);
+	u16 t = 0;
+	int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
+				  info->fix.xpanstep);
+	int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
+	int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+	int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
+				   info->var.xres_virtual);
+	int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
+		divides(ypan, vc->vc_font.height) && vyres > yres;
+	int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
+		divides(ywrap, vc->vc_font.height) &&
+		divides(vc->vc_font.height, vyres);
 	int reading_fast = cap & FBINFO_READS_FAST;
-	int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED);
-	int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED);
+	int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
+		!(cap & FBINFO_HWACCEL_DISABLED);
+	int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
+		!(cap & FBINFO_HWACCEL_DISABLED);
 
-	p->vrows = info->var.yres_virtual/fh;
-	if (info->var.yres > (fh * (vc->vc_rows + 1)))
-		p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh;
-	if ((info->var.yres % fh) && (info->var.yres_virtual % fh <
-				      info->var.yres % fh))
+	p->vrows = vyres/fh;
+	if (yres > (fh * (vc->vc_rows + 1)))
+		p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
+	if ((yres % fh) && (vyres % fh < yres % fh))
 		p->vrows--;
 
 	if (good_wrap || good_pan) {
 		if (reading_fast || fast_copyarea)
-			p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
+			p->scrollmode = good_wrap ?
+				SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
 		else
 			p->scrollmode = good_wrap ? SCROLL_REDRAW :
 				SCROLL_PAN_REDRAW;
@@ -1878,17 +2003,23 @@
 			unsigned int height)
 {
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct display *p = &fb_display[vc->vc_num];
 	struct fb_var_screeninfo var = info->var;
-	int x_diff, y_diff;
-	int fw = vc->vc_font.width;
-	int fh = vc->vc_font.height;
+	int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
 
-	var.xres = width * fw;
-	var.yres = height * fh;
+	virt_w = FBCON_SWAP(ops->rotate, width, height);
+	virt_h = FBCON_SWAP(ops->rotate, height, width);
+	virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
+				 vc->vc_font.height);
+	virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height,
+				 vc->vc_font.width);
+	var.xres = virt_w * virt_fw;
+	var.yres = virt_h * virt_fh;
 	x_diff = info->var.xres - var.xres;
 	y_diff = info->var.yres - var.yres;
-	if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) {
+	if (x_diff < 0 || x_diff > virt_fw ||
+	    y_diff < 0 || y_diff > virt_fh) {
 		struct fb_videomode *mode;
 
 		DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
@@ -1898,7 +2029,7 @@
 		display_to_var(&var, p);
 		fb_videomode_to_var(&var, mode);
 
-		if (width > var.xres/fw || height > var.yres/fh)
+		if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh)
 			return -EINVAL;
 
 		DPRINTK("resize now %ix%i\n", var.xres, var.yres);
@@ -1908,6 +2039,7 @@
 			fb_set_var(info, &var);
 		}
 		var_to_display(p, &info->var, info);
+		ops->var = info->var;
 	}
 	updatescrollmode(p, info, vc);
 	return 0;
@@ -1916,11 +2048,13 @@
 static int fbcon_switch(struct vc_data *vc)
 {
 	struct fb_info *info, *old_info = NULL;
+	struct fbcon_ops *ops;
 	struct display *p = &fb_display[vc->vc_num];
 	struct fb_var_screeninfo var;
 	int i, prev_console;
 
 	info = registered_fb[con2fb_map[vc->vc_num]];
+	ops = info->fbcon_par;
 
 	if (softback_top) {
 		if (softback_lines)
@@ -1939,7 +2073,7 @@
 		logo_shown = FBCON_LOGO_CANSHOW;
 	}
 
-	prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon;
+	prev_console = ops->currcon;
 	if (prev_console != -1)
 		old_info = registered_fb[con2fb_map[prev_console]];
 	/*
@@ -1952,9 +2086,9 @@
 	 */
 	for (i = 0; i < FB_MAX; i++) {
 		if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) {
-			struct fbcon_ops *ops = registered_fb[i]->fbcon_par;
+			struct fbcon_ops *o = registered_fb[i]->fbcon_par;
 
-			ops->currcon = vc->vc_num;
+			o->currcon = vc->vc_num;
 		}
 	}
 	memset(&var, 0, sizeof(struct fb_var_screeninfo));
@@ -1966,8 +2100,11 @@
 	 * in fb_set_var()
 	 */
 	info->var.activate = var.activate;
-	info->var.yoffset = info->var.xoffset = p->yscroll = 0;
+	var.yoffset = info->var.yoffset;
+	var.xoffset = info->var.xoffset;
+	var.vmode = info->var.vmode;
 	fb_set_var(info, &var);
+	ops->var = info->var;
 
 	if (old_info != NULL && old_info != info) {
 		if (info->fbops->fb_set_par)
@@ -1977,7 +2114,12 @@
 	}
 
 	set_blitting_type(vc, info, p);
-	((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1;
+	ops->cursor_reset = 1;
+
+	if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
+		ops->rotate = FB_ROTATE_UR;
+		set_blitting_type(vc, info, p);
+	}
 
 	vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
@@ -1997,10 +2139,11 @@
 		scrollback_phys_max = 0;
 		break;
 	}
+
 	scrollback_max = 0;
 	scrollback_current = 0;
-
-	update_var(vc->vc_num, info);
+	ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+	ops->update_start(info);
 	fbcon_set_palette(vc, color_table); 	
 	fbcon_clear_margins(vc, 0);
 
@@ -2008,7 +2151,7 @@
 
 		logo_shown = fg_console;
 		/* This is protected above by initmem_freed */
-		fb_show_logo(info);
+		fb_show_logo(info, ops->rotate);
 		update_region(vc,
 			      vc->vc_origin + vc->vc_size_row * vc->vc_top,
 			      vc->vc_size_row * (vc->vc_bottom -
@@ -2047,6 +2190,7 @@
 			var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
 			fb_set_var(info, &var);
 			ops->graphics = 0;
+			ops->var = info->var;
 		}
 	}
 
@@ -2135,6 +2279,7 @@
 			     const u8 * data, int userfont)
 {
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct display *p = &fb_display[vc->vc_num];
 	int resize;
 	int cnt;
@@ -2214,9 +2359,13 @@
 	}
 
 	if (resize) {
-		/* reset wrap/pan */
-		info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-		vc_resize(vc, info->var.xres / w, info->var.yres / h);
+		int cols, rows;
+
+		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+		cols /= w;
+		rows /= h;
+		vc_resize(vc, cols, rows);
 		if (CON_IS_VISIBLE(vc) && softback_buf)
 			fbcon_update_softback(vc);
 	} else if (CON_IS_VISIBLE(vc)
@@ -2444,6 +2593,7 @@
 static int fbcon_scrolldelta(struct vc_data *vc, int lines)
 {
 	struct fb_info *info = registered_fb[con2fb_map[fg_console]];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct display *p = &fb_display[fg_console];
 	int offset, limit, scrollback_old;
 
@@ -2520,9 +2670,11 @@
 		offset += limit;
 	else if (offset >= limit)
 		offset -= limit;
-	info->var.xoffset = 0;
-	info->var.yoffset = offset * vc->vc_font.height;
-	update_var(vc->vc_num, info);
+
+	ops->var.xoffset = 0;
+	ops->var.yoffset = offset * vc->vc_font.height;
+	ops->update_start(info);
+
 	if (!scrollback_current)
 		fbcon_cursor(vc, CM_DRAW);
 	return 0;
@@ -2570,22 +2722,25 @@
 	if (!ops || ops->currcon < 0)
 		return;
 	vc = vc_cons[ops->currcon].d;
-	if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info)
+	if (vc->vc_mode != KD_TEXT ||
+	    registered_fb[con2fb_map[ops->currcon]] != info)
 		return;
 
 	p = &fb_display[vc->vc_num];
-
-	info->var.xoffset = info->var.yoffset = p->yscroll = 0;
+	set_blitting_type(vc, info, p);
 
 	if (CON_IS_VISIBLE(vc)) {
 		var_to_display(p, &info->var, info);
-		cols = info->var.xres / vc->vc_font.width;
-		rows = info->var.yres / vc->vc_font.height;
+		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+		cols /= vc->vc_font.width;
+		rows /= vc->vc_font.height;
 		vc_resize(vc, cols, rows);
 		updatescrollmode(p, info, vc);
 		scrollback_max = 0;
 		scrollback_current = 0;
-		update_var(vc->vc_num, info);
+		ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+		ops->update_start(info);
 		fbcon_set_palette(vc, color_table);
 		update_screen(vc);
 		if (softback_buf)
@@ -2610,18 +2765,20 @@
 			continue;
 
 		p = &fb_display[vc->vc_num];
-
-		info->var.xoffset = info->var.yoffset = p->yscroll = 0;
+		set_blitting_type(vc, info, p);
 		var_to_display(p, &info->var, info);
-		cols = info->var.xres / vc->vc_font.width;
-		rows = info->var.yres / vc->vc_font.height;
+		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+		cols /= vc->vc_font.width;
+		rows /= vc->vc_font.height;
 		vc_resize(vc, cols, rows);
 
 		if (CON_IS_VISIBLE(vc)) {
 			updatescrollmode(p, info, vc);
 			scrollback_max = 0;
 			scrollback_current = 0;
-			update_var(vc->vc_num, info);
+			ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+			ops->update_start(info);
 			fbcon_set_palette(vc, color_table);
 			update_screen(vc);
 			if (softback_buf)
@@ -2771,6 +2928,14 @@
 	case FB_EVENT_NEW_MODELIST:
 		fbcon_new_modelist(info);
 		break;
+	case FB_EVENT_SET_CON_ROTATE:
+		fbcon_rotate(info, *(int *)event->data);
+		break;
+	case FB_EVENT_GET_CON_ROTATE:
+		ret = fbcon_get_rotate(info);
+		break;
+	case FB_EVENT_SET_CON_ROTATE_ALL:
+		fbcon_rotate_all(info, *(int *)event->data);
 	}
 
 	return ret;
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index b68e0e2..accfd7bd 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -27,15 +27,15 @@
     */
 
 struct display {
-    /* Filled in by the frame buffer device */
-    u_short inverse;                /* != 0 text black on white as default */
     /* Filled in by the low-level console driver */
     const u_char *fontdata;
     int userfont;                   /* != 0 if fontdata kmalloc()ed */
     u_short scrollmode;             /* Scroll Method */
+    u_short inverse;                /* != 0 text black on white as default */
     short yscroll;                  /* Hardware scrolling */
     int vrows;                      /* number of virtual rows */
     int cursor_shape;
+    int con_rotate;
     u32 xres_virtual;
     u32 yres_virtual;
     u32 height;
@@ -52,6 +52,8 @@
     struct fb_videomode *mode;
 };
 
+extern struct display fb_display[];
+
 struct fbcon_ops {
 	void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
 		      int sx, int dy, int dx, int height, int width);
@@ -63,8 +65,12 @@
 	void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
 			      int bottom_only);
 	void (*cursor)(struct vc_data *vc, struct fb_info *info,
-		       struct display *p, int mode, int softback_lines, int fg, int bg);
-
+		       struct display *p, int mode, int softback_lines,
+		       int fg, int bg);
+	int  (*update_start)(struct fb_info *info);
+	int  (*rotate_font)(struct fb_info *info, struct vc_data *vc,
+			    struct display *p);
+	struct fb_var_screeninfo var;  /* copy of the current fb_var_screeninfo */
 	struct timer_list cursor_timer; /* Cursor timer */
 	struct fb_cursor cursor_state;
         int    currcon;	                /* Current VC. */
@@ -73,7 +79,12 @@
 	int    blank_state;
 	int    graphics;
 	int    flags;
+	int    rotate;
+	int    cur_rotate;
 	char  *cursor_data;
+	u8    *fontbuffer;
+	u8    *fontdata;
+	u32    fd_size;
 };
     /*
      *  Attribute Decoding
@@ -168,4 +179,47 @@
 #endif
 extern void fbcon_set_bitops(struct fbcon_ops *ops);
 extern int  soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
+
+#define FBCON_ATTRIBUTE_UNDERLINE 1
+#define FBCON_ATTRIBUTE_REVERSE   2
+#define FBCON_ATTRIBUTE_BOLD      4
+
+static inline int real_y(struct display *p, int ypos)
+{
+	int rows = p->vrows;
+
+	ypos += p->yscroll;
+	return ypos < rows ? ypos : ypos - rows;
+}
+
+
+static inline int get_attribute(struct fb_info *info, u16 c)
+{
+	int attribute = 0;
+
+	if (fb_get_color_depth(&info->var, &info->fix) == 1) {
+		if (attr_underline(c))
+			attribute |= FBCON_ATTRIBUTE_UNDERLINE;
+		if (attr_reverse(c))
+			attribute |= FBCON_ATTRIBUTE_REVERSE;
+		if (attr_bold(c))
+			attribute |= FBCON_ATTRIBUTE_BOLD;
+	}
+
+	return attribute;
+}
+
+#define FBCON_SWAP(i,r,v) ({ \
+        typeof(r) _r = (r);  \
+        typeof(v) _v = (v);  \
+        (void) (&_r == &_v); \
+        (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; })
+
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+extern void fbcon_set_rotate(struct fbcon_ops *ops);
+#else
+#define fbcon_set_rotate(x) do {} while(0)
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
+
 #endif /* _VIDEO_FBCON_H */
+
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
new file mode 100644
index 0000000..680aaba
--- /dev/null
+++ b/drivers/video/console/fbcon_ccw.c
@@ -0,0 +1,428 @@
+/*
+ *  linux/drivers/video/console/fbcon_ccw.c -- Software Rotation - 270 degrees
+ *
+ *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ *  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/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+/*
+ * Rotation 270 degrees
+ */
+
+static inline void ccw_update_attr(u8 *dst, u8 *src, int attribute,
+				  struct vc_data *vc)
+{
+	int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
+	int width = (vc->vc_font.height + 7) >> 3;
+	int mod = vc->vc_font.height % 8;
+	u8 c, msk = ~(0xff << offset), msk1 = 0;
+
+	if (mod)
+		msk <<= (8 - mod);
+
+	if (offset > mod)
+		set_bit(FBCON_BIT(7), (void *)&msk1);
+
+	for (i = 0; i < vc->vc_font.width; i++) {
+		for (j = 0; j < width; j++) {
+			c = *src;
+
+			if (attribute & FBCON_ATTRIBUTE_UNDERLINE) {
+				if (j == width - 1)
+					c |= msk;
+
+				if (msk1 && j == width - 2)
+					c |= msk1;
+			}
+
+			if (attribute & FBCON_ATTRIBUTE_BOLD && i)
+				*(dst - width) |= c;
+
+			if (attribute & FBCON_ATTRIBUTE_REVERSE)
+				c = ~c;
+			src++;
+			*dst++ = c;
+		}
+	}
+}
+
+
+static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+		     int sx, int dy, int dx, int height, int width)
+{
+	struct display *p = &fb_display[vc->vc_num];
+	struct fb_copyarea area;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+
+	area.sx = sy * vc->vc_font.height;
+	area.sy = vyres - ((sx + width) * vc->vc_font.width);
+	area.dx = dy * vc->vc_font.height;
+	area.dy = vyres - ((dx + width) * vc->vc_font.width);
+	area.width = height * vc->vc_font.height;
+	area.height  = width * vc->vc_font.width;
+
+	info->fbops->fb_copyarea(info, &area);
+}
+
+static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
+		     int sx, int height, int width)
+{
+	struct display *p = &fb_display[vc->vc_num];
+	struct fb_fillrect region;
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+
+	region.color = attr_bgcol_ec(bgshift,vc);
+	region.dx = sy * vc->vc_font.height;
+	region.dy = vyres - ((sx + width) * vc->vc_font.width);
+	region.height = width * vc->vc_font.width;
+	region.width = height * vc->vc_font.height;
+	region.rop = ROP_COPY;
+
+	info->fbops->fb_fillrect(info, &region);
+}
+
+static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+				    const u16 *s, u32 attr, u32 cnt,
+				    u32 d_pitch, u32 s_pitch, u32 cellsize,
+				    struct fb_image *image, u8 *buf, u8 *dst)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	u32 idx = (vc->vc_font.height + 7) >> 3;
+	u8 *src;
+
+	while (cnt--) {
+		src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+
+		if (attr) {
+			ccw_update_attr(buf, src, attr, vc);
+			src = buf;
+		}
+
+		if (likely(idx == 1))
+			__fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+						vc->vc_font.width);
+		else
+			fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+					      vc->vc_font.width);
+
+		dst += d_pitch * vc->vc_font.width;
+	}
+
+	info->fbops->fb_imageblit(info, image);
+}
+
+static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
+		      const unsigned short *s, int count, int yy, int xx,
+		      int fg, int bg)
+{
+	struct fb_image image;
+	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
+	u32 width = (vc->vc_font.height + 7)/8;
+	u32 cellsize = width * vc->vc_font.width;
+	u32 maxcnt = info->pixmap.size/cellsize;
+	u32 scan_align = info->pixmap.scan_align - 1;
+	u32 buf_align = info->pixmap.buf_align - 1;
+	u32 cnt, pitch, size;
+	u32 attribute = get_attribute(info, scr_readw(s));
+	u8 *dst, *buf = NULL;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+
+	if (!ops->fontbuffer)
+		return;
+
+	image.fg_color = fg;
+	image.bg_color = bg;
+	image.dx = yy * vc->vc_font.height;
+	image.dy = vyres - ((xx + count) * vc->vc_font.width);
+	image.width = vc->vc_font.height;
+	image.depth = 1;
+
+	if (attribute) {
+		buf = kmalloc(cellsize, GFP_KERNEL);
+		if (!buf)
+			return;
+	}
+
+	s += count - 1;
+
+	while (count) {
+		if (count > maxcnt)
+			cnt = maxcnt;
+		else
+			cnt = count;
+
+		image.height = vc->vc_font.width * cnt;
+		pitch = ((image.width + 7) >> 3) + scan_align;
+		pitch &= ~scan_align;
+		size = pitch * image.height + buf_align;
+		size &= ~buf_align;
+		dst = fb_get_buffer_offset(info, &info->pixmap, size);
+		image.data = dst;
+		ccw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
+				 width, cellsize, &image, buf, dst);
+		image.dy += image.height;
+		count -= cnt;
+		s -= cnt;
+	}
+
+	/* buf is always NULL except when in monochrome mode, so in this case
+	   it's a gain to check buf against NULL even though kfree() handles
+	   NULL pointers just fine */
+	if (unlikely(buf))
+		kfree(buf);
+
+}
+
+static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
+			     int bottom_only)
+{
+	unsigned int cw = vc->vc_font.width;
+	unsigned int ch = vc->vc_font.height;
+	unsigned int rw = info->var.yres - (vc->vc_cols*cw);
+	unsigned int bh = info->var.xres - (vc->vc_rows*ch);
+	unsigned int bs = vc->vc_rows*ch;
+	struct fb_fillrect region;
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+
+	region.color = attr_bgcol_ec(bgshift,vc);
+	region.rop = ROP_COPY;
+
+	if (rw && !bottom_only) {
+		region.dx = 0;
+		region.dy = info->var.yoffset;
+		region.height = rw;
+		region.width = info->var.xres_virtual;
+		info->fbops->fb_fillrect(info, &region);
+	}
+
+	if (bh) {
+		region.dx = info->var.xoffset + bs;
+		region.dy = 0;
+                region.height = info->var.yres_virtual;
+                region.width = bh;
+		info->fbops->fb_fillrect(info, &region);
+	}
+}
+
+static void ccw_cursor(struct vc_data *vc, struct fb_info *info,
+		      struct display *p, int mode, int softback_lines,
+		      int fg, int bg)
+{
+	struct fb_cursor cursor;
+	struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	int w = (vc->vc_font.height + 7) >> 3, c;
+	int y = real_y(p, vc->vc_y);
+	int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+	int err = 1, dx, dy;
+	char *src;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+
+	if (!ops->fontbuffer)
+		return;
+
+	cursor.set = 0;
+
+	if (softback_lines) {
+		if (y + softback_lines >= vc->vc_rows) {
+			mode = CM_ERASE;
+			ops->cursor_flash = 0;
+			return;
+		} else
+			y += softback_lines;
+	}
+
+ 	c = scr_readw((u16 *) vc->vc_pos);
+	attribute = get_attribute(info, c);
+	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+
+	if (ops->cursor_state.image.data != src ||
+	    ops->cursor_reset) {
+	    ops->cursor_state.image.data = src;
+	    cursor.set |= FB_CUR_SETIMAGE;
+	}
+
+	if (attribute) {
+		u8 *dst;
+
+		dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC);
+		if (!dst)
+			return;
+		kfree(ops->cursor_data);
+		ops->cursor_data = dst;
+		ccw_update_attr(dst, src, attribute, vc);
+		src = dst;
+	}
+
+	if (ops->cursor_state.image.fg_color != fg ||
+	    ops->cursor_state.image.bg_color != bg ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.fg_color = fg;
+		ops->cursor_state.image.bg_color = bg;
+		cursor.set |= FB_CUR_SETCMAP;
+	}
+
+	if (ops->cursor_state.image.height != vc->vc_font.width ||
+	    ops->cursor_state.image.width != vc->vc_font.height ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.height = vc->vc_font.width;
+		ops->cursor_state.image.width = vc->vc_font.height;
+		cursor.set |= FB_CUR_SETSIZE;
+	}
+
+	dx = y * vc->vc_font.height;
+	dy = vyres - ((vc->vc_x + 1) * vc->vc_font.width);
+
+	if (ops->cursor_state.image.dx != dx ||
+	    ops->cursor_state.image.dy != dy ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.dx = dx;
+		ops->cursor_state.image.dy = dy;
+		cursor.set |= FB_CUR_SETPOS;
+	}
+
+	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+	    ops->cursor_reset) {
+		ops->cursor_state.hot.x = cursor.hot.y = 0;
+		cursor.set |= FB_CUR_SETHOT;
+	}
+
+	if (cursor.set & FB_CUR_SETSIZE ||
+	    vc->vc_cursor_type != p->cursor_shape ||
+	    ops->cursor_state.mask == NULL ||
+	    ops->cursor_reset) {
+		char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC);
+		int cur_height, size, i = 0;
+		int width = (vc->vc_font.width + 7)/8;
+
+		if (!mask)
+			return;
+
+		tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC);
+
+		if (!tmp) {
+			kfree(mask);
+			return;
+		}
+
+		kfree(ops->cursor_state.mask);
+		ops->cursor_state.mask = mask;
+
+		p->cursor_shape = vc->vc_cursor_type;
+		cursor.set |= FB_CUR_SETSHAPE;
+
+		switch (p->cursor_shape & CUR_HWMASK) {
+		case CUR_NONE:
+			cur_height = 0;
+			break;
+		case CUR_UNDERLINE:
+			cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+			break;
+		case CUR_LOWER_THIRD:
+			cur_height = vc->vc_font.height/3;
+			break;
+		case CUR_LOWER_HALF:
+			cur_height = vc->vc_font.height >> 1;
+			break;
+		case CUR_TWO_THIRDS:
+			cur_height = (vc->vc_font.height << 1)/3;
+			break;
+		case CUR_BLOCK:
+		default:
+			cur_height = vc->vc_font.height;
+			break;
+		}
+
+		size = (vc->vc_font.height - cur_height) * width;
+		while (size--)
+			tmp[i++] = 0;
+		size = cur_height * width;
+		while (size--)
+			tmp[i++] = 0xff;
+		memset(mask, 0, w * vc->vc_font.width);
+		rotate_ccw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
+		kfree(tmp);
+	}
+
+	switch (mode) {
+	case CM_ERASE:
+		ops->cursor_state.enable = 0;
+		break;
+	case CM_DRAW:
+	case CM_MOVE:
+	default:
+		ops->cursor_state.enable = (use_sw) ? 0 : 1;
+		break;
+	}
+
+	cursor.image.data = src;
+	cursor.image.fg_color = ops->cursor_state.image.fg_color;
+	cursor.image.bg_color = ops->cursor_state.image.bg_color;
+	cursor.image.dx = ops->cursor_state.image.dx;
+	cursor.image.dy = ops->cursor_state.image.dy;
+	cursor.image.height = ops->cursor_state.image.height;
+	cursor.image.width = ops->cursor_state.image.width;
+	cursor.hot.x = ops->cursor_state.hot.x;
+	cursor.hot.y = ops->cursor_state.hot.y;
+	cursor.mask = ops->cursor_state.mask;
+	cursor.enable = ops->cursor_state.enable;
+	cursor.image.depth = 1;
+	cursor.rop = ROP_XOR;
+
+	if (info->fbops->fb_cursor)
+		err = info->fbops->fb_cursor(info, &cursor);
+
+	if (err)
+		soft_cursor(info, &cursor);
+
+	ops->cursor_reset = 0;
+}
+
+int ccw_update_start(struct fb_info *info)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct display *p = &fb_display[ops->currcon];
+	u32 yoffset;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+	int err;
+
+	yoffset = (vyres - info->var.yres) - ops->var.xoffset;
+	ops->var.xoffset = ops->var.yoffset;
+	ops->var.yoffset = yoffset;
+	err = fb_pan_display(info, &ops->var);
+	ops->var.xoffset = info->var.xoffset;
+	ops->var.yoffset = info->var.yoffset;
+	ops->var.vmode = info->var.vmode;
+	return err;
+}
+
+void fbcon_rotate_ccw(struct fbcon_ops *ops)
+{
+	ops->bmove = ccw_bmove;
+	ops->clear = ccw_clear;
+	ops->putcs = ccw_putcs;
+	ops->clear_margins = ccw_clear_margins;
+	ops->cursor = ccw_cursor;
+	ops->update_start = ccw_update_start;
+}
+EXPORT_SYMBOL(fbcon_rotate_ccw);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation (270 degrees) Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
new file mode 100644
index 0000000..6c6f3b6
--- /dev/null
+++ b/drivers/video/console/fbcon_cw.c
@@ -0,0 +1,412 @@
+/*
+ *  linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 90 degrees
+ *
+ *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ *  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/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+/*
+ * Rotation 90 degrees
+ */
+
+static inline void cw_update_attr(u8 *dst, u8 *src, int attribute,
+				  struct vc_data *vc)
+{
+	int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
+	int width = (vc->vc_font.height + 7) >> 3;
+	u8 c, t = 0, msk = ~(0xff >> offset);
+
+	for (i = 0; i < vc->vc_font.width; i++) {
+		for (j = 0; j < width; j++) {
+			c = *src;
+			if (attribute & FBCON_ATTRIBUTE_UNDERLINE && !j)
+				c |= msk;
+			if (attribute & FBCON_ATTRIBUTE_BOLD && i)
+				c |= *(src-width);
+			if (attribute & FBCON_ATTRIBUTE_REVERSE)
+				c = ~c;
+			src++;
+			*dst++ = c;
+			t = c;
+		}
+	}
+}
+
+
+static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+		     int sx, int dy, int dx, int height, int width)
+{
+	struct display *p = &fb_display[vc->vc_num];
+	struct fb_copyarea area;
+	u32 vxres = GETVXRES(p->scrollmode, info);
+
+	area.sx = vxres - ((sy + height) * vc->vc_font.height);
+	area.sy = sx * vc->vc_font.width;
+	area.dx = vxres - ((dy + height) * vc->vc_font.height);
+	area.dy = dx * vc->vc_font.width;
+	area.width = height * vc->vc_font.height;
+	area.height  = width * vc->vc_font.width;
+
+	info->fbops->fb_copyarea(info, &area);
+}
+
+static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
+		     int sx, int height, int width)
+{
+	struct display *p = &fb_display[vc->vc_num];
+	struct fb_fillrect region;
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+	u32 vxres = GETVXRES(p->scrollmode, info);
+
+	region.color = attr_bgcol_ec(bgshift,vc);
+	region.dx = vxres - ((sy + height) * vc->vc_font.height);
+	region.dy = sx *  vc->vc_font.width;
+	region.height = width * vc->vc_font.width;
+	region.width = height * vc->vc_font.height;
+	region.rop = ROP_COPY;
+
+	info->fbops->fb_fillrect(info, &region);
+}
+
+static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+				    const u16 *s, u32 attr, u32 cnt,
+				    u32 d_pitch, u32 s_pitch, u32 cellsize,
+				    struct fb_image *image, u8 *buf, u8 *dst)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	u32 idx = (vc->vc_font.height + 7) >> 3;
+	u8 *src;
+
+	while (cnt--) {
+		src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize;
+
+		if (attr) {
+			cw_update_attr(buf, src, attr, vc);
+			src = buf;
+		}
+
+		if (likely(idx == 1))
+			__fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+						vc->vc_font.width);
+		else
+			fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+					      vc->vc_font.width);
+
+		dst += d_pitch * vc->vc_font.width;
+	}
+
+	info->fbops->fb_imageblit(info, image);
+}
+
+static void cw_putcs(struct vc_data *vc, struct fb_info *info,
+		      const unsigned short *s, int count, int yy, int xx,
+		      int fg, int bg)
+{
+	struct fb_image image;
+	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
+	u32 width = (vc->vc_font.height + 7)/8;
+	u32 cellsize = width * vc->vc_font.width;
+	u32 maxcnt = info->pixmap.size/cellsize;
+	u32 scan_align = info->pixmap.scan_align - 1;
+	u32 buf_align = info->pixmap.buf_align - 1;
+	u32 cnt, pitch, size;
+	u32 attribute = get_attribute(info, scr_readw(s));
+	u8 *dst, *buf = NULL;
+	u32 vxres = GETVXRES(p->scrollmode, info);
+
+	if (!ops->fontbuffer)
+		return;
+
+	image.fg_color = fg;
+	image.bg_color = bg;
+	image.dx = vxres - ((yy + 1) * vc->vc_font.height);
+	image.dy = xx * vc->vc_font.width;
+	image.width = vc->vc_font.height;
+	image.depth = 1;
+
+	if (attribute) {
+		buf = kmalloc(cellsize, GFP_KERNEL);
+		if (!buf)
+			return;
+	}
+
+	while (count) {
+		if (count > maxcnt)
+			cnt = maxcnt;
+		else
+			cnt = count;
+
+		image.height = vc->vc_font.width * cnt;
+		pitch = ((image.width + 7) >> 3) + scan_align;
+		pitch &= ~scan_align;
+		size = pitch * image.height + buf_align;
+		size &= ~buf_align;
+		dst = fb_get_buffer_offset(info, &info->pixmap, size);
+		image.data = dst;
+		cw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
+				 width, cellsize, &image, buf, dst);
+		image.dy += image.height;
+		count -= cnt;
+		s += cnt;
+	}
+
+	/* buf is always NULL except when in monochrome mode, so in this case
+	   it's a gain to check buf against NULL even though kfree() handles
+	   NULL pointers just fine */
+	if (unlikely(buf))
+		kfree(buf);
+
+}
+
+static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
+			     int bottom_only)
+{
+	unsigned int cw = vc->vc_font.width;
+	unsigned int ch = vc->vc_font.height;
+	unsigned int rw = info->var.yres - (vc->vc_cols*cw);
+	unsigned int bh = info->var.xres - (vc->vc_rows*ch);
+	unsigned int rs = info->var.yres - rw;
+	struct fb_fillrect region;
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+
+	region.color = attr_bgcol_ec(bgshift,vc);
+	region.rop = ROP_COPY;
+
+	if (rw && !bottom_only) {
+		region.dx = 0;
+		region.dy = info->var.yoffset + rs;
+		region.height = rw;
+		region.width = info->var.xres_virtual;
+		info->fbops->fb_fillrect(info, &region);
+	}
+
+	if (bh) {
+		region.dx = info->var.xoffset;
+		region.dy = info->var.yoffset;
+                region.height = info->var.yres;
+                region.width = bh;
+		info->fbops->fb_fillrect(info, &region);
+	}
+}
+
+static void cw_cursor(struct vc_data *vc, struct fb_info *info,
+		      struct display *p, int mode, int softback_lines,
+		      int fg, int bg)
+{
+	struct fb_cursor cursor;
+	struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	int w = (vc->vc_font.height + 7) >> 3, c;
+	int y = real_y(p, vc->vc_y);
+	int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+	int err = 1, dx, dy;
+	char *src;
+	u32 vxres = GETVXRES(p->scrollmode, info);
+
+	if (!ops->fontbuffer)
+		return;
+
+	cursor.set = 0;
+
+	if (softback_lines) {
+		if (y + softback_lines >= vc->vc_rows) {
+			mode = CM_ERASE;
+			ops->cursor_flash = 0;
+			return;
+		} else
+			y += softback_lines;
+	}
+
+ 	c = scr_readw((u16 *) vc->vc_pos);
+	attribute = get_attribute(info, c);
+	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+
+	if (ops->cursor_state.image.data != src ||
+	    ops->cursor_reset) {
+	    ops->cursor_state.image.data = src;
+	    cursor.set |= FB_CUR_SETIMAGE;
+	}
+
+	if (attribute) {
+		u8 *dst;
+
+		dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC);
+		if (!dst)
+			return;
+		kfree(ops->cursor_data);
+		ops->cursor_data = dst;
+		cw_update_attr(dst, src, attribute, vc);
+		src = dst;
+	}
+
+	if (ops->cursor_state.image.fg_color != fg ||
+	    ops->cursor_state.image.bg_color != bg ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.fg_color = fg;
+		ops->cursor_state.image.bg_color = bg;
+		cursor.set |= FB_CUR_SETCMAP;
+	}
+
+	if (ops->cursor_state.image.height != vc->vc_font.width ||
+	    ops->cursor_state.image.width != vc->vc_font.height ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.height = vc->vc_font.width;
+		ops->cursor_state.image.width = vc->vc_font.height;
+		cursor.set |= FB_CUR_SETSIZE;
+	}
+
+	dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height);
+	dy = vc->vc_x * vc->vc_font.width;
+
+	if (ops->cursor_state.image.dx != dx ||
+	    ops->cursor_state.image.dy != dy ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.dx = dx;
+		ops->cursor_state.image.dy = dy;
+		cursor.set |= FB_CUR_SETPOS;
+	}
+
+	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+	    ops->cursor_reset) {
+		ops->cursor_state.hot.x = cursor.hot.y = 0;
+		cursor.set |= FB_CUR_SETHOT;
+	}
+
+	if (cursor.set & FB_CUR_SETSIZE ||
+	    vc->vc_cursor_type != p->cursor_shape ||
+	    ops->cursor_state.mask == NULL ||
+	    ops->cursor_reset) {
+		char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC);
+		int cur_height, size, i = 0;
+		int width = (vc->vc_font.width + 7)/8;
+
+		if (!mask)
+			return;
+
+		tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC);
+
+		if (!tmp) {
+			kfree(mask);
+			return;
+		}
+
+		kfree(ops->cursor_state.mask);
+		ops->cursor_state.mask = mask;
+
+		p->cursor_shape = vc->vc_cursor_type;
+		cursor.set |= FB_CUR_SETSHAPE;
+
+		switch (p->cursor_shape & CUR_HWMASK) {
+		case CUR_NONE:
+			cur_height = 0;
+			break;
+		case CUR_UNDERLINE:
+			cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+			break;
+		case CUR_LOWER_THIRD:
+			cur_height = vc->vc_font.height/3;
+			break;
+		case CUR_LOWER_HALF:
+			cur_height = vc->vc_font.height >> 1;
+			break;
+		case CUR_TWO_THIRDS:
+			cur_height = (vc->vc_font.height << 1)/3;
+			break;
+		case CUR_BLOCK:
+		default:
+			cur_height = vc->vc_font.height;
+			break;
+		}
+
+		size = (vc->vc_font.height - cur_height) * width;
+		while (size--)
+			tmp[i++] = 0;
+		size = cur_height * width;
+		while (size--)
+			tmp[i++] = 0xff;
+		memset(mask, 0, w * vc->vc_font.width);
+		rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
+		kfree(tmp);
+	}
+
+	switch (mode) {
+	case CM_ERASE:
+		ops->cursor_state.enable = 0;
+		break;
+	case CM_DRAW:
+	case CM_MOVE:
+	default:
+		ops->cursor_state.enable = (use_sw) ? 0 : 1;
+		break;
+	}
+
+	cursor.image.data = src;
+	cursor.image.fg_color = ops->cursor_state.image.fg_color;
+	cursor.image.bg_color = ops->cursor_state.image.bg_color;
+	cursor.image.dx = ops->cursor_state.image.dx;
+	cursor.image.dy = ops->cursor_state.image.dy;
+	cursor.image.height = ops->cursor_state.image.height;
+	cursor.image.width = ops->cursor_state.image.width;
+	cursor.hot.x = ops->cursor_state.hot.x;
+	cursor.hot.y = ops->cursor_state.hot.y;
+	cursor.mask = ops->cursor_state.mask;
+	cursor.enable = ops->cursor_state.enable;
+	cursor.image.depth = 1;
+	cursor.rop = ROP_XOR;
+
+	if (info->fbops->fb_cursor)
+		err = info->fbops->fb_cursor(info, &cursor);
+
+	if (err)
+		soft_cursor(info, &cursor);
+
+	ops->cursor_reset = 0;
+}
+
+int cw_update_start(struct fb_info *info)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct display *p = &fb_display[ops->currcon];
+	u32 vxres = GETVXRES(p->scrollmode, info);
+	u32 xoffset;
+	int err;
+
+	xoffset = vxres - (info->var.xres + ops->var.yoffset);
+	ops->var.yoffset = ops->var.xoffset;
+	ops->var.xoffset = xoffset;
+	err = fb_pan_display(info, &ops->var);
+	ops->var.xoffset = info->var.xoffset;
+	ops->var.yoffset = info->var.yoffset;
+	ops->var.vmode = info->var.vmode;
+	return err;
+}
+
+void fbcon_rotate_cw(struct fbcon_ops *ops)
+{
+	ops->bmove = cw_bmove;
+	ops->clear = cw_clear;
+	ops->putcs = cw_putcs;
+	ops->clear_margins = cw_clear_margins;
+	ops->cursor = cw_cursor;
+	ops->update_start = cw_update_start;
+}
+EXPORT_SYMBOL(fbcon_rotate_cw);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation (90 degrees) Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon_rotate.c b/drivers/video/console/fbcon_rotate.c
new file mode 100644
index 0000000..ec0dd8f
--- /dev/null
+++ b/drivers/video/console/fbcon_rotate.c
@@ -0,0 +1,117 @@
+/*
+ *  linux/drivers/video/console/fbcon_rotate.c -- Software Rotation
+ *
+ *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ *  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/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc,
+			     struct display *p)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	int len, err = 0;
+	int s_cellsize, d_cellsize, i;
+	const u8 *src;
+	u8 *dst;
+
+	if (vc->vc_font.data == ops->fontdata &&
+	    p->con_rotate == ops->cur_rotate)
+		goto finished;
+
+	src = ops->fontdata = vc->vc_font.data;
+	ops->cur_rotate = p->con_rotate;
+	len = (!p->userfont) ? 256 : FNTCHARCNT(src);
+	s_cellsize = ((vc->vc_font.width + 7)/8) *
+		vc->vc_font.height;
+	d_cellsize = s_cellsize;
+
+	if (ops->rotate == FB_ROTATE_CW ||
+	    ops->rotate == FB_ROTATE_CCW)
+		d_cellsize = ((vc->vc_font.height + 7)/8) *
+			vc->vc_font.width;
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	if (ops->fd_size < d_cellsize * len) {
+		dst = kmalloc(d_cellsize * len, GFP_KERNEL);
+
+		if (dst == NULL) {
+			err = -ENOMEM;
+			goto finished;
+		}
+
+		ops->fd_size = d_cellsize * len;
+		kfree(ops->fontbuffer);
+		ops->fontbuffer = dst;
+	}
+
+	dst = ops->fontbuffer;
+	memset(dst, 0, ops->fd_size);
+
+	switch (ops->rotate) {
+	case FB_ROTATE_UD:
+		for (i = len; i--; ) {
+			rotate_ud(src, dst, vc->vc_font.width,
+				  vc->vc_font.height);
+
+			src += s_cellsize;
+			dst += d_cellsize;
+		}
+		break;
+	case FB_ROTATE_CW:
+		for (i = len; i--; ) {
+			rotate_cw(src, dst, vc->vc_font.width,
+				  vc->vc_font.height);
+			src += s_cellsize;
+			dst += d_cellsize;
+		}
+		break;
+	case FB_ROTATE_CCW:
+		for (i = len; i--; ) {
+			rotate_ccw(src, dst, vc->vc_font.width,
+				   vc->vc_font.height);
+			src += s_cellsize;
+			dst += d_cellsize;
+		}
+		break;
+	}
+
+finished:
+	return err;
+}
+
+void fbcon_set_rotate(struct fbcon_ops *ops)
+{
+	ops->rotate_font = fbcon_rotate_font;
+
+	switch(ops->rotate) {
+	case FB_ROTATE_CW:
+		fbcon_rotate_cw(ops);
+		break;
+	case FB_ROTATE_UD:
+		fbcon_rotate_ud(ops);
+		break;
+	case FB_ROTATE_CCW:
+		fbcon_rotate_ccw(ops);
+		break;
+	}
+}
+EXPORT_SYMBOL(fbcon_set_rotate);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon_rotate.h b/drivers/video/console/fbcon_rotate.h
new file mode 100644
index 0000000..90c6720
--- /dev/null
+++ b/drivers/video/console/fbcon_rotate.h
@@ -0,0 +1,105 @@
+/*
+ *  linux/drivers/video/console/fbcon_rotate.h -- Software Display Rotation
+ *
+ *	Copyright (C) 2005 Antonino Daplas <adaplas@pol.net>
+ *
+ *  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 _FBCON_ROTATE_H
+#define _FBCON_ROTATE_H
+
+#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
+
+#define GETVYRES(s,i) ({                           \
+        (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
+        (i)->var.yres : (i)->var.yres_virtual; })
+
+#define GETVXRES(s,i) ({                           \
+        (s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
+        (i)->var.xres : (i)->var.xres_virtual; })
+
+/*
+ * The bitmap is always big endian
+ */
+#if defined(__LITTLE_ENDIAN)
+#define FBCON_BIT(b) (7 - (b))
+#else
+#define FBCON_BIT(b) (b)
+#endif
+
+static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
+{
+	u32 tmp = (y * pitch) + x, index = tmp / 8,  bit = tmp % 8;
+
+	pat +=index;
+	return (test_bit(FBCON_BIT(bit), (void *)pat));
+}
+
+static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat)
+{
+	u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
+
+	pat += index;
+	set_bit(FBCON_BIT(bit), (void *)pat);
+}
+
+static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
+{
+	int i, j;
+	int shift = width % 8;
+
+	width = (width + 7) & ~7;
+
+	for (i = 0; i < height; i++) {
+		for (j = 0; j < width; j++) {
+			if (pattern_test_bit(j, i, width, in))
+				pattern_set_bit(width - (1 + j + shift),
+						height - (1 + i),
+						width, out);
+		}
+
+	}
+}
+
+static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
+{
+	int i, j, h = height, w = width;
+	int shift = (8 - (height % 8)) & 7;
+
+	width = (width + 7) & ~7;
+	height = (height + 7) & ~7;
+
+	for (i = 0; i < h; i++) {
+		for (j = 0; j < w; j++) {
+			if (pattern_test_bit(j, i, width, in))
+				pattern_set_bit(height - 1 - i - shift, j,
+						height, out);
+
+		}
+	}
+}
+
+static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
+{
+	int i, j, h = height, w = width;
+	int shift = width % 8;
+
+	width = (width + 7) & ~7;
+	height = (height + 7) & ~7;
+
+	for (i = 0; i < h; i++) {
+		for (j = 0; j < w; j++) {
+			if (pattern_test_bit(j, i, width, in))
+				pattern_set_bit(i, width - 1 - j - shift,
+						height, out);
+		}
+	}
+}
+
+extern void fbcon_rotate_cw(struct fbcon_ops *ops);
+extern void fbcon_rotate_ud(struct fbcon_ops *ops);
+extern void fbcon_rotate_ccw(struct fbcon_ops *ops);
+#endif
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
new file mode 100644
index 0000000..2e1d9d4
--- /dev/null
+++ b/drivers/video/console/fbcon_ud.c
@@ -0,0 +1,454 @@
+/*
+ *  linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 180 degrees
+ *
+ *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ *  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/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+/*
+ * Rotation 180 degrees
+ */
+
+static inline void ud_update_attr(u8 *dst, u8 *src, int attribute,
+				  struct vc_data *vc)
+{
+	int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
+	int width = (vc->vc_font.width + 7) >> 3;
+	unsigned int cellsize = vc->vc_font.height * width;
+	u8 c;
+
+	offset = offset * width;
+
+	for (i = 0; i < cellsize; i++) {
+		c = src[i];
+		if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i < offset)
+			c = 0xff;
+		if (attribute & FBCON_ATTRIBUTE_BOLD)
+			c |= c << 1;
+		if (attribute & FBCON_ATTRIBUTE_REVERSE)
+			c = ~c;
+		dst[i] = c;
+	}
+}
+
+
+static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+		     int sx, int dy, int dx, int height, int width)
+{
+	struct display *p = &fb_display[vc->vc_num];
+	struct fb_copyarea area;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+	u32 vxres = GETVXRES(p->scrollmode, info);
+
+	area.sy = vyres - ((sy + height) * vc->vc_font.height);
+	area.sx = vxres - ((sx + width) * vc->vc_font.width);
+	area.dy = vyres - ((dy + height) * vc->vc_font.height);
+	area.dx = vxres - ((dx + width) * vc->vc_font.width);
+	area.height = height * vc->vc_font.height;
+	area.width  = width * vc->vc_font.width;
+
+	info->fbops->fb_copyarea(info, &area);
+}
+
+static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
+		     int sx, int height, int width)
+{
+	struct display *p = &fb_display[vc->vc_num];
+	struct fb_fillrect region;
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+	u32 vxres = GETVXRES(p->scrollmode, info);
+
+	region.color = attr_bgcol_ec(bgshift,vc);
+	region.dy = vyres - ((sy + height) * vc->vc_font.height);
+	region.dx = vxres - ((sx + width) *  vc->vc_font.width);
+	region.width = width * vc->vc_font.width;
+	region.height = height * vc->vc_font.height;
+	region.rop = ROP_COPY;
+
+	info->fbops->fb_fillrect(info, &region);
+}
+
+static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+				    const u16 *s, u32 attr, u32 cnt,
+				    u32 d_pitch, u32 s_pitch, u32 cellsize,
+				    struct fb_image *image, u8 *buf, u8 *dst)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	u32 idx = vc->vc_font.width >> 3;
+	u8 *src;
+
+	while (cnt--) {
+		src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+
+		if (attr) {
+			ud_update_attr(buf, src, attr, vc);
+			src = buf;
+		}
+
+		if (likely(idx == 1))
+			__fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+						image->height);
+		else
+			fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+					      image->height);
+
+		dst += s_pitch;
+	}
+
+	info->fbops->fb_imageblit(info, image);
+}
+
+static inline void ud_putcs_unaligned(struct vc_data *vc,
+				      struct fb_info *info, const u16 *s,
+				      u32 attr, u32 cnt, u32 d_pitch,
+				      u32 s_pitch, u32 cellsize,
+				      struct fb_image *image, u8 *buf,
+				      u8 *dst)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	u32 shift_low = 0, mod = vc->vc_font.width % 8;
+	u32 shift_high = 8;
+	u32 idx = vc->vc_font.width >> 3;
+	u8 *src;
+
+	while (cnt--) {
+		src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+
+		if (attr) {
+			ud_update_attr(buf, src, attr, vc);
+			src = buf;
+		}
+
+		fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
+					image->height, shift_high,
+					shift_low, mod);
+		shift_low += mod;
+		dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
+		shift_low &= 7;
+		shift_high = 8 - shift_low;
+	}
+
+	info->fbops->fb_imageblit(info, image);
+
+}
+
+static void ud_putcs(struct vc_data *vc, struct fb_info *info,
+		      const unsigned short *s, int count, int yy, int xx,
+		      int fg, int bg)
+{
+	struct fb_image image;
+	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
+	u32 width = (vc->vc_font.width + 7)/8;
+	u32 cellsize = width * vc->vc_font.height;
+	u32 maxcnt = info->pixmap.size/cellsize;
+	u32 scan_align = info->pixmap.scan_align - 1;
+	u32 buf_align = info->pixmap.buf_align - 1;
+	u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
+	u32 attribute = get_attribute(info, scr_readw(s));
+	u8 *dst, *buf = NULL;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+	u32 vxres = GETVXRES(p->scrollmode, info);
+
+	if (!ops->fontbuffer)
+		return;
+
+	image.fg_color = fg;
+	image.bg_color = bg;
+	image.dy = vyres - ((yy * vc->vc_font.height) + vc->vc_font.height);
+	image.dx = vxres - ((xx + count) * vc->vc_font.width);
+	image.height = vc->vc_font.height;
+	image.depth = 1;
+
+	if (attribute) {
+		buf = kmalloc(cellsize, GFP_KERNEL);
+		if (!buf)
+			return;
+	}
+
+	s += count - 1;
+
+	while (count) {
+		if (count > maxcnt)
+			cnt = maxcnt;
+		else
+			cnt = count;
+
+		image.width = vc->vc_font.width * cnt;
+		pitch = ((image.width + 7) >> 3) + scan_align;
+		pitch &= ~scan_align;
+		size = pitch * image.height + buf_align;
+		size &= ~buf_align;
+		dst = fb_get_buffer_offset(info, &info->pixmap, size);
+		image.data = dst;
+
+		if (!mod)
+			ud_putcs_aligned(vc, info, s, attribute, cnt, pitch,
+					 width, cellsize, &image, buf, dst);
+		else
+			ud_putcs_unaligned(vc, info, s, attribute, cnt, pitch,
+					   width, cellsize, &image,
+					   buf, dst);
+
+		image.dx += image.width;
+		count -= cnt;
+		s -= cnt;
+		xx += cnt;
+	}
+
+	/* buf is always NULL except when in monochrome mode, so in this case
+	   it's a gain to check buf against NULL even though kfree() handles
+	   NULL pointers just fine */
+	if (unlikely(buf))
+		kfree(buf);
+
+}
+
+static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
+			     int bottom_only)
+{
+	unsigned int cw = vc->vc_font.width;
+	unsigned int ch = vc->vc_font.height;
+	unsigned int rw = info->var.xres - (vc->vc_cols*cw);
+	unsigned int bh = info->var.yres - (vc->vc_rows*ch);
+	struct fb_fillrect region;
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+
+	region.color = attr_bgcol_ec(bgshift,vc);
+	region.rop = ROP_COPY;
+
+	if (rw && !bottom_only) {
+		region.dy = 0;
+		region.dx = info->var.xoffset;
+		region.width  = rw;
+		region.height = info->var.yres_virtual;
+		info->fbops->fb_fillrect(info, &region);
+	}
+
+	if (bh) {
+		region.dy = info->var.yoffset;
+		region.dx = info->var.xoffset;
+                region.height  = bh;
+                region.width = info->var.xres;
+		info->fbops->fb_fillrect(info, &region);
+	}
+}
+
+static void ud_cursor(struct vc_data *vc, struct fb_info *info,
+		      struct display *p, int mode, int softback_lines,
+		      int fg, int bg)
+{
+	struct fb_cursor cursor;
+	struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	int w = (vc->vc_font.width + 7) >> 3, c;
+	int y = real_y(p, vc->vc_y);
+	int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+	int err = 1, dx, dy;
+	char *src;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+	u32 vxres = GETVXRES(p->scrollmode, info);
+
+	if (!ops->fontbuffer)
+		return;
+
+	cursor.set = 0;
+
+	if (softback_lines) {
+		if (y + softback_lines >= vc->vc_rows) {
+			mode = CM_ERASE;
+			ops->cursor_flash = 0;
+			return;
+		} else
+			y += softback_lines;
+	}
+
+ 	c = scr_readw((u16 *) vc->vc_pos);
+	attribute = get_attribute(info, c);
+	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
+
+	if (ops->cursor_state.image.data != src ||
+	    ops->cursor_reset) {
+	    ops->cursor_state.image.data = src;
+	    cursor.set |= FB_CUR_SETIMAGE;
+	}
+
+	if (attribute) {
+		u8 *dst;
+
+		dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
+		if (!dst)
+			return;
+		kfree(ops->cursor_data);
+		ops->cursor_data = dst;
+		ud_update_attr(dst, src, attribute, vc);
+		src = dst;
+	}
+
+	if (ops->cursor_state.image.fg_color != fg ||
+	    ops->cursor_state.image.bg_color != bg ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.fg_color = fg;
+		ops->cursor_state.image.bg_color = bg;
+		cursor.set |= FB_CUR_SETCMAP;
+	}
+
+	if (ops->cursor_state.image.height != vc->vc_font.height ||
+	    ops->cursor_state.image.width != vc->vc_font.width ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.height = vc->vc_font.height;
+		ops->cursor_state.image.width = vc->vc_font.width;
+		cursor.set |= FB_CUR_SETSIZE;
+	}
+
+	dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height);
+	dx = vxres - ((vc->vc_x * vc->vc_font.width) + vc->vc_font.width);
+
+	if (ops->cursor_state.image.dx != dx ||
+	    ops->cursor_state.image.dy != dy ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.dx = dx;
+		ops->cursor_state.image.dy = dy;
+		cursor.set |= FB_CUR_SETPOS;
+	}
+
+	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+	    ops->cursor_reset) {
+		ops->cursor_state.hot.x = cursor.hot.y = 0;
+		cursor.set |= FB_CUR_SETHOT;
+	}
+
+	if (cursor.set & FB_CUR_SETSIZE ||
+	    vc->vc_cursor_type != p->cursor_shape ||
+	    ops->cursor_state.mask == NULL ||
+	    ops->cursor_reset) {
+		char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
+		int cur_height, size, i = 0;
+		u8 msk = 0xff;
+
+		if (!mask)
+			return;
+
+		kfree(ops->cursor_state.mask);
+		ops->cursor_state.mask = mask;
+
+		p->cursor_shape = vc->vc_cursor_type;
+		cursor.set |= FB_CUR_SETSHAPE;
+
+		switch (p->cursor_shape & CUR_HWMASK) {
+		case CUR_NONE:
+			cur_height = 0;
+			break;
+		case CUR_UNDERLINE:
+			cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+			break;
+		case CUR_LOWER_THIRD:
+			cur_height = vc->vc_font.height/3;
+			break;
+		case CUR_LOWER_HALF:
+			cur_height = vc->vc_font.height >> 1;
+			break;
+		case CUR_TWO_THIRDS:
+			cur_height = (vc->vc_font.height << 1)/3;
+			break;
+		case CUR_BLOCK:
+		default:
+			cur_height = vc->vc_font.height;
+			break;
+		}
+
+		size = cur_height * w;
+
+		while (size--)
+			mask[i++] = msk;
+
+		size = (vc->vc_font.height - cur_height) * w;
+
+		while (size--)
+			mask[i++] = ~msk;
+	}
+
+	switch (mode) {
+	case CM_ERASE:
+		ops->cursor_state.enable = 0;
+		break;
+	case CM_DRAW:
+	case CM_MOVE:
+	default:
+		ops->cursor_state.enable = (use_sw) ? 0 : 1;
+		break;
+	}
+
+	cursor.image.data = src;
+	cursor.image.fg_color = ops->cursor_state.image.fg_color;
+	cursor.image.bg_color = ops->cursor_state.image.bg_color;
+	cursor.image.dx = ops->cursor_state.image.dx;
+	cursor.image.dy = ops->cursor_state.image.dy;
+	cursor.image.height = ops->cursor_state.image.height;
+	cursor.image.width = ops->cursor_state.image.width;
+	cursor.hot.x = ops->cursor_state.hot.x;
+	cursor.hot.y = ops->cursor_state.hot.y;
+	cursor.mask = ops->cursor_state.mask;
+	cursor.enable = ops->cursor_state.enable;
+	cursor.image.depth = 1;
+	cursor.rop = ROP_XOR;
+
+	if (info->fbops->fb_cursor)
+		err = info->fbops->fb_cursor(info, &cursor);
+
+	if (err)
+		soft_cursor(info, &cursor);
+
+	ops->cursor_reset = 0;
+}
+
+int ud_update_start(struct fb_info *info)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct display *p = &fb_display[ops->currcon];
+	u32 xoffset, yoffset;
+	u32 vyres = GETVYRES(p->scrollmode, info);
+	u32 vxres = GETVXRES(p->scrollmode, info);
+	int err;
+
+	xoffset = (vxres - info->var.xres) - ops->var.xoffset;
+	yoffset = (vyres - info->var.yres) - ops->var.yoffset;
+	ops->var.xoffset = xoffset;
+	ops->var.yoffset = yoffset;
+	err = fb_pan_display(info, &ops->var);
+	ops->var.xoffset = info->var.xoffset;
+	ops->var.yoffset = info->var.yoffset;
+	ops->var.vmode = info->var.vmode;
+	return err;
+}
+
+void fbcon_rotate_ud(struct fbcon_ops *ops)
+{
+	ops->bmove = ud_bmove;
+	ops->clear = ud_clear;
+	ops->putcs = ud_putcs;
+	ops->clear_margins = ud_clear_margins;
+	ops->cursor = ud_cursor;
+	ops->update_start = ud_update_start;
+}
+EXPORT_SYMBOL(fbcon_rotate_ud);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation (180 degrees) Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c
index 7f76e2c..cb25324 100644
--- a/drivers/video/console/tileblit.c
+++ b/drivers/video/console/tileblit.c
@@ -118,6 +118,18 @@
 	info->tileops->fb_tilecursor(info, &cursor);
 }
 
+static int tile_update_start(struct fb_info *info)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	int err;
+
+	err = fb_pan_display(info, &ops->var);
+	ops->var.xoffset = info->var.xoffset;
+	ops->var.yoffset = info->var.yoffset;
+	ops->var.vmode = info->var.vmode;
+	return err;
+}
+
 void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
 		       struct display *p, struct fbcon_ops *ops)
 {
@@ -128,6 +140,7 @@
 	ops->putcs = tile_putcs;
 	ops->clear_margins = tile_clear_margins;
 	ops->cursor = tile_cursor;
+	ops->update_start = tile_update_start;
 
 	if (p) {
 		map.width = vc->vc_font.width;
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c
index 957a3ad..5abd3cb 100644
--- a/drivers/video/dnfb.c
+++ b/drivers/video/dnfb.c
@@ -227,9 +227,8 @@
  * Initialization
  */
 
-static int __devinit dnfb_probe(struct device *device)
+static int __devinit dnfb_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(device);
 	struct fb_info *info;
 	int err = 0;
 
@@ -257,7 +256,7 @@
 		framebuffer_release(info);
 		return err;
 	}
-	dev_set_drvdata(&dev->dev, info);
+	platform_set_drvdata(dev, info);
 
 	/* now we have registered we can safely setup the hardware */
 	out_8(AP_CONTROL_3A, RESET_CREG);
@@ -271,10 +270,11 @@
 	return err;
 }
 
-static struct device_driver dnfb_driver = {
-	.name	= "dnfb",
-	.bus	= &platform_bus_type,
+static struct platform_driver dnfb_driver = {
 	.probe	= dnfb_probe,
+	.driver	= {
+		.name	= "dnfb",
+	},
 };
 
 static struct platform_device dnfb_device = {
@@ -288,12 +288,12 @@
 	if (fb_get_options("dnfb", NULL))
 		return -ENODEV;
 
-	ret = driver_register(&dnfb_driver);
+	ret = platform_driver_register(&dnfb_driver);
 
 	if (!ret) {
 		ret = platform_device_register(&dnfb_device);
 		if (ret)
-			driver_unregister(&dnfb_driver);
+			platform_driver_unregister(&dnfb_driver);
 	}
 	return ret;
 }
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 6a81a1d..3b0e713 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -609,9 +609,9 @@
 {
 }
 
-static int epson1355fb_remove(struct device *device)
+static int epson1355fb_remove(struct platform_device *dev)
 {
-	struct fb_info *info = dev_get_drvdata(device);
+	struct fb_info *info = platform_get_drvdata(dev);
 	struct epson1355_par *par = info->par;
 
 	backlight_enable(0);
@@ -632,9 +632,8 @@
 	return 0;
 }
 
-int __init epson1355fb_probe(struct device *device)
+int __init epson1355fb_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(device);
 	struct epson1355_par *default_par;
 	struct fb_info *info;
 	u8 revision;
@@ -713,7 +712,7 @@
 	/*
 	 * Our driver data.
 	 */
-	dev_set_drvdata(&dev->dev, info);
+	platform_set_drvdata(dev, info);
 
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
 	       info->node, info->fix.id);
@@ -721,15 +720,16 @@
 	return 0;
 
       bail:
-	epson1355fb_remove(device);
+	epson1355fb_remove(dev);
 	return rc;
 }
 
-static struct device_driver epson1355fb_driver = {
-	.name	= "epson1355fb",
-	.bus	= &platform_bus_type,
+static struct platform_driver epson1355fb_driver = {
 	.probe	= epson1355fb_probe,
 	.remove	= epson1355fb_remove,
+	.driver	= {
+		.name	= "epson1355fb",
+	},
 };
 
 static struct platform_device epson1355fb_device = {
@@ -747,11 +747,11 @@
 	if (fb_get_options("epson1355fb", NULL))
 		return -ENODEV;
 
-	ret = driver_register(&epson1355fb_driver);
+	ret = platform_driver_register(&epson1355fb_driver);
 	if (!ret) {
 		ret = platform_device_register(&epson1355fb_device);
 		if (ret)
-			driver_unregister(&epson1355fb_driver);
+			platform_driver_unregister(&epson1355fb_driver);
 	}
 	return ret;
 }
@@ -762,7 +762,7 @@
 static void __exit epson1355fb_exit(void)
 {
 	platform_device_unregister(&epson1355fb_device);
-	driver_unregister(&epson1355fb_driver);
+	platform_driver_unregister(&epson1355fb_driver);
 }
 
 /* ------------------------------------------------------------------------- */
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index e2667dd..9f18009 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -14,6 +14,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 
+#include <linux/compat.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -323,9 +324,103 @@
 	const struct linux_logo *logo;
 } fb_logo;
 
-int fb_prepare_logo(struct fb_info *info)
+static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
+{
+	u32 size = width * height, i;
+
+	out += size - 1;
+
+	for (i = size; i--; )
+		*out-- = *in++;
+}
+
+static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
+{
+	int i, j, w = width - 1;
+
+	for (i = 0; i < height; i++)
+		for (j = 0; j < width; j++)
+			out[height * j + w - i] = *in++;
+}
+
+static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
+{
+	int i, j, w = width - 1;
+
+	for (i = 0; i < height; i++)
+		for (j = 0; j < width; j++)
+			out[height * (w - j) + i] = *in++;
+}
+
+static void fb_rotate_logo(struct fb_info *info, u8 *dst,
+			   struct fb_image *image, int rotate)
+{
+	u32 tmp;
+
+	if (rotate == FB_ROTATE_UD) {
+		image->dx = info->var.xres - image->width;
+		image->dy = info->var.yres - image->height;
+		fb_rotate_logo_ud(image->data, dst, image->width,
+				  image->height);
+	} else if (rotate == FB_ROTATE_CW) {
+		tmp = image->width;
+		image->width = image->height;
+		image->height = tmp;
+		image->dx = info->var.xres - image->height;
+		fb_rotate_logo_cw(image->data, dst, image->width,
+				  image->height);
+	} else if (rotate == FB_ROTATE_CCW) {
+		tmp = image->width;
+		image->width = image->height;
+		image->height = tmp;
+		image->dy = info->var.yres - image->width;
+		fb_rotate_logo_ccw(image->data, dst, image->width,
+				   image->height);
+	}
+
+	image->data = dst;
+}
+
+static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
+			    int rotate)
+{
+	int x;
+
+	if (rotate == FB_ROTATE_UR) {
+		for (x = 0; x < num_online_cpus() &&
+			     x * (fb_logo.logo->width + 8) <=
+			     info->var.xres - fb_logo.logo->width; x++) {
+			info->fbops->fb_imageblit(info, image);
+			image->dx += fb_logo.logo->width + 8;
+		}
+	} else if (rotate == FB_ROTATE_UD) {
+		for (x = 0; x < num_online_cpus() &&
+			     x * (fb_logo.logo->width + 8) <=
+			     info->var.xres - fb_logo.logo->width; x++) {
+			info->fbops->fb_imageblit(info, image);
+			image->dx -= fb_logo.logo->width + 8;
+		}
+	} else if (rotate == FB_ROTATE_CW) {
+		for (x = 0; x < num_online_cpus() &&
+			     x * (fb_logo.logo->width + 8) <=
+			     info->var.yres - fb_logo.logo->width; x++) {
+			info->fbops->fb_imageblit(info, image);
+			image->dy += fb_logo.logo->width + 8;
+		}
+	} else if (rotate == FB_ROTATE_CCW) {
+		for (x = 0; x < num_online_cpus() &&
+			     x * (fb_logo.logo->width + 8) <=
+			     info->var.yres - fb_logo.logo->width; x++) {
+			info->fbops->fb_imageblit(info, image);
+			image->dy -= fb_logo.logo->width + 8;
+		}
+	}
+}
+
+int fb_prepare_logo(struct fb_info *info, int rotate)
 {
 	int depth = fb_get_color_depth(&info->var, &info->fix);
+	int yres;
 
 	memset(&fb_logo, 0, sizeof(struct logo_data));
 
@@ -358,10 +453,16 @@
 	/* Return if no suitable logo was found */
 	fb_logo.logo = fb_find_logo(depth);
 	
-	if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) {
+	if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
+		yres = info->var.yres;
+	else
+		yres = info->var.xres;
+
+	if (fb_logo.logo && fb_logo.logo->height > yres) {
 		fb_logo.logo = NULL;
 		return 0;
 	}
+
 	/* What depth we asked for might be different from what we get */
 	if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
 		fb_logo.depth = 8;
@@ -372,12 +473,11 @@
 	return fb_logo.logo->height;
 }
 
-int fb_show_logo(struct fb_info *info)
+int fb_show_logo(struct fb_info *info, int rotate)
 {
 	u32 *palette = NULL, *saved_pseudo_palette = NULL;
-	unsigned char *logo_new = NULL;
+	unsigned char *logo_new = NULL, *logo_rotate = NULL;
 	struct fb_image image;
-	int x;
 
 	/* Return if the frame buffer is not mapped or suspended */
 	if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
@@ -417,25 +517,30 @@
 		fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
 	}
 
+	image.dx = 0;
+	image.dy = 0;
 	image.width = fb_logo.logo->width;
 	image.height = fb_logo.logo->height;
-	image.dy = 0;
 
-	for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) &&
-	     x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
-		image.dx = x;
-		info->fbops->fb_imageblit(info, &image);
+	if (rotate) {
+		logo_rotate = kmalloc(fb_logo.logo->width *
+				      fb_logo.logo->height, GFP_KERNEL);
+		if (logo_rotate)
+			fb_rotate_logo(info, logo_rotate, &image, rotate);
 	}
-	
+
+	fb_do_show_logo(info, &image, rotate);
+
 	kfree(palette);
 	if (saved_pseudo_palette != NULL)
 		info->pseudo_palette = saved_pseudo_palette;
 	kfree(logo_new);
+	kfree(logo_rotate);
 	return fb_logo.logo->height;
 }
 #else
-int fb_prepare_logo(struct fb_info *info) { return 0; }
-int fb_show_logo(struct fb_info *info) { return 0; }
+int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
+int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
 #endif /* CONFIG_LOGO */
 
 static int fbmem_read_proc(char *buf, char **start, off_t offset,
@@ -829,18 +934,154 @@
 }
 
 #ifdef CONFIG_COMPAT
+struct fb_fix_screeninfo32 {
+	char			id[16];
+	compat_caddr_t		smem_start;
+	u32			smem_len;
+	u32			type;
+	u32			type_aux;
+	u32			visual;
+	u16			xpanstep;
+	u16			ypanstep;
+	u16			ywrapstep;
+	u32			line_length;
+	compat_caddr_t		mmio_start;
+	u32			mmio_len;
+	u32			accel;
+	u16			reserved[3];
+};
+
+struct fb_cmap32 {
+	u32			start;
+	u32			len;
+	compat_caddr_t	red;
+	compat_caddr_t	green;
+	compat_caddr_t	blue;
+	compat_caddr_t	transp;
+};
+
+static int fb_getput_cmap(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct fb_cmap_user __user *cmap;
+	struct fb_cmap32 __user *cmap32;
+	__u32 data;
+	int err;
+
+	cmap = compat_alloc_user_space(sizeof(*cmap));
+	cmap32 = compat_ptr(arg);
+
+	if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
+		return -EFAULT;
+
+	if (get_user(data, &cmap32->red) ||
+	    put_user(compat_ptr(data), &cmap->red) ||
+	    get_user(data, &cmap32->green) ||
+	    put_user(compat_ptr(data), &cmap->green) ||
+	    get_user(data, &cmap32->blue) ||
+	    put_user(compat_ptr(data), &cmap->blue) ||
+	    get_user(data, &cmap32->transp) ||
+	    put_user(compat_ptr(data), &cmap->transp))
+		return -EFAULT;
+
+	err = fb_ioctl(inode, file, cmd, (unsigned long) cmap);
+
+	if (!err) {
+		if (copy_in_user(&cmap32->start,
+				 &cmap->start,
+				 2 * sizeof(__u32)))
+			err = -EFAULT;
+	}
+	return err;
+}
+
+static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
+				  struct fb_fix_screeninfo32 __user *fix32)
+{
+	__u32 data;
+	int err;
+
+	err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
+
+	data = (__u32) (unsigned long) fix->smem_start;
+	err |= put_user(data, &fix32->smem_start);
+
+	err |= put_user(fix->smem_len, &fix32->smem_len);
+	err |= put_user(fix->type, &fix32->type);
+	err |= put_user(fix->type_aux, &fix32->type_aux);
+	err |= put_user(fix->visual, &fix32->visual);
+	err |= put_user(fix->xpanstep, &fix32->xpanstep);
+	err |= put_user(fix->ypanstep, &fix32->ypanstep);
+	err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
+	err |= put_user(fix->line_length, &fix32->line_length);
+
+	data = (__u32) (unsigned long) fix->mmio_start;
+	err |= put_user(data, &fix32->mmio_start);
+
+	err |= put_user(fix->mmio_len, &fix32->mmio_len);
+	err |= put_user(fix->accel, &fix32->accel);
+	err |= copy_to_user(fix32->reserved, fix->reserved,
+			    sizeof(fix->reserved));
+
+	return err;
+}
+
+static int fb_get_fscreeninfo(struct inode *inode, struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs;
+	struct fb_fix_screeninfo fix;
+	struct fb_fix_screeninfo32 __user *fix32;
+	int err;
+
+	fix32 = compat_ptr(arg);
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = fb_ioctl(inode, file, cmd, (unsigned long) &fix);
+	set_fs(old_fs);
+
+	if (!err)
+		err = do_fscreeninfo_to_user(&fix, fix32);
+
+	return err;
+}
+
 static long
 fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	int fbidx = iminor(file->f_dentry->d_inode);
+	struct inode *inode = file->f_dentry->d_inode;
+	int fbidx = iminor(inode);
 	struct fb_info *info = registered_fb[fbidx];
 	struct fb_ops *fb = info->fbops;
-	long ret;
+	long ret = -ENOIOCTLCMD;
 
-	if (fb->fb_compat_ioctl == NULL)
-		return -ENOIOCTLCMD;
 	lock_kernel();
-	ret = fb->fb_compat_ioctl(file, cmd, arg, info);
+	switch(cmd) {
+	case FBIOGET_VSCREENINFO:
+	case FBIOPUT_VSCREENINFO:
+	case FBIOPAN_DISPLAY:
+	case FBIOGET_CON2FBMAP:
+	case FBIOPUT_CON2FBMAP:
+		arg = (unsigned long) compat_ptr(arg);
+	case FBIOBLANK:
+		ret = fb_ioctl(inode, file, cmd, arg);
+		break;
+
+	case FBIOGET_FSCREENINFO:
+		ret = fb_get_fscreeninfo(inode, file, cmd, arg);
+		break;
+
+	case FBIOGETCMAP:
+	case FBIOPUTCMAP:
+		ret = fb_getput_cmap(inode, file, cmd, arg);
+		break;
+
+	default:
+		if (fb->fb_compat_ioctl)
+			ret = fb->fb_compat_ioctl(file, cmd, arg, info);
+		break;
+	}
 	unlock_kernel();
 	return ret;
 }
@@ -1215,6 +1456,28 @@
 	return err;
 }
 
+/**
+ * fb_con_duit - user<->fbcon passthrough
+ * @info: struct fb_info
+ * @event: notification event to be passed to fbcon
+ * @data: private data
+ *
+ * DESCRIPTION
+ * This function is an fbcon-user event passing channel
+ * which bypasses fbdev.  This is hopefully temporary
+ * until a user interface for fbcon is created
+ */
+int fb_con_duit(struct fb_info *info, int event, void *data)
+{
+	struct fb_event evnt;
+
+	evnt.info = info;
+	evnt.data = data;
+
+	return notifier_call_chain(&fb_notifier_list, event, &evnt);
+}
+EXPORT_SYMBOL(fb_con_duit);
+
 static char *video_options[FB_MAX];
 static int ofonly;
 
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 007c8e9..08dac95 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -213,6 +213,70 @@
 	return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
 }
 
+static ssize_t store_rotate(struct class_device *class_device, const char *buf,
+			    size_t count)
+{
+	struct fb_info *fb_info = class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char **last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.rotate = simple_strtoul(buf, last, 0);
+
+	if ((err = activate(fb_info, &var)))
+		return err;
+
+	return count;
+}
+
+
+static ssize_t show_rotate(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = class_get_devdata(class_device);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate);
+}
+
+static ssize_t store_con_rotate(struct class_device *class_device,
+				const char *buf, size_t count)
+{
+	struct fb_info *fb_info = class_get_devdata(class_device);
+	int rotate;
+	char **last = NULL;
+
+	acquire_console_sem();
+	rotate = simple_strtoul(buf, last, 0);
+	fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE, &rotate);
+	release_console_sem();
+	return count;
+}
+
+static ssize_t store_con_rotate_all(struct class_device *class_device,
+				const char *buf, size_t count)
+{
+	struct fb_info *fb_info = class_get_devdata(class_device);
+	int rotate;
+	char **last = NULL;
+
+	acquire_console_sem();
+	rotate = simple_strtoul(buf, last, 0);
+	fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE_ALL, &rotate);
+	release_console_sem();
+	return count;
+}
+
+static ssize_t show_con_rotate(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = class_get_devdata(class_device);
+	int rotate;
+
+	acquire_console_sem();
+	rotate = fb_con_duit(fb_info, FB_EVENT_GET_CON_ROTATE, NULL);
+	release_console_sem();
+	return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
+}
+
 static ssize_t store_virtual(struct class_device *class_device,
 			     const char * buf, size_t count)
 {
@@ -440,6 +504,9 @@
 	__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
 	__ATTR(name, S_IRUGO, show_name, NULL),
 	__ATTR(stride, S_IRUGO, show_stride, NULL),
+	__ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
+	__ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate),
+	__ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all),
 };
 
 int fb_init_class_device(struct fb_info *fb_info)
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index 9d5e4f3..d744c51 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -1105,12 +1105,11 @@
 	return 0;
 }
 
-static int __init gbefb_probe(struct device *dev)
+static int __init gbefb_probe(struct platform_device *p_dev)
 {
 	int i, ret = 0;
 	struct fb_info *info;
 	struct gbefb_par *par;
-	struct platform_device *p_dev = to_platform_device(dev);
 #ifndef MODULE
 	char *options = NULL;
 #endif
@@ -1204,8 +1203,8 @@
 		goto out_gbe_unmap;
 	}
 
-	dev_set_drvdata(&p_dev->dev, info);
-	gbefb_create_sysfs(dev);
+	platform_set_drvdata(p_dev, info);
+	gbefb_create_sysfs(&p_dev->dev);
 
 	printk(KERN_INFO "fb%d: %s rev %d @ 0x%08x using %dkB memory\n",
 	       info->node, info->fix.id, gbe_revision, (unsigned) GBE_BASE,
@@ -1231,10 +1230,9 @@
 	return ret;
 }
 
-static int __devexit gbefb_remove(struct device* dev)
+static int __devexit gbefb_remove(struct platform_device* p_dev)
 {
-	struct platform_device *p_dev = to_platform_device(dev);
-	struct fb_info *info = dev_get_drvdata(&p_dev->dev);
+	struct fb_info *info = platform_get_drvdata(p_dev);
 
 	unregister_framebuffer(info);
 	gbe_turn_off();
@@ -1252,18 +1250,19 @@
 	return 0;
 }
 
-static struct device_driver gbefb_driver = {
-	.name = "gbefb",
-	.bus = &platform_bus_type,
+static struct platform_driver gbefb_driver = {
 	.probe = gbefb_probe,
 	.remove = __devexit_p(gbefb_remove),
+	.driver	= {
+		.name = "gbefb",
+	},
 };
 
 static struct platform_device *gbefb_device;
 
 int __init gbefb_init(void)
 {
-	int ret = driver_register(&gbefb_driver);
+	int ret = platform_driver_register(&gbefb_driver);
 	if (!ret) {
 		gbefb_device = platform_device_alloc("gbefb", 0);
 		if (gbefb_device) {
@@ -1273,7 +1272,7 @@
 		}
 		if (ret) {
 			platform_device_put(gbefb_device);
-			driver_unregister(&gbefb_driver);
+			platform_driver_unregister(&gbefb_driver);
 		}
 	}
 	return ret;
@@ -1282,7 +1281,7 @@
 void __exit gbefb_exit(void)
 {
 	platform_device_unregister(gbefb_device);
-	driver_unregister(&gbefb_driver);
+	platform_driver_unregister(&gbefb_driver);
 }
 
 module_init(gbefb_init);
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index e20b9f3..5924cc2 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -423,18 +423,18 @@
  * Power management hooks.  Note that we won't be called from IRQ context,
  * unlike the blank functions above, so we may sleep.
  */
-static int imxfb_suspend(struct device *dev, pm_message_t state)
+static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct imxfb_info *fbi = dev_get_drvdata(dev);
+	struct imxfb_info *fbi = platform_get_drvdata(dev);
 	pr_debug("%s\n",__FUNCTION__);
 
 	imxfb_disable_controller(fbi);
 	return 0;
 }
 
-static int imxfb_resume(struct device *dev)
+static int imxfb_resume(struct platform_device *dev)
 {
-	struct imxfb_info *fbi = dev_get_drvdata(dev);
+	struct imxfb_info *fbi = platform_get_drvdata(dev);
 	pr_debug("%s\n",__FUNCTION__);
 
 	imxfb_enable_controller(fbi);
@@ -538,9 +538,8 @@
 	return fbi->map_cpu ? 0 : -ENOMEM;
 }
 
-static int __init imxfb_probe(struct device *dev)
+static int __init imxfb_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct imxfb_info *fbi;
 	struct fb_info *info;
 	struct imxfb_mach_info *inf;
@@ -553,21 +552,21 @@
 	if(!res)
 		return -ENODEV;
 
-	inf = dev->platform_data;
+	inf = pdev->dev.platform_data;
 	if(!inf) {
 		dev_err(dev,"No platform_data available\n");
 		return -ENOMEM;
 	}
 
-	info = framebuffer_alloc(sizeof(struct imxfb_info), dev);
+	info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
 	if(!info)
 		return -ENOMEM;
 
 	fbi = info->par;
 
-	dev_set_drvdata(dev, info);
+	platform_set_drvdata(pdev, info);
 
-	ret = imxfb_init_fbinfo(dev);
+	ret = imxfb_init_fbinfo(&pdev->dev);
 	if( ret < 0 )
 		goto failed_init;
 
@@ -621,22 +620,21 @@
 	fb_dealloc_cmap(&info->cmap);
 failed_cmap:
 	if (!inf->fixed_screen_cpu)
-		dma_free_writecombine(dev,fbi->map_size,fbi->map_cpu,
+		dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
 		           fbi->map_dma);
 failed_map:
 	kfree(info->pseudo_palette);
 failed_regs:
 	release_mem_region(res->start, res->end - res->start);
 failed_init:
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 	framebuffer_release(info);
 	return ret;
 }
 
-static int imxfb_remove(struct device *dev)
+static int imxfb_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct fb_info *info = dev_get_drvdata(dev);
+	struct fb_info *info = platform_get_drvdata(pdev);
 	struct imxfb_info *fbi = info->par;
 	struct resource *res;
 
@@ -651,36 +649,37 @@
 	framebuffer_release(info);
 
 	release_mem_region(res->start, res->end - res->start + 1);
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 
 	return 0;
 }
 
-void  imxfb_shutdown(struct device * dev)
+void  imxfb_shutdown(struct platform_device * dev)
 {
-	struct fb_info *info = dev_get_drvdata(dev);
+	struct fb_info *info = platform_get_drvdata(dev);
 	struct imxfb_info *fbi = info->par;
 	imxfb_disable_controller(fbi);
 }
 
-static struct device_driver imxfb_driver = {
-	.name		= "imx-fb",
-	.bus		= &platform_bus_type,
+static struct platform_driver imxfb_driver = {
 	.probe		= imxfb_probe,
 	.suspend	= imxfb_suspend,
 	.resume		= imxfb_resume,
 	.remove		= imxfb_remove,
 	.shutdown	= imxfb_shutdown,
+	.driver		= {
+		.name	= "imx-fb",
+	},
 };
 
 int __init imxfb_init(void)
 {
-	return driver_register(&imxfb_driver);
+	return platform_driver_register(&imxfb_driver);
 }
 
 static void __exit imxfb_cleanup(void)
 {
-	driver_unregister(&imxfb_driver);
+	platform_driver_unregister(&imxfb_driver);
 }
 
 module_init(imxfb_init);
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 0799b99..427689e 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -122,7 +122,6 @@
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
-#include <linux/version.h>
 
 #include <asm/io.h>
 
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index ac94c2e..624c4bc 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -34,7 +34,6 @@
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
-#include <linux/version.h>
 
 #include <asm/io.h>
 
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 1789a52..1da2f84 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -251,6 +251,10 @@
 	NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3,
 	FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 	FB_VMODE_NONINTERLACED
+    }, {
+	/* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */
+	NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
     },
 };
 
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index f305a5b..7b4cd25 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -980,17 +980,17 @@
  * Power management hooks.  Note that we won't be called from IRQ context,
  * unlike the blank functions above, so we may sleep.
  */
-static int pxafb_suspend(struct device *dev, pm_message_t state)
+static int pxafb_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct pxafb_info *fbi = dev_get_drvdata(dev);
+	struct pxafb_info *fbi = platform_get_drvdata(dev);
 
 	set_ctrlr_state(fbi, C_DISABLE_PM);
 	return 0;
 }
 
-static int pxafb_resume(struct device *dev)
+static int pxafb_resume(struct platform_device *dev)
 {
-	struct pxafb_info *fbi = dev_get_drvdata(dev);
+	struct pxafb_info *fbi = platform_get_drvdata(dev);
 
 	set_ctrlr_state(fbi, C_ENABLE_PM);
 	return 0;
@@ -1268,7 +1268,7 @@
 }
 #endif
 
-int __init pxafb_probe(struct device *dev)
+int __init pxafb_probe(struct platform_device *dev)
 {
 	struct pxafb_info *fbi;
 	struct pxafb_mach_info *inf;
@@ -1276,14 +1276,14 @@
 
 	dev_dbg(dev, "pxafb_probe\n");
 
-	inf = dev->platform_data;
+	inf = dev->dev.platform_data;
 	ret = -ENOMEM;
 	fbi = NULL;
 	if (!inf)
 		goto failed;
 
 #ifdef CONFIG_FB_PXA_PARAMETERS
-	ret = pxafb_parse_options(dev, g_options);
+	ret = pxafb_parse_options(&dev->dev, g_options);
 	if (ret < 0)
 		goto failed;
 #endif
@@ -1293,36 +1293,36 @@
 	 * a warning is given. */
 
         if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
-                dev_warn(dev, "machine LCCR0 setting contains illegal bits: %08x\n",
+                dev_warn(&dev->dev, "machine LCCR0 setting contains illegal bits: %08x\n",
                         inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
         if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
-                dev_warn(dev, "machine LCCR3 setting contains illegal bits: %08x\n",
+                dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n",
                         inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
         if (inf->lccr0 & LCCR0_DPD &&
 	    ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
 	     (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
 	     (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
-                dev_warn(dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
+                dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
 			 " single panel mode\n");
         if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
 	    (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
-                dev_warn(dev, "Dual panel only valid in passive mode\n");
+                dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
         if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
              (inf->upper_margin || inf->lower_margin))
-                dev_warn(dev, "Upper and lower margins must be 0 in passive mode\n");
+                dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n");
 #endif
 
-	dev_dbg(dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
+	dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
 	if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) {
-		dev_err(dev, "Invalid resolution or bit depth\n");
+		dev_err(&dev->dev, "Invalid resolution or bit depth\n");
 		ret = -EINVAL;
 		goto failed;
 	}
 	pxafb_backlight_power = inf->pxafb_backlight_power;
 	pxafb_lcd_power = inf->pxafb_lcd_power;
-	fbi = pxafb_init_fbinfo(dev);
+	fbi = pxafb_init_fbinfo(&dev->dev);
 	if (!fbi) {
-		dev_err(dev, "Failed to initialize framebuffer device\n");
+		dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
 		ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
 		goto failed;
 	}
@@ -1330,14 +1330,14 @@
 	/* Initialize video memory */
 	ret = pxafb_map_video_memory(fbi);
 	if (ret) {
-		dev_err(dev, "Failed to allocate video RAM: %d\n", ret);
+		dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret);
 		ret = -ENOMEM;
 		goto failed;
 	}
 
 	ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi);
 	if (ret) {
-		dev_err(dev, "request_irq failed: %d\n", ret);
+		dev_err(&dev->dev, "request_irq failed: %d\n", ret);
 		ret = -EBUSY;
 		goto failed;
 	}
@@ -1349,11 +1349,11 @@
 	pxafb_check_var(&fbi->fb.var, &fbi->fb);
 	pxafb_set_par(&fbi->fb);
 
-	dev_set_drvdata(dev, fbi);
+	platform_set_drvdata(dev, fbi);
 
 	ret = register_framebuffer(&fbi->fb);
 	if (ret < 0) {
-		dev_err(dev, "Failed to register framebuffer device: %d\n", ret);
+		dev_err(&dev->dev, "Failed to register framebuffer device: %d\n", ret);
 		goto failed;
 	}
 
@@ -1376,19 +1376,20 @@
 	return 0;
 
 failed:
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(dev, NULL);
 	kfree(fbi);
 	return ret;
 }
 
-static struct device_driver pxafb_driver = {
-	.name		= "pxa2xx-fb",
-	.bus		= &platform_bus_type,
+static struct platform_driver pxafb_driver = {
 	.probe		= pxafb_probe,
 #ifdef CONFIG_PM
 	.suspend	= pxafb_suspend,
 	.resume		= pxafb_resume,
 #endif
+	.driver		= {
+		.name	= "pxa2xx-fb",
+	},
 };
 
 #ifndef MODULE
@@ -1415,7 +1416,7 @@
 		return -ENODEV;
 	pxafb_setup(option);
 #endif
-	return driver_register(&pxafb_driver);
+	return platform_driver_register(&pxafb_driver);
 }
 
 module_init(pxafb_init);
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
index bfc41f2..fc91dbf 100644
--- a/drivers/video/q40fb.c
+++ b/drivers/video/q40fb.c
@@ -86,9 +86,8 @@
 	.fb_imageblit	= cfb_imageblit,
 };
 
-static int __init q40fb_probe(struct device *device)
+static int __init q40fb_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(device);
 	struct fb_info *info;
 
 	if (!MACH_IS_Q40)
@@ -128,10 +127,11 @@
 	return 0;
 }
 
-static struct device_driver q40fb_driver = {
-	.name	= "q40fb",
-	.bus	= &platform_bus_type,
+static struct platform_driver q40fb_driver = {
 	.probe	= q40fb_probe,
+	.driver	= {
+		.name	= "q40fb",
+	},
 };
 
 static struct platform_device q40fb_device = {
@@ -145,12 +145,12 @@
 	if (fb_get_options("q40fb", NULL))
 		return -ENODEV;
 
-	ret = driver_register(&q40fb_driver);
+	ret = platform_driver_register(&q40fb_driver);
 
 	if (!ret) {
 		ret = platform_device_register(&q40fb_device);
 		if (ret)
-			driver_unregister(&q40fb_driver);
+			platform_driver_unregister(&q40fb_driver);
 	}
 	return ret;
 }
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index 3edbd14..e5d0f92 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -503,10 +503,9 @@
 
 
 static int
-s1d13xxxfb_remove(struct device *dev)
+s1d13xxxfb_remove(struct platform_device *pdev)
 {
-	struct fb_info *info = dev_get_drvdata(dev);
-	struct platform_device *pdev = to_platform_device(dev);
+	struct fb_info *info = platform_get_drvdata(pdev);
 	struct s1d13xxxfb_par *par = NULL;
 
 	if (info) {
@@ -534,9 +533,8 @@
 }
 
 static int __devinit
-s1d13xxxfb_probe(struct device *dev)
+s1d13xxxfb_probe(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct s1d13xxxfb_par *default_par;
 	struct fb_info *info;
 	struct s1d13xxxfb_pdata *pdata = NULL;
@@ -548,8 +546,8 @@
 	printk(KERN_INFO "Epson S1D13XXX FB Driver\n");
 
 	/* enable platform-dependent hardware glue, if any */
-	if (dev->platform_data)
-		pdata = dev->platform_data;
+	if (pdev->dev.platform_data)
+		pdata = pdev->dev.platform_data;
 
 	if (pdata && pdata->platform_init_video)
 		pdata->platform_init_video();
@@ -572,14 +570,14 @@
 
 	if (!request_mem_region(pdev->resource[0].start,
 		pdev->resource[0].end - pdev->resource[0].start +1, "s1d13xxxfb mem")) {
-		dev_dbg(dev, "request_mem_region failed\n");
+		dev_dbg(&pdev->dev, "request_mem_region failed\n");
 		ret = -EBUSY;
 		goto bail;
 	}
 
 	if (!request_mem_region(pdev->resource[1].start,
 		pdev->resource[1].end - pdev->resource[1].start +1, "s1d13xxxfb regs")) {
-		dev_dbg(dev, "request_mem_region failed\n");
+		dev_dbg(&pdev->dev, "request_mem_region failed\n");
 		ret = -EBUSY;
 		goto bail;
 	}
@@ -640,7 +638,7 @@
 		goto bail;
 	}
 
-	dev_set_drvdata(&pdev->dev, info);
+	platform_set_drvdata(pdev, info);
 
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
 	       info->node, info->fix.id);
@@ -648,15 +646,15 @@
 	return 0;
 
 bail:
-	s1d13xxxfb_remove(dev);
+	s1d13xxxfb_remove(pdev);
 	return ret;
 
 }
 
 #ifdef CONFIG_PM
-static int s1d13xxxfb_suspend(struct device *dev, pm_message_t state)
+static int s1d13xxxfb_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct fb_info *info = dev_get_drvdata(dev);
+	struct fb_info *info = platform_get_drvdata(dev);
 	struct s1d13xxxfb_par *s1dfb = info->par;
 	struct s1d13xxxfb_pdata *pdata = NULL;
 
@@ -664,8 +662,8 @@
 	lcd_enable(s1dfb, 0);
 	crt_enable(s1dfb, 0);
 
-	if (dev->platform_data)
-		pdata = dev->platform_data;
+	if (dev->dev.platform_data)
+		pdata = dev->dev.platform_data;
 
 #if 0
 	if (!s1dfb->disp_save)
@@ -701,9 +699,9 @@
 		return 0;
 }
 
-static int s1d13xxxfb_resume(struct device *dev)
+static int s1d13xxxfb_resume(struct platform_device *dev)
 {
-	struct fb_info *info = dev_get_drvdata(dev);
+	struct fb_info *info = platform_get_drvdata(dev);
 	struct s1d13xxxfb_par *s1dfb = info->par;
 	struct s1d13xxxfb_pdata *pdata = NULL;
 
@@ -714,8 +712,8 @@
 	while ((s1d13xxxfb_readreg(s1dfb, S1DREG_PS_STATUS) & 0x01))
 		udelay(10);
 
-	if (dev->platform_data)
-		pdata = dev->platform_data;
+	if (dev->dev.platform_data)
+		pdata = dev->dev.platform_data;
 
 	if (s1dfb->regs_save) {
 		/* will write RO regs, *should* get away with it :) */
@@ -741,15 +739,16 @@
 }
 #endif /* CONFIG_PM */
 
-static struct device_driver s1d13xxxfb_driver = {
-	.name		= S1D_DEVICENAME,
-	.bus		= &platform_bus_type,
+static struct platform_driver s1d13xxxfb_driver = {
 	.probe		= s1d13xxxfb_probe,
 	.remove		= s1d13xxxfb_remove,
 #ifdef CONFIG_PM
 	.suspend	= s1d13xxxfb_suspend,
-	.resume		= s1d13xxxfb_resume
+	.resume		= s1d13xxxfb_resume,
 #endif
+	.driver		= {
+		.name	= S1D_DEVICENAME,
+	},
 };
 
 
@@ -759,14 +758,14 @@
 	if (fb_get_options("s1d13xxxfb", NULL))
 		return -ENODEV;
 
-	return driver_register(&s1d13xxxfb_driver);
+	return platform_driver_register(&s1d13xxxfb_driver);
 }
 
 
 static void __exit
 s1d13xxxfb_exit(void)
 {
-	driver_unregister(&s1d13xxxfb_driver);
+	platform_driver_unregister(&s1d13xxxfb_driver);
 }
 
 module_init(s1d13xxxfb_init);
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 855a677..ce6e749 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -634,19 +634,18 @@
 
 static char driver_name[]="s3c2410fb";
 
-int __init s3c2410fb_probe(struct device *dev)
+int __init s3c2410fb_probe(struct platform_device *pdev)
 {
 	struct s3c2410fb_info *info;
 	struct fb_info	   *fbinfo;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct s3c2410fb_hw *mregs;
 	int ret;
 	int irq;
 	int i;
 
-	mach_info = dev->platform_data;
+	mach_info = pdev->dev.platform_data;
 	if (mach_info == NULL) {
-		dev_err(dev,"no platform data for lcd, cannot attach\n");
+		dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n");
 		return -EINVAL;
 	}
 
@@ -654,11 +653,11 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(dev, "no irq for device\n");
+		dev_err(&pdev->dev, "no irq for device\n");
 		return -ENOENT;
 	}
 
-	fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), dev);
+	fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);
 	if (!fbinfo) {
 		return -ENOMEM;
 	}
@@ -666,7 +665,7 @@
 
 	info = fbinfo->par;
 	info->fb = fbinfo;
-	dev_set_drvdata(dev, fbinfo);
+	platform_set_drvdata(pdev, fbinfo);
 
 	s3c2410fb_init_registers(info);
 
@@ -676,7 +675,7 @@
 
 	memcpy(&info->regs, &mach_info->regs, sizeof(info->regs));
 
-	info->mach_info		    = dev->platform_data;
+	info->mach_info		    = pdev->dev.platform_data;
 
 	fbinfo->fix.type	    = FB_TYPE_PACKED_PIXELS;
 	fbinfo->fix.type_aux	    = 0;
@@ -735,7 +734,7 @@
 
 	ret = request_irq(irq, s3c2410fb_irq, SA_INTERRUPT, pdev->name, info);
 	if (ret) {
-		dev_err(dev, "cannot get irq %d - err %d\n", irq, ret);
+		dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
 		ret = -EBUSY;
 		goto release_mem;
 	}
@@ -773,7 +772,7 @@
 	}
 
 	/* create device files */
-	device_create_file(dev, &dev_attr_debug);
+	device_create_file(&pdev->dev, &dev_attr_debug);
 
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
 		fbinfo->node, fbinfo->fix.id);
@@ -816,10 +815,9 @@
 /*
  *  Cleanup
  */
-static int s3c2410fb_remove(struct device *dev)
+static int s3c2410fb_remove(struct platform_device *pdev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct fb_info	   *fbinfo = dev_get_drvdata(dev);
+	struct fb_info	   *fbinfo = platform_get_drvdata(pdev);
 	struct s3c2410fb_info *info = fbinfo->par;
 	int irq;
 
@@ -847,9 +845,9 @@
 
 /* suspend and resume support for the lcd controller */
 
-static int s3c2410fb_suspend(struct device *dev, pm_message_t state)
+static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct fb_info	   *fbinfo = dev_get_drvdata(dev);
+	struct fb_info	   *fbinfo = platform_get_drvdata(dev);
 	struct s3c2410fb_info *info = fbinfo->par;
 
 	s3c2410fb_stop_lcd();
@@ -864,9 +862,9 @@
 	return 0;
 }
 
-static int s3c2410fb_resume(struct device *dev)
+static int s3c2410fb_resume(struct platform_device *dev)
 {
-	struct fb_info	   *fbinfo = dev_get_drvdata(dev);
+	struct fb_info	   *fbinfo = platform_get_drvdata(dev);
 	struct s3c2410fb_info *info = fbinfo->par;
 
 	clk_enable(info->clk);
@@ -882,24 +880,25 @@
 #define s3c2410fb_resume  NULL
 #endif
 
-static struct device_driver s3c2410fb_driver = {
-	.name		= "s3c2410-lcd",
-	.owner		= THIS_MODULE,
-	.bus		= &platform_bus_type,
+static struct platform_driver s3c2410fb_driver = {
 	.probe		= s3c2410fb_probe,
+	.remove		= s3c2410fb_remove,
 	.suspend	= s3c2410fb_suspend,
 	.resume		= s3c2410fb_resume,
-	.remove		= s3c2410fb_remove
+	.driver		= {
+		.name	= "s3c2410-lcd",
+		.owner	= THIS_MODULE,
+	},
 };
 
 int __devinit s3c2410fb_init(void)
 {
-	return driver_register(&s3c2410fb_driver);
+	return platform_driver_register(&s3c2410fb_driver);
 }
 
 static void __exit s3c2410fb_cleanup(void)
 {
-	driver_unregister(&s3c2410fb_driver);
+	platform_driver_unregister(&s3c2410fb_driver);
 }
 
 
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index a518457..2ea1354 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -1308,17 +1308,17 @@
  * Power management hooks.  Note that we won't be called from IRQ context,
  * unlike the blank functions above, so we may sleep.
  */
-static int sa1100fb_suspend(struct device *dev, pm_message_t state)
+static int sa1100fb_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct sa1100fb_info *fbi = dev_get_drvdata(dev);
+	struct sa1100fb_info *fbi = platform_get_drvdata(dev);
 
 	set_ctrlr_state(fbi, C_DISABLE_PM);
 	return 0;
 }
 
-static int sa1100fb_resume(struct device *dev)
+static int sa1100fb_resume(struct platform_device *dev)
 {
-	struct sa1100fb_info *fbi = dev_get_drvdata(dev);
+	struct sa1100fb_info *fbi = platform_get_drvdata(dev);
 
 	set_ctrlr_state(fbi, C_ENABLE_PM);
 	return 0;
@@ -1452,7 +1452,7 @@
 	return fbi;
 }
 
-static int __init sa1100fb_probe(struct device *dev)
+static int __init sa1100fb_probe(struct platform_device *pdev)
 {
 	struct sa1100fb_info *fbi;
 	int ret;
@@ -1460,7 +1460,7 @@
 	if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
 		return -EBUSY;
 
-	fbi = sa1100fb_init_fbinfo(dev);
+	fbi = sa1100fb_init_fbinfo(&pdev->dev);
 	ret = -ENOMEM;
 	if (!fbi)
 		goto failed;
@@ -1488,7 +1488,7 @@
 	 */
 	sa1100fb_check_var(&fbi->fb.var, &fbi->fb);
 
-	dev_set_drvdata(dev, fbi);
+	platform_set_drvdata(pdev, fbi);
 
 	ret = register_framebuffer(&fbi->fb);
 	if (ret < 0)
@@ -1505,18 +1505,19 @@
 	return 0;
 
 failed:
-	dev_set_drvdata(dev, NULL);
+	platform_set_drvdata(pdev, NULL);
 	kfree(fbi);
 	release_mem_region(0xb0100000, 0x10000);
 	return ret;
 }
 
-static struct device_driver sa1100fb_driver = {
-	.name		= "sa11x0-fb",
-	.bus		= &platform_bus_type,
+static struct platform_driver sa1100fb_driver = {
 	.probe		= sa1100fb_probe,
 	.suspend	= sa1100fb_suspend,
 	.resume		= sa1100fb_resume,
+	.driver		= {
+		.name	= "sa11x0-fb",
+	},
 };
 
 int __init sa1100fb_init(void)
@@ -1524,7 +1525,7 @@
 	if (fb_get_options("sa1100fb", NULL))
 		return -ENODEV;
 
-	return driver_register(&sa1100fb_driver);
+	return platform_driver_register(&sa1100fb_driver);
 }
 
 int __init sa1100fb_setup(char *options)
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index f0dfb35..09e2f28 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -1315,10 +1315,14 @@
 	info->fix.line_length = info->var.xres_virtual *
 		info->var.bits_per_pixel / 8;
 
-	if (info->var.bits_per_pixel == 8)
+	if (info->var.bits_per_pixel == 8) {
 		info->fix.visual      = FB_VISUAL_PSEUDOCOLOR;
-	else
+		info->fix.xpanstep    = 4;
+	} else {
 		info->fix.visual      = FB_VISUAL_TRUECOLOR;
+		info->fix.xpanstep    = 2;
+	}
+
 }
 
 #if defined(CONFIG_FB_SAVAGE_ACCEL)
@@ -1363,7 +1367,6 @@
 	par->minClock = 10000;
 
 	savagefb_set_par_int (par);
-	savagefb_update_start (par, var);
 	fb_set_cmap (&info->cmap, info);
 	savagefb_set_fix(info);
 	savagefb_set_clip(info);
@@ -1873,7 +1876,6 @@
 
 	info->fix.type	   = FB_TYPE_PACKED_PIXELS;
 	info->fix.type_aux	   = 0;
-	info->fix.xpanstep	   = 2;
 	info->fix.ypanstep	   = 1;
 	info->fix.ywrapstep   = 0;
 	info->fix.accel       = id->driver_data;
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index 2e8769d..7054660 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -750,9 +750,8 @@
 /*
  *  Initialisation
  */
-static int __init sgivwfb_probe(struct device *device)
+static int __init sgivwfb_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(device);
 	struct sgivw_par *par;
 	struct fb_info *info;
 	char *monitor;
@@ -813,7 +812,7 @@
 		goto fail_register_framebuffer;
 	}
 
-	dev_set_drvdata(&dev->dev, info);
+	platform_set_drvdata(dev, info);
 
 	printk(KERN_INFO "fb%d: SGI DBE frame buffer device, using %ldK of video memory at %#lx\n",      
 		info->node, sgivwfb_mem_size >> 10, sgivwfb_mem_phys);
@@ -831,9 +830,9 @@
 	return -ENXIO;
 }
 
-static int sgivwfb_remove(struct device *device)
+static int sgivwfb_remove(struct platform_device *dev)
 {
-	struct fb_info *info = dev_get_drvdata(device);
+	struct fb_info *info = platform_get_drvdata(dev);
 
 	if (info) {
 		struct sgivw_par *par = info->par;
@@ -847,11 +846,12 @@
 	return 0;
 }
 
-static struct device_driver sgivwfb_driver = {
-	.name	= "sgivwfb",
-	.bus	= &platform_bus_type,
+static struct platform_driver sgivwfb_driver = {
 	.probe	= sgivwfb_probe,
 	.remove	= sgivwfb_remove,
+	.driver	= {
+		.name	= "sgivwfb",
+	},
 };
 
 static struct platform_device *sgivwfb_device;
@@ -867,7 +867,7 @@
 		return -ENODEV;
 	sgivwfb_setup(option);
 #endif
-	ret = driver_register(&sgivwfb_driver);
+	ret = platform_driver_register(&sgivwfb_driver);
 	if (!ret) {
 		sgivwfb_device = platform_device_alloc("sgivwfb", 0);
 		if (sgivwfb_device) {
@@ -875,7 +875,7 @@
 		} else
 			ret = -ENOMEM;
 		if (ret) {
-			driver_unregister(&sgivwfb_driver);
+			platform_driver_unregister(&sgivwfb_driver);
 			platform_device_put(sgivwfb_device);
 		}
 	}
@@ -890,7 +890,7 @@
 static void __exit sgivwfb_exit(void)
 {
 	platform_device_unregister(sgivwfb_device);
-	driver_unregister(&sgivwfb_driver);
+	platform_driver_unregister(&sgivwfb_driver);
 }
 
 module_exit(sgivwfb_exit);
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index e25eae1..2c3aa2f 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -245,9 +245,8 @@
 	return 0;
 }
 
-static int __init vesafb_probe(struct device *device)
+static int __init vesafb_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(device);
 	struct fb_info *info;
 	int i, err;
 	unsigned int size_vmode;
@@ -480,10 +479,11 @@
 	return err;
 }
 
-static struct device_driver vesafb_driver = {
-	.name	= "vesafb",
-	.bus	= &platform_bus_type,
+static struct platform_driver vesafb_driver = {
 	.probe	= vesafb_probe,
+	.driver	= {
+		.name	= "vesafb",
+	},
 };
 
 static struct platform_device vesafb_device = {
@@ -498,12 +498,12 @@
 	/* ignore error return of fb_get_options */
 	fb_get_options("vesafb", &option);
 	vesafb_setup(option);
-	ret = driver_register(&vesafb_driver);
+	ret = platform_driver_register(&vesafb_driver);
 
 	if (!ret) {
 		ret = platform_device_register(&vesafb_device);
 		if (ret)
-			driver_unregister(&vesafb_driver);
+			platform_driver_unregister(&vesafb_driver);
 	}
 	return ret;
 }
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 8794dc5..ffa1ad4 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -403,9 +403,8 @@
 	// This is called when the reference count goes to zero.
 }
 
-static int __init vfb_probe(struct device *device)
+static int __init vfb_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(device);
 	struct fb_info *info;
 	int retval = -ENOMEM;
 
@@ -447,7 +446,7 @@
 	retval = register_framebuffer(info);
 	if (retval < 0)
 		goto err2;
-	dev_set_drvdata(&dev->dev, info);
+	platform_set_drvdata(dev, info);
 
 	printk(KERN_INFO
 	       "fb%d: Virtual frame buffer device, using %ldK of video memory\n",
@@ -462,9 +461,9 @@
 	return retval;
 }
 
-static int vfb_remove(struct device *device)
+static int vfb_remove(struct platform_device *dev)
 {
-	struct fb_info *info = dev_get_drvdata(device);
+	struct fb_info *info = platform_get_drvdata(dev);
 
 	if (info) {
 		unregister_framebuffer(info);
@@ -474,11 +473,12 @@
 	return 0;
 }
 
-static struct device_driver vfb_driver = {
-	.name	= "vfb",
-	.bus	= &platform_bus_type,
+static struct platform_driver vfb_driver = {
 	.probe	= vfb_probe,
 	.remove = vfb_remove,
+	.driver = {
+		.name	= "vfb",
+	},
 };
 
 static struct platform_device vfb_device = {
@@ -504,12 +504,12 @@
 	if (!vfb_enable)
 		return -ENXIO;
 
-	ret = driver_register(&vfb_driver);
+	ret = platform_driver_register(&vfb_driver);
 
 	if (!ret) {
 		ret = platform_device_register(&vfb_device);
 		if (ret)
-			driver_unregister(&vfb_driver);
+			platform_driver_unregister(&vfb_driver);
 	}
 	return ret;
 }
@@ -520,7 +520,7 @@
 static void __exit vfb_exit(void)
 {
 	platform_device_unregister(&vfb_device);
-	driver_unregister(&vfb_driver);
+	platform_driver_unregister(&vfb_driver);
 }
 
 module_exit(vfb_exit);
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 690bb6f..226ae8a 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -21,6 +21,7 @@
 #include <linux/fb.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 
 #include <asm/io.h>
 #include <video/vga.h>
@@ -51,35 +52,33 @@
  * card parameters
  */
 
-static struct fb_info vga16fb; 
-
-static struct vga16fb_par {
+struct vga16fb_par {
 	/* structure holding original VGA register settings when the
            screen is blanked */
 	struct {
-		unsigned char	SeqCtrlIndex;		/* Sequencer Index reg.   */
-		unsigned char	CrtCtrlIndex;		/* CRT-Contr. Index reg.  */
-		unsigned char	CrtMiscIO;		/* Miscellaneous register */
-		unsigned char	HorizontalTotal;	/* CRT-Controller:00h */
-		unsigned char	HorizDisplayEnd;	/* CRT-Controller:01h */
-		unsigned char	StartHorizRetrace;	/* CRT-Controller:04h */
-		unsigned char	EndHorizRetrace;	/* CRT-Controller:05h */
-		unsigned char	Overflow;		/* CRT-Controller:07h */
-		unsigned char	StartVertRetrace;	/* CRT-Controller:10h */
-		unsigned char	EndVertRetrace;		/* CRT-Controller:11h */
-		unsigned char	ModeControl;		/* CRT-Controller:17h */
-		unsigned char	ClockingMode;		/* Seq-Controller:01h */
+		unsigned char	SeqCtrlIndex;	  /* Sequencer Index reg.   */
+		unsigned char	CrtCtrlIndex;	  /* CRT-Contr. Index reg.  */
+		unsigned char	CrtMiscIO;	  /* Miscellaneous register */
+		unsigned char	HorizontalTotal;  /* CRT-Controller:00h */
+		unsigned char	HorizDisplayEnd;  /* CRT-Controller:01h */
+		unsigned char	StartHorizRetrace;/* CRT-Controller:04h */
+		unsigned char	EndHorizRetrace;  /* CRT-Controller:05h */
+		unsigned char	Overflow;	  /* CRT-Controller:07h */
+		unsigned char	StartVertRetrace; /* CRT-Controller:10h */
+		unsigned char	EndVertRetrace;	  /* CRT-Controller:11h */
+		unsigned char	ModeControl;	  /* CRT-Controller:17h */
+		unsigned char	ClockingMode;	  /* Seq-Controller:01h */
 	} vga_state;
 	struct vgastate state;
 	atomic_t ref_count;
 	int palette_blanked, vesa_blanked, mode, isVGA;
 	u8 misc, pel_msk, vss, clkdiv;
 	u8 crtc[VGA_CRT_C];
-} vga16_par;
+};
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_var_screeninfo vga16fb_defined = {
+static struct fb_var_screeninfo vga16fb_defined __initdata = {
 	.xres		= 640,
 	.yres		= 480,
 	.xres_virtual	= 640,
@@ -205,7 +204,7 @@
 static void vga16fb_pan_var(struct fb_info *info, 
 			    struct fb_var_screeninfo *var)
 {
-	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	struct vga16fb_par *par = info->par;
 	u32 xoffset, pos;
 
 	xoffset = var->xoffset;
@@ -300,7 +299,7 @@
 
 static int vga16fb_open(struct fb_info *info, int user)
 {
-	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	struct vga16fb_par *par = info->par;
 	int cnt = atomic_read(&par->ref_count);
 
 	if (!cnt) {
@@ -315,7 +314,7 @@
 
 static int vga16fb_release(struct fb_info *info, int user)
 {
-	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	struct vga16fb_par *par = info->par;
 	int cnt = atomic_read(&par->ref_count);
 
 	if (!cnt)
@@ -330,7 +329,7 @@
 static int vga16fb_check_var(struct fb_var_screeninfo *var,
 			     struct fb_info *info)
 {
-	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	struct vga16fb_par *par = info->par;
 	u32 xres, right, hslen, left, xtotal;
 	u32 yres, lower, vslen, upper, ytotal;
 	u32 vxres, xoffset, vyres, yoffset;
@@ -535,7 +534,7 @@
 
 static int vga16fb_set_par(struct fb_info *info)
 {
-	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	struct vga16fb_par *par = info->par;
 	u8 gdc[VGA_GFX_C];
 	u8 seq[VGA_SEQ_C];
 	u8 atc[VGA_ATT_C];
@@ -677,7 +676,7 @@
 			     unsigned blue, unsigned transp,
 			     struct fb_info *info)
 {
-	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	struct vga16fb_par *par = info->par;
 	int gray;
 
 	/*
@@ -850,7 +849,7 @@
 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
 static int vga16fb_blank(int blank, struct fb_info *info)
 {
-	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	struct vga16fb_par *par = info->par;
 
 	switch (blank) {
 	case FB_BLANK_UNBLANK:				/* Unblank */
@@ -1201,7 +1200,7 @@
 {
 	char __iomem *where = info->screen_base + (image->dx/8) +
 		image->dy * info->fix.line_length;
-	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	struct vga16fb_par *par = info->par;
 	char *cdat = (char *) image->data;
 	char __iomem *dst;
 	int x, y;
@@ -1266,7 +1265,7 @@
 	/*
 	 * Draw logo 
 	 */
-	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	struct vga16fb_par *par = info->par;
 	char __iomem *where =
 		info->screen_base + image->dy * info->fix.line_length +
 		image->dx/8;
@@ -1343,9 +1342,117 @@
 }
 #endif
 
+static int __init vga16fb_probe(struct device *device)
+{
+	struct platform_device *dev = to_platform_device(device);
+	struct fb_info *info;
+	struct vga16fb_par *par;
+	int i;
+	int ret = 0;
+
+	printk(KERN_DEBUG "vga16fb: initializing\n");
+	info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
+
+	if (!info) {
+		ret = -ENOMEM;
+		goto err_fb_alloc;
+	}
+
+	/* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
+	info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS);
+
+	if (!info->screen_base) {
+		printk(KERN_ERR "vga16fb: unable to map device\n");
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
+	par = info->par;
+
+	par->isVGA = ORIG_VIDEO_ISVGA;
+	par->palette_blanked = 0;
+	par->vesa_blanked = 0;
+
+	i = par->isVGA? 6 : 2;
+	
+	vga16fb_defined.red.length   = i;
+	vga16fb_defined.green.length = i;
+	vga16fb_defined.blue.length  = i;	
+
+	/* name should not depend on EGA/VGA */
+	info->fbops = &vga16fb_ops;
+	info->var = vga16fb_defined;
+	info->fix = vga16fb_fix;
+	info->flags = FBINFO_FLAG_DEFAULT |
+		FBINFO_HWACCEL_YPAN;
+
+	i = (info->var.bits_per_pixel == 8) ? 256 : 16;
+	ret = fb_alloc_cmap(&info->cmap, i, 0);
+	if (ret) {
+		printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
+		ret = -ENOMEM;
+		goto err_alloc_cmap;
+	}
+
+	if (vga16fb_check_var(&info->var, info)) {
+		printk(KERN_ERR "vga16fb: unable to validate variable\n");
+		ret = -EINVAL;
+		goto err_check_var;
+	}
+
+	vga16fb_update_fix(info);
+
+	if (register_framebuffer(info) < 0) {
+		printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
+		ret = -EINVAL;
+		goto err_check_var;
+	}
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+	dev_set_drvdata(device, info);
+
+	return 0;
+
+ err_check_var:
+	fb_dealloc_cmap(&info->cmap);
+ err_alloc_cmap:
+	iounmap(info->screen_base);
+ err_ioremap:
+	framebuffer_release(info);
+ err_fb_alloc:
+	return ret;
+}
+
+static int vga16fb_remove(struct device *device)
+{
+	struct fb_info *info = dev_get_drvdata(device);
+
+	if (info) {
+		unregister_framebuffer(info);
+		iounmap(info->screen_base);
+		fb_dealloc_cmap(&info->cmap);
+	/* XXX unshare VGA regions */
+		framebuffer_release(info);
+	}
+
+	return 0;
+}
+
+static struct device_driver vga16fb_driver = {
+	.name = "vga16fb",
+	.bus  = &platform_bus_type,
+	.probe = vga16fb_probe,
+	.remove = vga16fb_remove,
+};
+
+static struct platform_device vga16fb_device = {
+	.name = "vga16fb",
+};
+
 static int __init vga16fb_init(void)
 {
-	int i;
 	int ret;
 #ifndef MODULE
 	char *option = NULL;
@@ -1355,77 +1462,21 @@
 
 	vga16fb_setup(option);
 #endif
-	printk(KERN_DEBUG "vga16fb: initializing\n");
+	ret = driver_register(&vga16fb_driver);
 
-	/* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
-
-	vga16fb.screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS);
-	if (!vga16fb.screen_base) {
-		printk(KERN_ERR "vga16fb: unable to map device\n");
-		ret = -ENOMEM;
-		goto err_ioremap;
-	}
-	printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.screen_base);
-
-	vga16_par.isVGA = ORIG_VIDEO_ISVGA;
-	vga16_par.palette_blanked = 0;
-	vga16_par.vesa_blanked = 0;
-
-	i = vga16_par.isVGA? 6 : 2;
-	
-	vga16fb_defined.red.length   = i;
-	vga16fb_defined.green.length = i;
-	vga16fb_defined.blue.length  = i;	
-
-	/* name should not depend on EGA/VGA */
-	vga16fb.fbops = &vga16fb_ops;
-	vga16fb.var = vga16fb_defined;
-	vga16fb.fix = vga16fb_fix;
-	vga16fb.par = &vga16_par;
-	vga16fb.flags = FBINFO_FLAG_DEFAULT |
-		FBINFO_HWACCEL_YPAN;
-
-	i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16;
-	ret = fb_alloc_cmap(&vga16fb.cmap, i, 0);
-	if (ret) {
-		printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
-		ret = -ENOMEM;
-		goto err_alloc_cmap;
+	if (!ret) {
+		ret = platform_device_register(&vga16fb_device);
+		if (ret)
+			driver_unregister(&vga16fb_driver);
 	}
 
-	if (vga16fb_check_var(&vga16fb.var, &vga16fb)) {
-		printk(KERN_ERR "vga16fb: unable to validate variable\n");
-		ret = -EINVAL;
-		goto err_check_var;
-	}
-
-	vga16fb_update_fix(&vga16fb);
-
-	if (register_framebuffer(&vga16fb) < 0) {
-		printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
-		ret = -EINVAL;
-		goto err_check_var;
-	}
-
-	printk(KERN_INFO "fb%d: %s frame buffer device\n",
-	       vga16fb.node, vga16fb.fix.id);
-
-	return 0;
-
- err_check_var:
-	fb_dealloc_cmap(&vga16fb.cmap);
- err_alloc_cmap:
-	iounmap(vga16fb.screen_base);
- err_ioremap:
 	return ret;
 }
 
 static void __exit vga16fb_exit(void)
 {
-    unregister_framebuffer(&vga16fb);
-    iounmap(vga16fb.screen_base);
-    fb_dealloc_cmap(&vga16fb.cmap);
-    /* XXX unshare VGA regions */
+	platform_device_unregister(&vga16fb_device);
+	driver_unregister(&vga16fb_driver);
 }
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c
index ca92940..d9e01da 100644
--- a/drivers/video/vgastate.c
+++ b/drivers/video/vgastate.c
@@ -485,11 +485,6 @@
 	return 0;
 }
 
-#ifdef MODULE
-int init_module(void) { return 0; };
-void cleanup_module(void) {};
-#endif
-
 EXPORT_SYMBOL(save_vga);
 EXPORT_SYMBOL(restore_vga);
 
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index 48e70f1..daa4605 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -437,9 +437,9 @@
 	}
 }
 
-static int w100fb_suspend(struct device *dev, pm_message_t state)
+static int w100fb_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct fb_info *info = dev_get_drvdata(dev);
+	struct fb_info *info = platform_get_drvdata(dev);
 	struct w100fb_par *par=info->par;
 	struct w100_tg_info *tg = par->mach->tg;
 
@@ -452,9 +452,9 @@
 	return 0;
 }
 
-static int w100fb_resume(struct device *dev)
+static int w100fb_resume(struct platform_device *dev)
 {
-	struct fb_info *info = dev_get_drvdata(dev);
+	struct fb_info *info = platform_get_drvdata(dev);
 	struct w100fb_par *par=info->par;
 	struct w100_tg_info *tg = par->mach->tg;
 
@@ -473,13 +473,12 @@
 #endif
 
 
-int __init w100fb_probe(struct device *dev)
+int __init w100fb_probe(struct platform_device *pdev)
 {
 	int err = -EIO;
 	struct w100fb_mach_info *inf;
 	struct fb_info *info = NULL;
 	struct w100fb_par *par;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	unsigned int chip_id;
 
@@ -522,9 +521,9 @@
 	}
 
 	par = info->par;
-	dev_set_drvdata(dev, info);
+	platform_set_drvdata(pdev, info);
 
-	inf = dev->platform_data;
+	inf = pdev->dev.platform_data;
 	par->chip_id = chip_id;
 	par->mach = inf;
 	par->fastpll_mode = 0;
@@ -600,10 +599,10 @@
 		goto out;
 	}
 
-	device_create_file(dev, &dev_attr_fastpllclk);
-	device_create_file(dev, &dev_attr_reg_read);
-	device_create_file(dev, &dev_attr_reg_write);
-	device_create_file(dev, &dev_attr_flip);
+	device_create_file(&pdev->dev, &dev_attr_fastpllclk);
+	device_create_file(&pdev->dev, &dev_attr_reg_read);
+	device_create_file(&pdev->dev, &dev_attr_reg_write);
+	device_create_file(&pdev->dev, &dev_attr_flip);
 
 	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
 	return 0;
@@ -622,15 +621,15 @@
 }
 
 
-static int w100fb_remove(struct device *dev)
+static int w100fb_remove(struct platform_device *pdev)
 {
-	struct fb_info *info = dev_get_drvdata(dev);
+	struct fb_info *info = platform_get_drvdata(pdev);
 	struct w100fb_par *par=info->par;
 
-	device_remove_file(dev, &dev_attr_fastpllclk);
-	device_remove_file(dev, &dev_attr_reg_read);
-	device_remove_file(dev, &dev_attr_reg_write);
-	device_remove_file(dev, &dev_attr_flip);
+	device_remove_file(&pdev->dev, &dev_attr_fastpllclk);
+	device_remove_file(&pdev->dev, &dev_attr_reg_read);
+	device_remove_file(&pdev->dev, &dev_attr_reg_write);
+	device_remove_file(&pdev->dev, &dev_attr_flip);
 
 	unregister_framebuffer(info);
 
@@ -1448,23 +1447,24 @@
 	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
 }
 
-static struct device_driver w100fb_driver = {
-	.name		= "w100fb",
-	.bus		= &platform_bus_type,
+static struct platform_driver w100fb_driver = {
 	.probe		= w100fb_probe,
 	.remove		= w100fb_remove,
 	.suspend	= w100fb_suspend,
 	.resume		= w100fb_resume,
+	.driver		= {
+		.name	= "w100fb",
+	},
 };
 
 int __devinit w100fb_init(void)
 {
-	return driver_register(&w100fb_driver);
+	return platform_driver_register(&w100fb_driver);
 }
 
 void __exit w100fb_cleanup(void)
 {
- 	driver_unregister(&w100fb_driver);
+	platform_driver_unregister(&w100fb_driver);
 }
 
 module_init(w100fb_init);
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index bbc3cc6..89c849d 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -32,7 +32,6 @@
 #include <linux/string.h>
 #include <linux/smp_lock.h>
 #include <linux/inet.h>
-#include <linux/version.h>
 #include <linux/list.h>
 #include <asm/uaccess.h>
 #include <linux/idr.h>
diff --git a/fs/Kconfig b/fs/Kconfig
index 7d6ae36..d5255e6 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1601,9 +1601,10 @@
 	  PC operating systems.  The CIFS protocol is fully supported by 
 	  file servers such as Windows 2000 (including Windows 2003, NT 4  
 	  and Windows XP) as well by Samba (which provides excellent CIFS
-	  server support for Linux and many other operating systems). Currently
-	  you must use the smbfs client filesystem to access older SMB servers
-	  such as Windows 9x and OS/2.
+	  server support for Linux and many other operating systems). Limited
+	  support for Windows ME and similar servers is provided as well. 
+	  You must use the smbfs client filesystem to access older SMB servers
+	  such as OS/2 and DOS.
 
 	  The intent of the cifs module is to provide an advanced
 	  network file system client for mounting to CIFS compliant servers, 
@@ -1614,7 +1615,7 @@
 	  cifs if running only a (Samba) server. It is possible to enable both
 	  smbfs and cifs (e.g. if you are using CIFS for accessing Windows 2003
 	  and Samba 3 servers, and smbfs for accessing old servers). If you need 
-	  to mount to Samba or Windows 2003 servers from this machine, say Y.
+	  to mount to Samba or Windows from this machine, say Y.
 
 config CIFS_STATS
         bool "CIFS statistics"
@@ -1623,8 +1624,22 @@
           Enabling this option will cause statistics for each server share
 	  mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
 
+config CIFS_STATS2
+	bool "CIFS extended statistics"
+	depends on CIFS_STATS
+	help
+	  Enabling this option will allow more detailed statistics on SMB
+	  request timing to be displayed in /proc/fs/cifs/DebugData and also
+	  allow optional logging of slow responses to dmesg (depending on the
+	  value of /proc/fs/cifs/cifsFYI, see fs/cifs/README for more details).
+	  These additional statistics may have a minor effect on performance
+	  and memory utilization.
+
+	  Unless you are a developer or are doing network performance analysis
+	  or tuning, say N.
+
 config CIFS_XATTR
-        bool "CIFS extended attributes (EXPERIMENTAL)"
+        bool "CIFS extended attributes"
         depends on CIFS
         help
           Extended attributes are name:value pairs associated with inodes by
@@ -1636,11 +1651,11 @@
           prefaced by the user namespace prefix. The system namespace
           (used by some filesystems to store ACLs) is not supported at
           this time.
-                                                                                                    
+
           If unsure, say N.
 
 config CIFS_POSIX
-        bool "CIFS POSIX Extensions (EXPERIMENTAL)"
+        bool "CIFS POSIX Extensions"
         depends on CIFS_XATTR
         help
           Enabling this option will cause the cifs client to attempt to
@@ -1653,10 +1668,28 @@
 
 config CIFS_EXPERIMENTAL
 	  bool "CIFS Experimental Features (EXPERIMENTAL)"
-	  depends on CIFS
+	  depends on CIFS && EXPERIMENTAL
 	  help
-	    Enables cifs features under testing. These features
-	    are highly experimental.  If unsure, say N.
+	    Enables cifs features under testing. These features are
+	    experimental and currently include support for writepages
+	    (multipage writebehind performance improvements) and directory
+	    change notification ie fcntl(F_DNOTIFY) as well as some security
+	    improvements.  Some also depend on setting at runtime the
+	    pseudo-file /proc/fs/cifs/Experimental (which is disabled by
+	    default). See the file fs/cifs/README for more details.
+
+	    If unsure, say N.
+
+config CIFS_UPCALL
+	  bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
+	  depends on CIFS_EXPERIMENTAL
+	  select CONNECTOR
+	  help
+	    Enables an upcall mechanism for CIFS which will be used to contact
+	    userspace helper utilities to provide SPNEGO packaged Kerberos
+	    tickets which are needed to mount to certain secure servers
+	    (for which more secure Kerberos authentication is required). If
+	    unsure, say N.
 
 config NCP_FS
 	tristate "NCP file system support (to mount NetWare volumes)"
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index fd52843..f6cd013 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -12,7 +12,6 @@
 #define ADFS_NDA_PUBLIC_READ	(1 << 5)
 #define ADFS_NDA_PUBLIC_WRITE	(1 << 6)
 
-#include <linux/version.h>
 #include "dir_f.h"
 
 struct buffer_head;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 8ae0db6..2568eb4 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -150,7 +150,7 @@
 
 		/* if the binary is not readable than enforce mm->dumpable=0
 		   regardless of the interpreter's permissions */
-		if (permission(bprm->file->f_dentry->d_inode, MAY_READ, NULL))
+		if (file_permission(bprm->file, MAY_READ))
 			bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
 
 		allow_write_access(bprm->file);
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 5bab24f..eab3750 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -2,7 +2,7 @@
 ------------
 Defer close of a file handle slightly if pending writes depend on that file handle
 (this reduces the EBADF bad file handle errors that can be logged under heavy
-stress on writes).
+stress on writes). Modify cifs Kconfig options to expose CONFIG_CIFS_STATS2 
 
 Version 1.38
 ------------
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index 99a096d..4e12053 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -74,10 +74,11 @@
 			cERROR(1,
 			       ("cifs_strtoUCS: char2uni returned %d",
 				charlen));
-			to[i] = cpu_to_le16(0x003f);	/* a question mark */
+			/* A question mark */
+			to[i] = (wchar_t)cpu_to_le16(0x003f);
 			charlen = 1;
 		} else 
-			to[i] = cpu_to_le16(to[i]);
+			to[i] = (wchar_t)cpu_to_le16(to[i]);
 
 	}
 
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 877095a..682b023 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -405,6 +405,7 @@
 };
 #endif
 
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 static void cifs_umount_begin(struct super_block * sblock)
 {
 	struct cifs_sb_info *cifs_sb;
@@ -422,16 +423,18 @@
 		tcon->tidStatus = CifsExiting;
 	up(&tcon->tconSem);
 
+	/* cancel_brl_requests(tcon); */
+	/* cancel_notify_requests(tcon); */
 	if(tcon->ses && tcon->ses->server)
 	{
-		cERROR(1,("wake up tasks now - umount begin not complete"));
+		cFYI(1,("wake up tasks now - umount begin not complete"));
 		wake_up_all(&tcon->ses->server->request_q);
 	}
 /* BB FIXME - finish add checks for tidStatus BB */
 
 	return;
 }
-	
+#endif	
 
 static int cifs_remount(struct super_block *sb, int *flags, char *data)
 {
@@ -450,7 +453,9 @@
    unless later we add lazy close of inodes or unless the kernel forgets to call
    us with the same number of releases (closes) as opens */
 	.show_options = cifs_show_options,
-/*	.umount_begin   = cifs_umount_begin, */ /* BB finish in the future */
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+	.umount_begin   = cifs_umount_begin,
+#endif
 	.remount_fs = cifs_remount,
 };
 
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index d301149b1..1b73f4f 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -242,11 +242,11 @@
 			const int netfid, const unsigned int count,
 			const __u64 offset, unsigned int *nbytes, 
 			struct kvec *iov, const int nvec, const int long_op);
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
 extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName, __u64 * inode_number,
 			const struct nls_table *nls_codepage, 
 			int remap_special_chars);
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
 extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
 			const struct nls_table * codepage);
 extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 9312bfc..a53c596 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2959,7 +2959,6 @@
 	return rc;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 int
 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
                 const unsigned char *searchName,
@@ -3053,7 +3052,6 @@
 		goto GetInodeNumberRetry;
 	return rc;
 }
-#endif /* CIFS_EXPERIMENTAL */
 
 int
 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
diff --git a/fs/cifs/cn_cifs.h b/fs/cifs/cn_cifs.h
new file mode 100644
index 0000000..ea59cca
--- /dev/null
+++ b/fs/cifs/cn_cifs.h
@@ -0,0 +1,37 @@
+/*
+ *   fs/cifs/cn_cifs.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _CN_CIFS_H
+#define _CN_CIFS_H
+#ifdef CONFIG_CIFS_UPCALL
+#include <linux/types.h>
+#include <linux/connector.h>
+
+struct cifs_upcall {
+	char signature[4]; /* CIFS */
+	enum command {
+		CIFS_GET_IP = 0x00000001,   /* get ip address for hostname */
+		CIFS_GET_SECBLOB = 0x00000002, /* get SPNEGO wrapped blob */
+	} command;
+	/* union cifs upcall data follows */
+};
+#endif /* CIFS_UPCALL */
+#endif /* _CN_CIFS_H */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 450ab75..2cb6207 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -42,6 +42,7 @@
 #include "ntlmssp.h"
 #include "nterr.h"
 #include "rfc1002pdu.h"
+#include "cn_cifs.h"
 
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 912d401..923d071 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -283,7 +283,6 @@
 			   there Windows server or network appliances for which
 			   IndexNumber field is not guaranteed unique? */
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL		
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
 				int rc1 = 0;
 				__u64 inode_num;
@@ -299,7 +298,6 @@
 				} else /* do we need cast or hash to ino? */
 					(*pinode)->i_ino = inode_num;
 			} /* else ino incremented to unique num in new_inode*/
-#endif /* CIFS_EXPERIMENTAL */
 			insert_inode_hash(*pinode);
 		}
 		inode = *pinode;
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 4909754..26300fc 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -840,146 +840,6 @@
 	return err ? -EFAULT : 0;
 }
 
-struct fb_fix_screeninfo32 {
-	char			id[16];
-        compat_caddr_t	smem_start;
-	u32			smem_len;
-	u32			type;
-	u32			type_aux;
-	u32			visual;
-	u16			xpanstep;
-	u16			ypanstep;
-	u16			ywrapstep;
-	u32			line_length;
-        compat_caddr_t	mmio_start;
-	u32			mmio_len;
-	u32			accel;
-	u16			reserved[3];
-};
-
-struct fb_cmap32 {
-	u32			start;
-	u32			len;
-	compat_caddr_t	red;
-	compat_caddr_t	green;
-	compat_caddr_t	blue;
-	compat_caddr_t	transp;
-};
-
-static int fb_getput_cmap(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct fb_cmap_user __user *cmap;
-	struct fb_cmap32 __user *cmap32;
-	__u32 data;
-	int err;
-
-	cmap = compat_alloc_user_space(sizeof(*cmap));
-	cmap32 = compat_ptr(arg);
-
-	if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
-		return -EFAULT;
-
-	if (get_user(data, &cmap32->red) ||
-	    put_user(compat_ptr(data), &cmap->red) ||
-	    get_user(data, &cmap32->green) ||
-	    put_user(compat_ptr(data), &cmap->green) ||
-	    get_user(data, &cmap32->blue) ||
-	    put_user(compat_ptr(data), &cmap->blue) ||
-	    get_user(data, &cmap32->transp) ||
-	    put_user(compat_ptr(data), &cmap->transp))
-		return -EFAULT;
-
-	err = sys_ioctl(fd, cmd, (unsigned long) cmap);
-
-	if (!err) {
-		if (copy_in_user(&cmap32->start,
-				 &cmap->start,
-				 2 * sizeof(__u32)))
-			err = -EFAULT;
-	}
-	return err;
-}
-
-static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
-				  struct fb_fix_screeninfo32 __user *fix32)
-{
-	__u32 data;
-	int err;
-
-	err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
-
-	data = (__u32) (unsigned long) fix->smem_start;
-	err |= put_user(data, &fix32->smem_start);
-
-	err |= put_user(fix->smem_len, &fix32->smem_len);
-	err |= put_user(fix->type, &fix32->type);
-	err |= put_user(fix->type_aux, &fix32->type_aux);
-	err |= put_user(fix->visual, &fix32->visual);
-	err |= put_user(fix->xpanstep, &fix32->xpanstep);
-	err |= put_user(fix->ypanstep, &fix32->ypanstep);
-	err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
-	err |= put_user(fix->line_length, &fix32->line_length);
-
-	data = (__u32) (unsigned long) fix->mmio_start;
-	err |= put_user(data, &fix32->mmio_start);
-
-	err |= put_user(fix->mmio_len, &fix32->mmio_len);
-	err |= put_user(fix->accel, &fix32->accel);
-	err |= copy_to_user(fix32->reserved, fix->reserved,
-			    sizeof(fix->reserved));
-
-	return err;
-}
-
-static int fb_get_fscreeninfo(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	mm_segment_t old_fs;
-	struct fb_fix_screeninfo fix;
-	struct fb_fix_screeninfo32 __user *fix32;
-	int err;
-
-	fix32 = compat_ptr(arg);
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_ioctl(fd, cmd, (unsigned long) &fix);
-	set_fs(old_fs);
-
-	if (!err)
-		err = do_fscreeninfo_to_user(&fix, fix32);
-
-	return err;
-}
-
-static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	int err;
-
-	switch (cmd) {
-	case FBIOGET_FSCREENINFO:
-		err = fb_get_fscreeninfo(fd,cmd, arg);
-		break;
-
-  	case FBIOGETCMAP:
-	case FBIOPUTCMAP:
-		err = fb_getput_cmap(fd, cmd, arg);
-		break;
-
-	default:
-		do {
-			static int count;
-			if (++count <= 20)
-				printk("%s: Unknown fb ioctl cmd fd(%d) "
-				       "cmd(%08x) arg(%08lx)\n",
-				       __FUNCTION__, fd, cmd, arg);
-		} while(0);
-		err = -ENOSYS;
-		break;
-	};
-
-	return err;
-}
-
 static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	mm_segment_t old_fs = get_fs();
@@ -2953,10 +2813,7 @@
 HANDLE_IOCTL(0x1260, broken_blkgetsize)
 HANDLE_IOCTL(BLKFRAGET, w_long)
 HANDLE_IOCTL(BLKSECTGET, w_long)
-HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans)
 HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
-HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
-HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans)
 HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
 HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans)
 HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
@@ -3051,6 +2908,16 @@
 COMPATIBLE_IOCTL(TIOCGLTC)
 COMPATIBLE_IOCTL(TIOCSLTC)
 #endif
+#ifdef TIOCSTART
+/*
+ * For these two we have defintions in ioctls.h and/or termios.h on
+ * some architectures but no actual implemention.  Some applications
+ * like bash call them if they are defined in the headers, so we provide
+ * entries here to avoid syslog message spew.
+ */
+COMPATIBLE_IOCTL(TIOCSTART)
+COMPATIBLE_IOCTL(TIOCSTOP)
+#endif
 /* Usbdevfs */
 HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
 HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
diff --git a/fs/exec.c b/fs/exec.c
index cd6c574..c466fec 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -135,7 +135,7 @@
 	if (!S_ISREG(nd.dentry->d_inode->i_mode))
 		goto exit;
 
-	error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC, &nd);
+	error = vfs_permission(&nd, MAY_READ | MAY_EXEC);
 	if (error)
 		goto exit;
 
@@ -495,7 +495,7 @@
 		file = ERR_PTR(-EACCES);
 		if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
 		    S_ISREG(inode->i_mode)) {
-			int err = permission(inode, MAY_EXEC, &nd);
+			int err = vfs_permission(&nd, MAY_EXEC);
 			if (!err && !(inode->i_mode & 0111))
 				err = -EACCES;
 			file = ERR_PTR(err);
@@ -590,6 +590,7 @@
 	struct signal_struct *sig = tsk->signal;
 	struct sighand_struct *newsighand, *oldsighand = tsk->sighand;
 	spinlock_t *lock = &oldsighand->siglock;
+	struct task_struct *leader = NULL;
 	int count;
 
 	/*
@@ -665,7 +666,7 @@
 	 * and to assume its PID:
 	 */
 	if (!thread_group_leader(current)) {
-		struct task_struct *leader = current->group_leader, *parent;
+		struct task_struct *parent;
 		struct dentry *proc_dentry1, *proc_dentry2;
 		unsigned long exit_state, ptrace;
 
@@ -674,6 +675,7 @@
 		 * It should already be zombie at this point, most
 		 * of the time.
 		 */
+		leader = current->group_leader;
 		while (leader->exit_state != EXIT_ZOMBIE)
 			yield();
 
@@ -733,7 +735,6 @@
 		proc_pid_flush(proc_dentry2);
 
 		BUG_ON(exit_state != EXIT_ZOMBIE);
-		release_task(leader);
         }
 
 	/*
@@ -743,8 +744,11 @@
 	sig->flags = 0;
 
 no_thread_group:
-	BUG_ON(atomic_read(&sig->count) != 1);
 	exit_itimers(sig);
+	if (leader)
+		release_task(leader);
+
+	BUG_ON(atomic_read(&sig->count) != 1);
 
 	if (atomic_read(&oldsighand->count) == 1) {
 		/*
@@ -892,7 +896,7 @@
 	flush_thread();
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-	    permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) ||
+	    file_permission(bprm->file, MAY_READ) ||
 	    (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
 		suid_keys(current);
 		current->mm->dumpable = suid_dumpable;
diff --git a/fs/ext2/CHANGES b/fs/ext2/CHANGES
deleted file mode 100644
index aa5aaf0..0000000
--- a/fs/ext2/CHANGES
+++ /dev/null
@@ -1,157 +0,0 @@
-Changes from version 0.5a to version 0.5b
-=========================================
-	- Now that we have sysctl(), the immutable flag cannot be changed when
-	  the system is running at security level > 0.
-	- Some cleanups in the code.
-	- More consistency checks on directories.
-	- The ext2.diff patch from Tom May <ftom@netcom.com> has been
-	  integrated.  This patch replaces expensive "/" and "%" with
-	  cheap ">>" and "&" where possible.
-
-Changes from version 0.5 to version 0.5a
-========================================
-	- Zero the partial block following the end of the file when a file
-	  is truncated.
-	- Dates updated in the copyright.
-	- More checks when the filesystem is mounted: the count of blocks,
-	  fragments, and inodes per group is checked against the block size.
-	- The buffers used by the error routines are now static variables, to
-	  avoid using space on the kernel stack, as requested by Linus.
-	- Some cleanups in the error messages (some versions of syslog contain
-	  a bug which truncates an error message if it contains '\n').
-	- Check that no data can be written to a file past the 2GB limit.
-	- The famous readdir() bug has been fixed by Stephen Tweedie.
-	- Added a revision level in the superblock.
-	- Full support for O_SYNC flag of the open system call.
-	- New mount options: `resuid=#uid' and `resgid=#gid'.  `resuid' causes
-	  ext2fs to consider user #uid like root for the reserved blocks.
-	  `resgid' acts the same way with group #gid.  New fields in the
-	  superblock contain default values for resuid and resgid and can
-	  be modified by tune2fs.
-	  Idea comes from Rene Cougnenc <cougnenc@renux.frmug.fr.net>.
-	- New mount options: `bsddf' and `minixdf'.  `bsddf' causes ext2fs
-	  to remove the blocks used for FS structures from the total block
-	  count in statfs.  With `minixdf', ext2fs mimics Minix behavior
-	  in statfs (i.e. it returns the total number of blocks on the
-	  partition).  This is intended to make bde happy :-)
-	- New file attributes:
-	  - Immutable files cannot be modified.  Data cannot be written to
-	    these files.  They cannot be removed, renamed and new links cannot
-	    be created.  Even root cannot modify the files.  He has to remove
-	    the immutable attribute first.
-	  - Append-only files: can only be written in append-mode when writing.
-	    They cannot be removed, renamed and new links cannot be created.
-	    Note: files may only be added to an append-only directory.
-	  - No-dump files: the attribute is not used by the kernel.  My port
-	    of dump uses it to avoid backing up files which are not important.
-	- New check in ext2_check_dir_entry: the inode number is checked.
-	- Support for big file systems: the copy of the FS descriptor is now
-	  dynamically allocated (previous versions used a fixed size array).
-	  This allows to mount 2GB+ FS.
-	- Reorganization of the ext2_inode structure to allow other operating
-	  systems to create specific fields if they use ext2fs as their native
-	  file system.  Currently, ext2fs is only implemented in Linux but
-	  will soon be part of Gnu Hurd and of Masix.
-
-Changes from version 0.4b to version 0.5
-========================================
-	- New superblock fields: s_lastcheck and s_checkinterval added
-	  by Uwe Ohse <uwe@tirka.gun.de> to implement timedependent checks
-	  of the file system
-	- Real random numbers for secure rm added by Pierre del Perugia
-	  <delperug@gla.ecoledoc.ibp.fr>
-	- The mount warnings related to the state of a fs are not printed
-	  if the fs is mounted read-only, idea by Nick Holloway
-	  <alfie@dcs.warwick.ac.uk>
-
-Changes from version 0.4a to version 0.4b
-=========================================
-	- Copyrights changed to include the name of my laboratory.
-	- Clean up of balloc.c and ialloc.c.
-	- More consistency checks.
-	- Block preallocation added by Stephen Tweedie.
-	- Direct reads of directories disallowed.
-	- Readahead implemented in readdir by Stephen Tweedie.
-	- Bugs in block and inodes allocation fixed.
-	- Readahead implemented in ext2_find_entry by Chip Salzenberg.
-	- New mount options:
-	  `check=none|normal|strict'
-	  `debug'
-	  `errors=continue|remount-ro|panic'
-	  `grpid', `bsdgroups'
-	  `nocheck'
-	  `nogrpid', `sysvgroups'
-	- truncate() now tries to deallocate contiguous blocks in a single call
-	  to ext2_free_blocks().
-	- lots of cosmetic changes.
-
-Changes from version 0.4 to version 0.4a
-========================================
-        - the `sync' option support is now complete.  Version 0.4 was not
-          supporting it when truncating a file.  I have tested the synchronous
-          writes and they work but they make the system very slow :-(  I have
-          to work again on this to make it faster.
-        - when detecting an error on a mounted filesystem, version 0.4 used
-          to try to write a flag in the super block even if the filesystem had
-          been mounted read-only.  This is fixed.
-        - the `sb=#' option now causes the kernel code to use the filesystem
-          descriptors located at block #+1.  Version 0.4 used the superblock
-          backup located at block # but used the main copy of the descriptors.
-        - a new file attribute `S' is supported.  This attribute causes
-          synchronous writes but is applied to a file not to the entire file
-          system (thanks to Michael Kraehe <kraehe@bakunin.north.de> for
-          suggesting it).
-        - the directory cache is inhibited by default.  The cache management
-          code seems to be buggy and I have to look at it carefully before
-          using it again.
-        - deleting a file with the `s' attribute (secure deletion) causes its
-          blocks to be overwritten with random values not with zeros (thanks to
-          Michael A. Griffith <grif@cs.ucr.edu> for suggesting it).
-        - lots of cosmetic changes have been made.
-
-Changes from version 0.3 to version 0.4
-=======================================
-        - Three new mount options are supported: `check', `sync' and `sb=#'.
-          `check' tells the kernel code to make more consistency checks
-          when the file system is mounted.  Currently, the kernel code checks
-          that the blocks and inodes bitmaps are consistent with the free
-          blocks and inodes counts.  More checks will be added in future
-          releases.
-          `sync' tells the kernel code to use synchronous writes when updating
-          an inode, a bitmap, a directory entry or an indirect block.  This
-          can make the file system much slower but can be a big win for files
-          recovery in case of a crash (and we can now say to the BSD folks
-          that Linux also supports synchronous updates :-).
-          `sb=#' tells the kernel code to use an alternate super block instead
-          of its master copy.  `#' is the number of the block (counted in
-          1024 bytes blocks) which contains the alternate super block.
-          An ext2 file system typically contains backups of the super block
-          at blocks 8193, 16385, and so on.
-        - I have change the meaning of the valid flag used by e2fsck.  it
-          now contains the state of the file system.  If the kernel code
-          detects an inconsistency while the file system is mounted, it flags
-          it as erroneous and e2fsck will detect that on next run.
-        - The super block now contains a mount counter.  This counter is
-          incremented each time the file system is mounted read/write.   When
-          this counter becomes bigger than a maximal mount counts (also stored
-          in the super block), e2fsck checks the file system, even if it had
-          been unmounted cleanly, and resets this counter to 0.
-        - File attributes are now supported.  One can associate a set of
-          attributes to a file.  Three attributes are defined:
-          `c': the file is marked for automatic compression,
-          `s': the file is marked for secure deletion: when the file is
-          deleted, its blocks are zeroed and written back to the disk,
-          `u': the file is marked for undeletion: when the file is deleted,
-          its contents are saved to allow a future undeletion.
-          Currently, only the `s' attribute is implemented in the kernel
-          code.  Support for the other attributes will be added in a future
-          release.
-        - a few bugs related to times updates have been fixed by Bruce
-          Evans and me.
-        - a bug related to the links count of deleted inodes has been fixed.
-          Previous versions used to keep the links count set to 1 when a file
-          was deleted.  The new version now sets links_count to 0 when deleting
-          the last link.
-        - a race condition when deallocating an inode has been fixed by
-          Stephen Tweedie.
-
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 6591abe..bb69080 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -624,76 +624,3 @@
 	return EXT2_SB(sb)->s_gdb_count;
 }
 
-#ifdef CONFIG_EXT2_CHECK
-/* Called at mount-time, super-block is locked */
-void ext2_check_blocks_bitmap (struct super_block * sb)
-{
-	struct buffer_head *bitmap_bh = NULL;
-	struct ext2_super_block * es;
-	unsigned long desc_count, bitmap_count, x, j;
-	unsigned long desc_blocks;
-	struct ext2_group_desc * desc;
-	int i;
-
-	es = EXT2_SB(sb)->s_es;
-	desc_count = 0;
-	bitmap_count = 0;
-	desc = NULL;
-	for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
-		desc = ext2_get_group_desc (sb, i, NULL);
-		if (!desc)
-			continue;
-		desc_count += le16_to_cpu(desc->bg_free_blocks_count);
-		brelse(bitmap_bh);
-		bitmap_bh = read_block_bitmap(sb, i);
-		if (!bitmap_bh)
-			continue;
-
-		if (ext2_bg_has_super(sb, i) &&
-				!ext2_test_bit(0, bitmap_bh->b_data))
-			ext2_error(sb, __FUNCTION__,
-				   "Superblock in group %d is marked free", i);
-
-		desc_blocks = ext2_bg_num_gdb(sb, i);
-		for (j = 0; j < desc_blocks; j++)
-			if (!ext2_test_bit(j + 1, bitmap_bh->b_data))
-				ext2_error(sb, __FUNCTION__,
-					   "Descriptor block #%ld in group "
-					   "%d is marked free", j, i);
-
-		if (!block_in_use(le32_to_cpu(desc->bg_block_bitmap),
-					sb, bitmap_bh->b_data))
-			ext2_error(sb, "ext2_check_blocks_bitmap",
-				    "Block bitmap for group %d is marked free",
-				    i);
-
-		if (!block_in_use(le32_to_cpu(desc->bg_inode_bitmap),
-					sb, bitmap_bh->b_data))
-			ext2_error(sb, "ext2_check_blocks_bitmap",
-				    "Inode bitmap for group %d is marked free",
-				    i);
-
-		for (j = 0; j < EXT2_SB(sb)->s_itb_per_group; j++)
-			if (!block_in_use(le32_to_cpu(desc->bg_inode_table) + j,
-						sb, bitmap_bh->b_data))
-				ext2_error (sb, "ext2_check_blocks_bitmap",
-					    "Block #%ld of the inode table in "
-					    "group %d is marked free", j, i);
-
-		x = ext2_count_free(bitmap_bh, sb->s_blocksize);
-		if (le16_to_cpu(desc->bg_free_blocks_count) != x)
-			ext2_error (sb, "ext2_check_blocks_bitmap",
-				    "Wrong free blocks count for group %d, "
-				    "stored = %d, counted = %lu", i,
-				    le16_to_cpu(desc->bg_free_blocks_count), x);
-		bitmap_count += x;
-	}
-	if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)
-		ext2_error (sb, "ext2_check_blocks_bitmap",
-			"Wrong free blocks count in super block, "
-			"stored = %lu, counted = %lu",
-			(unsigned long)le32_to_cpu(es->s_free_blocks_count),
-			bitmap_count);
-	brelse(bitmap_bh);
-}
-#endif
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index e2d6208..74714af 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -700,43 +700,3 @@
 	return count;
 }
 
-#ifdef CONFIG_EXT2_CHECK
-/* Called at mount-time, super-block is locked */
-void ext2_check_inodes_bitmap (struct super_block * sb)
-{
-	struct ext2_super_block * es = EXT2_SB(sb)->s_es;
-	unsigned long desc_count = 0, bitmap_count = 0;
-	struct buffer_head *bitmap_bh = NULL;
-	int i;
-
-	for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
-		struct ext2_group_desc *desc;
-		unsigned x;
-
-		desc = ext2_get_group_desc(sb, i, NULL);
-		if (!desc)
-			continue;
-		desc_count += le16_to_cpu(desc->bg_free_inodes_count);
-		brelse(bitmap_bh);
-		bitmap_bh = read_inode_bitmap(sb, i);
-		if (!bitmap_bh)
-			continue;
-		
-		x = ext2_count_free(bitmap_bh, EXT2_INODES_PER_GROUP(sb) / 8);
-		if (le16_to_cpu(desc->bg_free_inodes_count) != x)
-			ext2_error (sb, "ext2_check_inodes_bitmap",
-				    "Wrong free inodes count in group %d, "
-				    "stored = %d, counted = %lu", i,
-				    le16_to_cpu(desc->bg_free_inodes_count), x);
-		bitmap_count += x;
-	}
-	brelse(bitmap_bh);
-	if (percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter) !=
-				bitmap_count)
-		ext2_error(sb, "ext2_check_inodes_bitmap",
-			    "Wrong free inodes count in super block, "
-			    "stored = %lu, counted = %lu",
-			    (unsigned long)le32_to_cpu(es->s_free_inodes_count),
-			    bitmap_count);
-}
-#endif
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 3c0c7c6..e4ed4b3 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -281,7 +281,7 @@
 enum {
 	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
 	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic,
-	Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug,
+	Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug,
 	Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
 	Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota,
 	Opt_usrquota, Opt_grpquota
@@ -303,7 +303,6 @@
 	{Opt_nouid32, "nouid32"},
 	{Opt_nocheck, "check=none"},
 	{Opt_nocheck, "nocheck"},
-	{Opt_check, "check"},
 	{Opt_debug, "debug"},
 	{Opt_oldalloc, "oldalloc"},
 	{Opt_orlov, "orlov"},
@@ -376,13 +375,6 @@
 		case Opt_nouid32:
 			set_opt (sbi->s_mount_opt, NO_UID32);
 			break;
-		case Opt_check:
-#ifdef CONFIG_EXT2_CHECK
-			set_opt (sbi->s_mount_opt, CHECK);
-#else
-			printk("EXT2 Check option not supported\n");
-#endif
-			break;
 		case Opt_nocheck:
 			clear_opt (sbi->s_mount_opt, CHECK);
 			break;
@@ -503,12 +495,6 @@
 			EXT2_BLOCKS_PER_GROUP(sb),
 			EXT2_INODES_PER_GROUP(sb),
 			sbi->s_mount_opt);
-#ifdef CONFIG_EXT2_CHECK
-	if (test_opt (sb, CHECK)) {
-		ext2_check_blocks_bitmap (sb);
-		ext2_check_inodes_bitmap (sb);
-	}
-#endif
 	return res;
 }
 
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 7992d21..ae1148c 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1517,76 +1517,3 @@
 	return EXT3_SB(sb)->s_gdb_count;
 }
 
-#ifdef CONFIG_EXT3_CHECK
-/* Called at mount-time, super-block is locked */
-void ext3_check_blocks_bitmap (struct super_block * sb)
-{
-	struct ext3_super_block *es;
-	unsigned long desc_count, bitmap_count, x, j;
-	unsigned long desc_blocks;
-	struct buffer_head *bitmap_bh = NULL;
-	struct ext3_group_desc *gdp;
-	int i;
-
-	es = EXT3_SB(sb)->s_es;
-	desc_count = 0;
-	bitmap_count = 0;
-	gdp = NULL;
-	for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
-		gdp = ext3_get_group_desc (sb, i, NULL);
-		if (!gdp)
-			continue;
-		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-		brelse(bitmap_bh);
-		bitmap_bh = read_block_bitmap(sb, i);
-		if (bitmap_bh == NULL)
-			continue;
-
-		if (ext3_bg_has_super(sb, i) &&
-				!ext3_test_bit(0, bitmap_bh->b_data))
-			ext3_error(sb, __FUNCTION__,
-				   "Superblock in group %d is marked free", i);
-
-		desc_blocks = ext3_bg_num_gdb(sb, i);
-		for (j = 0; j < desc_blocks; j++)
-			if (!ext3_test_bit(j + 1, bitmap_bh->b_data))
-				ext3_error(sb, __FUNCTION__,
-					   "Descriptor block #%ld in group "
-					   "%d is marked free", j, i);
-
-		if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap),
-						sb, bitmap_bh->b_data))
-			ext3_error (sb, "ext3_check_blocks_bitmap",
-				    "Block bitmap for group %d is marked free",
-				    i);
-
-		if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap),
-						sb, bitmap_bh->b_data))
-			ext3_error (sb, "ext3_check_blocks_bitmap",
-				    "Inode bitmap for group %d is marked free",
-				    i);
-
-		for (j = 0; j < EXT3_SB(sb)->s_itb_per_group; j++)
-			if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j,
-							sb, bitmap_bh->b_data))
-				ext3_error (sb, "ext3_check_blocks_bitmap",
-					    "Block #%d of the inode table in "
-					    "group %d is marked free", j, i);
-
-		x = ext3_count_free(bitmap_bh, sb->s_blocksize);
-		if (le16_to_cpu(gdp->bg_free_blocks_count) != x)
-			ext3_error (sb, "ext3_check_blocks_bitmap",
-				    "Wrong free blocks count for group %d, "
-				    "stored = %d, counted = %lu", i,
-				    le16_to_cpu(gdp->bg_free_blocks_count), x);
-		bitmap_count += x;
-	}
-	brelse(bitmap_bh);
-	if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)
-		ext3_error (sb, "ext3_check_blocks_bitmap",
-			"Wrong free blocks count in super block, "
-			"stored = %lu, counted = %lu",
-			(unsigned long)le32_to_cpu(es->s_free_blocks_count),
-			bitmap_count);
-}
-#endif
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index df3f517..9e4a243 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -756,44 +756,3 @@
 	return count;
 }
 
-#ifdef CONFIG_EXT3_CHECK
-/* Called at mount-time, super-block is locked */
-void ext3_check_inodes_bitmap (struct super_block * sb)
-{
-	struct ext3_super_block * es;
-	unsigned long desc_count, bitmap_count, x;
-	struct buffer_head *bitmap_bh = NULL;
-	struct ext3_group_desc * gdp;
-	int i;
-
-	es = EXT3_SB(sb)->s_es;
-	desc_count = 0;
-	bitmap_count = 0;
-	gdp = NULL;
-	for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
-		gdp = ext3_get_group_desc (sb, i, NULL);
-		if (!gdp)
-			continue;
-		desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
-		brelse(bitmap_bh);
-		bitmap_bh = read_inode_bitmap(sb, i);
-		if (!bitmap_bh)
-			continue;
-
-		x = ext3_count_free(bitmap_bh, EXT3_INODES_PER_GROUP(sb) / 8);
-		if (le16_to_cpu(gdp->bg_free_inodes_count) != x)
-			ext3_error (sb, "ext3_check_inodes_bitmap",
-				    "Wrong free inodes count in group %d, "
-				    "stored = %d, counted = %lu", i,
-				    le16_to_cpu(gdp->bg_free_inodes_count), x);
-		bitmap_count += x;
-	}
-	brelse(bitmap_bh);
-	if (le32_to_cpu(es->s_free_inodes_count) != bitmap_count)
-		ext3_error (sb, "ext3_check_inodes_bitmap",
-			    "Wrong free inodes count in super block, "
-			    "stored = %lu, counted = %lu",
-			    (unsigned long)le32_to_cpu(es->s_free_inodes_count),
-			    bitmap_count);
-}
-#endif
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index f594989..4e67306 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -625,7 +625,7 @@
 enum {
 	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
 	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
-	Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
+	Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
 	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
 	Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh,
 	Opt_commit, Opt_journal_update, Opt_journal_inum,
@@ -652,7 +652,6 @@
 	{Opt_nouid32, "nouid32"},
 	{Opt_nocheck, "nocheck"},
 	{Opt_nocheck, "check=none"},
-	{Opt_check, "check"},
 	{Opt_debug, "debug"},
 	{Opt_oldalloc, "oldalloc"},
 	{Opt_orlov, "orlov"},
@@ -773,14 +772,6 @@
 		case Opt_nouid32:
 			set_opt (sbi->s_mount_opt, NO_UID32);
 			break;
-		case Opt_check:
-#ifdef CONFIG_EXT3_CHECK
-			set_opt (sbi->s_mount_opt, CHECK);
-#else
-			printk(KERN_ERR
-			       "EXT3 Check option not supported\n");
-#endif
-			break;
 		case Opt_nocheck:
 			clear_opt (sbi->s_mount_opt, CHECK);
 			break;
@@ -1115,12 +1106,6 @@
 	} else {
 		printk("internal journal\n");
 	}
-#ifdef CONFIG_EXT3_CHECK
-	if (test_opt (sb, CHECK)) {
-		ext3_check_blocks_bitmap (sb);
-		ext3_check_inodes_bitmap (sb);
-	}
-#endif
 	return res;
 }
 
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index e2effe2..a0f9b9f 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -846,7 +846,7 @@
 	{Opt_err, NULL}
 };
 
-static int parse_options(char *options, int is_vfat, int *debug,
+static int parse_options(char *options, int is_vfat, int silent, int *debug,
 			 struct fat_mount_options *opts)
 {
 	char *p;
@@ -1008,8 +1008,11 @@
 			break;
 		/* unknown option */
 		default:
-			printk(KERN_ERR "FAT: Unrecognized mount option \"%s\" "
-			       "or missing value\n", p);
+			if (!silent) {
+				printk(KERN_ERR
+				       "FAT: Unrecognized mount option \"%s\" "
+				       "or missing value\n", p);
+			}
 			return -EINVAL;
 		}
 	}
@@ -1091,7 +1094,7 @@
 	sb->s_export_op = &fat_export_ops;
 	sbi->dir_ops = fs_dir_inode_ops;
 
-	error = parse_options(data, isvfat, &debug, &sbi->options);
+	error = parse_options(data, isvfat, silent, &debug, &sbi->options);
 	if (error)
 		goto out_fail;
 
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index aae019a..cc5dcd5 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -9,7 +9,6 @@
 #ifndef _LINUX_HFS_FS_H
 #define _LINUX_HFS_FS_H
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/buffer_head.h>
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 3f680c5..d499393a 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -12,7 +12,6 @@
  */
 
 #include <linux/pagemap.h>
-#include <linux/version.h>
 #include <linux/mpage.h>
 
 #include "hfs_fs.h"
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
index b85abc6..930cd92 100644
--- a/fs/hfsplus/bnode.c
+++ b/fs/hfsplus/bnode.c
@@ -13,7 +13,6 @@
 #include <linux/pagemap.h>
 #include <linux/fs.h>
 #include <linux/swap.h>
-#include <linux/version.h>
 
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 7bda766..50c8f44b 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <linux/version.h>
 
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c
index e7235ca..e3ff56a 100644
--- a/fs/hfsplus/extents.c
+++ b/fs/hfsplus/extents.c
@@ -11,7 +11,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include <linux/version.h>
 
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 2bc0cdd..c60e563 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -11,7 +11,6 @@
 #define _LINUX_HFSPLUS_FS_H
 
 #include <linux/fs.h>
-#include <linux/version.h>
 #include <linux/buffer_head.h>
 #include "hfsplus_raw.h"
 
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index f205773..fc98583 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -11,7 +11,6 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include <linux/version.h>
 #include <linux/mpage.h>
 
 #include "hfsplus_fs.h"
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 452fc1f..0ce1c45 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -14,7 +14,6 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 #include <linux/vfs.h>
 #include <linux/nls.h>
 
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c
index 0c51d63..95455e8 100644
--- a/fs/hfsplus/wrapper.c
+++ b/fs/hfsplus/wrapper.c
@@ -12,7 +12,6 @@
 #include <linux/blkdev.h>
 #include <linux/cdrom.h>
 #include <linux/genhd.h>
-#include <linux/version.h>
 #include <asm/unaligned.h>
 
 #include "hfsplus_fs.h"
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index a33fb1d..4684eb7 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -8,7 +8,6 @@
 
 #include <linux/stddef.h>
 #include <linux/fs.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index ab144da..7c995ac 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -114,11 +114,8 @@
 	ssize_t retval;
 
 	retval = generic_file_write(file, buf, count, ppos);
-	if (retval > 0) {
-		struct inode *inode = file->f_dentry->d_inode;
-		inode->i_mtime = CURRENT_TIME_SEC;
-		hpfs_i(inode)->i_dirty = 1;
-	}
+	if (retval > 0)
+		hpfs_i(file->f_dentry->d_inode)->i_dirty = 1;
 	return retval;
 }
 
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index e026c80..64983ab 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -63,7 +63,7 @@
  *
  * Result is in bytes to be compatible with is_hugepage_mem_enough()
  */
-unsigned long
+static unsigned long
 huge_pages_needed(struct address_space *mapping, struct vm_area_struct *vma)
 {
 	int i;
diff --git a/fs/inotify.c b/fs/inotify.c
index 9fbaebf..bf7ce1d 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -372,7 +372,7 @@
 	if (error)
 		return error;
 	/* you can only watch an inode if you have read permissions on it */
-	error = permission(nd->dentry->d_inode, MAY_READ, NULL);
+	error = vfs_permission(nd, MAY_READ);
 	if (error) 
 		path_release(nd);
 	return error;
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 1abe734..4abbe86 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -827,6 +827,7 @@
 	/* update object inode */
 	ip->i_nlink++;		/* for new link */
 	ip->i_ctime = CURRENT_TIME;
+	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(dir);
 	atomic_inc(&ip->i_count);
 
@@ -1024,6 +1025,8 @@
 	insert_inode_hash(ip);
 	mark_inode_dirty(ip);
 
+	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(dip);
 	/*
 	 * commit update of parent directory and link object
 	 */
diff --git a/fs/namei.c b/fs/namei.c
index b3f8a19..6dbbd42 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -256,6 +256,38 @@
 	return security_inode_permission(inode, mask, nd);
 }
 
+/**
+ * vfs_permission  -  check for access rights to a given path
+ * @nd:		lookup result that describes the path
+ * @mask:	right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
+ *
+ * Used to check for read/write/execute permissions on a path.
+ * We use "fsuid" for this, letting us set arbitrary permissions
+ * for filesystem access without changing the "normal" uids which
+ * are used for other things.
+ */
+int vfs_permission(struct nameidata *nd, int mask)
+{
+	return permission(nd->dentry->d_inode, mask, nd);
+}
+
+/**
+ * file_permission  -  check for additional access rights to a given file
+ * @file:	file to check access rights for
+ * @mask:	right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
+ *
+ * Used to check for read/write/execute permissions on an already opened
+ * file.
+ *
+ * Note:
+ *	Do not use this function in new code.  All access checks should
+ *	be done using vfs_permission().
+ */
+int file_permission(struct file *file, int mask)
+{
+	return permission(file->f_dentry->d_inode, mask, NULL);
+}
+
 /*
  * get_write_access() gets write permission for a file.
  * put_write_access() releases this write permission.
@@ -765,9 +797,8 @@
 
 		nd->flags |= LOOKUP_CONTINUE;
 		err = exec_permission_lite(inode, nd);
-		if (err == -EAGAIN) { 
-			err = permission(inode, MAY_EXEC, nd);
-		}
+		if (err == -EAGAIN)
+			err = vfs_permission(nd, MAY_EXEC);
  		if (err)
 			break;
 
@@ -1109,8 +1140,9 @@
  * @open_flags: open intent flags
  * @create_mode: create intent flags
  */
-int path_lookup_create(const char *name, unsigned int lookup_flags,
-		struct nameidata *nd, int open_flags, int create_mode)
+static int path_lookup_create(const char *name, unsigned int lookup_flags,
+			      struct nameidata *nd, int open_flags,
+			      int create_mode)
 {
 	return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd,
 			open_flags, create_mode);
@@ -1173,9 +1205,9 @@
 	return dentry;
 }
 
-struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
+struct dentry * lookup_hash(struct nameidata *nd)
 {
-	return __lookup_hash(name, base, NULL);
+	return __lookup_hash(&nd->last, nd->dentry, nd);
 }
 
 /* SMP-safe */
@@ -1199,7 +1231,7 @@
 	}
 	this.hash = end_name_hash(hash);
 
-	return lookup_hash(&this, base);
+	return __lookup_hash(&this, base, NULL);
 access:
 	return ERR_PTR(-EACCES);
 }
@@ -1407,7 +1439,7 @@
 	if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
 		return -EISDIR;
 
-	error = permission(inode, acc_mode, nd);
+	error = vfs_permission(nd, acc_mode);
 	if (error)
 		return error;
 
@@ -1532,7 +1564,7 @@
 	dir = nd->dentry;
 	nd->flags &= ~LOOKUP_PARENT;
 	down(&dir->d_inode->i_sem);
-	path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
+	path.dentry = lookup_hash(nd);
 	path.mnt = nd->mnt;
 
 do_last:
@@ -1634,7 +1666,7 @@
 	}
 	dir = nd->dentry;
 	down(&dir->d_inode->i_sem);
-	path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
+	path.dentry = lookup_hash(nd);
 	path.mnt = nd->mnt;
 	__putname(nd->last.name);
 	goto do_last;
@@ -1666,7 +1698,7 @@
 	/*
 	 * Do the final lookup.
 	 */
-	dentry = lookup_hash(&nd->last, nd->dentry);
+	dentry = lookup_hash(nd);
 	if (IS_ERR(dentry))
 		goto fail;
 
@@ -1901,7 +1933,7 @@
 			goto exit1;
 	}
 	down(&nd.dentry->d_inode->i_sem);
-	dentry = lookup_hash(&nd.last, nd.dentry);
+	dentry = lookup_hash(&nd);
 	error = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
 		error = vfs_rmdir(nd.dentry->d_inode, dentry);
@@ -1970,7 +2002,7 @@
 	if (nd.last_type != LAST_NORM)
 		goto exit1;
 	down(&nd.dentry->d_inode->i_sem);
-	dentry = lookup_hash(&nd.last, nd.dentry);
+	dentry = lookup_hash(&nd);
 	error = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
 		/* Why not before? Because we want correct error value */
@@ -2313,7 +2345,7 @@
 
 	trap = lock_rename(new_dir, old_dir);
 
-	old_dentry = lookup_hash(&oldnd.last, old_dir);
+	old_dentry = lookup_hash(&oldnd);
 	error = PTR_ERR(old_dentry);
 	if (IS_ERR(old_dentry))
 		goto exit3;
@@ -2333,7 +2365,7 @@
 	error = -EINVAL;
 	if (old_dentry == trap)
 		goto exit4;
-	new_dentry = lookup_hash(&newnd.last, new_dir);
+	new_dentry = lookup_hash(&newnd);
 	error = PTR_ERR(new_dentry);
 	if (IS_ERR(new_dentry))
 		goto exit4;
@@ -2536,6 +2568,8 @@
 EXPORT_SYMBOL(path_release);
 EXPORT_SYMBOL(path_walk);
 EXPORT_SYMBOL(permission);
+EXPORT_SYMBOL(vfs_permission);
+EXPORT_SYMBOL(file_permission);
 EXPORT_SYMBOL(unlock_rename);
 EXPORT_SYMBOL(vfs_create);
 EXPORT_SYMBOL(vfs_follow_link);
diff --git a/fs/namespace.c b/fs/namespace.c
index caa9187..2019899f 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -637,7 +637,7 @@
 		if (current->uid != nd->dentry->d_inode->i_uid)
 			return -EPERM;
 	}
-	if (permission(nd->dentry->d_inode, MAY_WRITE, nd))
+	if (vfs_permission(nd, MAY_WRITE))
 		return -EPERM;
 	return 0;
 #endif
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 88df793..fd3efdc 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -30,11 +30,13 @@
 #define NCP_PACKET_SIZE_INTERNAL 65536
 
 static int
-ncp_get_fs_info(struct ncp_server* server, struct inode* inode, struct ncp_fs_info __user *arg)
+ncp_get_fs_info(struct ncp_server * server, struct file *file,
+		struct ncp_fs_info __user *arg)
 {
+	struct inode *inode = file->f_dentry->d_inode;
 	struct ncp_fs_info info;
 
-	if ((permission(inode, MAY_WRITE, NULL) != 0)
+	if ((file_permission(file, MAY_WRITE) != 0)
 	    && (current->uid != server->m.mounted_uid)) {
 		return -EACCES;
 	}
@@ -58,11 +60,13 @@
 }
 
 static int
-ncp_get_fs_info_v2(struct ncp_server* server, struct inode* inode, struct ncp_fs_info_v2 __user * arg)
+ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
+		   struct ncp_fs_info_v2 __user * arg)
 {
+	struct inode *inode = file->f_dentry->d_inode;
 	struct ncp_fs_info_v2 info2;
 
-	if ((permission(inode, MAY_WRITE, NULL) != 0)
+	if ((file_permission(file, MAY_WRITE) != 0)
 	    && (current->uid != server->m.mounted_uid)) {
 		return -EACCES;
 	}
@@ -190,7 +194,7 @@
 	switch (cmd) {
 	case NCP_IOC_NCPREQUEST:
 
-		if ((permission(inode, MAY_WRITE, NULL) != 0)
+		if ((file_permission(filp, MAY_WRITE) != 0)
 		    && (current->uid != server->m.mounted_uid)) {
 			return -EACCES;
 		}
@@ -245,16 +249,16 @@
 		return ncp_conn_logged_in(inode->i_sb);
 
 	case NCP_IOC_GET_FS_INFO:
-		return ncp_get_fs_info(server, inode, argp);
+		return ncp_get_fs_info(server, filp, argp);
 
 	case NCP_IOC_GET_FS_INFO_V2:
-		return ncp_get_fs_info_v2(server, inode, argp);
+		return ncp_get_fs_info_v2(server, filp, argp);
 
 	case NCP_IOC_GETMOUNTUID2:
 		{
 			unsigned long tmp = server->m.mounted_uid;
 
-			if (   (permission(inode, MAY_READ, NULL) != 0)
+			if ((file_permission(filp, MAY_READ) != 0)
 			    && (current->uid != server->m.mounted_uid))
 			{
 				return -EACCES;
@@ -268,7 +272,7 @@
 		{
 			struct ncp_setroot_ioctl sr;
 
-			if (   (permission(inode, MAY_READ, NULL) != 0)
+			if ((file_permission(filp, MAY_READ) != 0)
 			    && (current->uid != server->m.mounted_uid))
 			{
 				return -EACCES;
@@ -343,7 +347,7 @@
 
 #ifdef CONFIG_NCPFS_PACKET_SIGNING	
 	case NCP_IOC_SIGN_INIT:
-		if ((permission(inode, MAY_WRITE, NULL) != 0)
+		if ((file_permission(filp, MAY_WRITE) != 0)
 		    && (current->uid != server->m.mounted_uid))
 		{
 			return -EACCES;
@@ -366,7 +370,7 @@
 		return 0;		
 		
         case NCP_IOC_SIGN_WANTED:
-		if (   (permission(inode, MAY_READ, NULL) != 0)
+		if ((file_permission(filp, MAY_READ) != 0)
 		    && (current->uid != server->m.mounted_uid))
 		{
 			return -EACCES;
@@ -379,7 +383,7 @@
 		{
 			int newstate;
 
-			if (   (permission(inode, MAY_WRITE, NULL) != 0)
+			if ((file_permission(filp, MAY_WRITE) != 0)
 			    && (current->uid != server->m.mounted_uid))
 			{
 				return -EACCES;
@@ -400,7 +404,7 @@
 
 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
 	case NCP_IOC_LOCKUNLOCK:
-		if (   (permission(inode, MAY_WRITE, NULL) != 0)
+		if ((file_permission(filp, MAY_WRITE) != 0)
 		    && (current->uid != server->m.mounted_uid))
 		{
 			return -EACCES;
@@ -605,7 +609,7 @@
 #endif /* CONFIG_NCPFS_NLS */
 
 	case NCP_IOC_SETDENTRYTTL:
-		if ((permission(inode, MAY_WRITE, NULL) != 0) &&
+		if ((file_permission(filp, MAY_WRITE) != 0) &&
 				 (current->uid != server->m.mounted_uid))
 			return -EACCES;
 		{
@@ -635,7 +639,7 @@
            so we have this out of switch */
 	if (cmd == NCP_IOC_GETMOUNTUID) {
 		__kernel_uid_t uid = 0;
-		if ((permission(inode, MAY_READ, NULL) != 0)
+		if ((file_permission(filp, MAY_READ) != 0)
 		    && (current->uid != server->m.mounted_uid)) {
 			return -EACCES;
 		}
diff --git a/fs/open.c b/fs/open.c
index 6e81367..f53a5b9 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -240,7 +240,7 @@
 	if (!S_ISREG(inode->i_mode))
 		goto dput_and_out;
 
-	error = permission(inode,MAY_WRITE,&nd);
+	error = vfs_permission(&nd, MAY_WRITE);
 	if (error)
 		goto dput_and_out;
 
@@ -394,7 +394,7 @@
                         goto dput_and_out;
 
 		if (current->fsuid != inode->i_uid &&
-		    (error = permission(inode,MAY_WRITE,&nd)) != 0)
+		    (error = vfs_permission(&nd, MAY_WRITE)) != 0)
 			goto dput_and_out;
 	}
 	down(&inode->i_sem);
@@ -447,7 +447,7 @@
                         goto dput_and_out;
 
 		if (current->fsuid != inode->i_uid &&
-		    (error = permission(inode,MAY_WRITE,&nd)) != 0)
+		    (error = vfs_permission(&nd, MAY_WRITE)) != 0)
 			goto dput_and_out;
 	}
 	down(&inode->i_sem);
@@ -506,7 +506,7 @@
 
 	res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
 	if (!res) {
-		res = permission(nd.dentry->d_inode, mode, &nd);
+		res = vfs_permission(&nd, mode);
 		/* SuS v2 requires we report a read only fs too */
 		if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
 		   && !special_file(nd.dentry->d_inode->i_mode))
@@ -530,7 +530,7 @@
 	if (error)
 		goto out;
 
-	error = permission(nd.dentry->d_inode,MAY_EXEC,&nd);
+	error = vfs_permission(&nd, MAY_EXEC);
 	if (error)
 		goto dput_and_out;
 
@@ -563,7 +563,7 @@
 	if (!S_ISDIR(inode->i_mode))
 		goto out_putf;
 
-	error = permission(inode, MAY_EXEC, NULL);
+	error = file_permission(file, MAY_EXEC);
 	if (!error)
 		set_fs_pwd(current->fs, mnt, dentry);
 out_putf:
@@ -581,7 +581,7 @@
 	if (error)
 		goto out;
 
-	error = permission(nd.dentry->d_inode,MAY_EXEC,&nd);
+	error = vfs_permission(&nd, MAY_EXEC);
 	if (error)
 		goto dput_and_out;
 
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index c20babd..7892a86 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -251,12 +251,12 @@
 						       blocks_to_allocate,
 						       blocks_to_allocate);
 			if (res != CARRY_ON) {
-				res = -ENOSPC;
+				res = res == QUOTA_EXCEEDED ? -EDQUOT : -ENOSPC;
 				pathrelse(&path);
 				goto error_exit;
 			}
 		} else {
-			res = -ENOSPC;
+			res = res == QUOTA_EXCEEDED ? -EDQUOT : -ENOSPC;
 			pathrelse(&path);
 			goto error_exit;
 		}
diff --git a/fs/udf/file.c b/fs/udf/file.c
index bb40d63..01f520c 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -186,7 +186,7 @@
 {
 	int result = -EINVAL;
 
-	if ( permission(inode, MAY_READ, NULL) != 0 )
+	if ( file_permission(filp, MAY_READ) != 0 )
 	{
 		udf_debug("no permission to access inode %lu\n",
 						inode->i_ino);
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index 44fed10..d8e21ba 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -72,7 +72,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/proc_fs.h>
-#include <linux/version.h>
 #include <linux/sort.h>
 
 #include <asm/page.h>
diff --git a/fs/xfs/xfs.h b/fs/xfs/xfs.h
index 99b50d2..1a48dbb 100644
--- a/fs/xfs/xfs.h
+++ b/fs/xfs/xfs.h
@@ -17,12 +17,5 @@
  */
 #ifndef __XFS_H__
 #define __XFS_H__
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #include <linux-2.6/xfs_linux.h>
-#else
-#include <linux-2.4/xfs_linux.h>
-#endif
-
 #endif	/* __XFS_H__ */
diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h
index 5a5c7a6..864bf69 100644
--- a/fs/xfs/xfs_dmapi.h
+++ b/fs/xfs/xfs_dmapi.h
@@ -18,6 +18,7 @@
 #ifndef __XFS_DMAPI_H__
 #define __XFS_DMAPI_H__
 
+#include <linux/version.h>
 /*	Values used to define the on-disk version of dm_attrname_t. All
  *	on-disk attribute names start with the 8-byte string "SGI_DMI_".
  *
diff --git a/include/asm-alpha/ide.h b/include/asm-alpha/ide.h
index 68934a2..6126afe 100644
--- a/include/asm-alpha/ide.h
+++ b/include/asm-alpha/ide.h
@@ -15,10 +15,6 @@
 
 #include <linux/config.h>
 
-#ifndef MAX_HWIFS
-#define MAX_HWIFS	CONFIG_IDE_MAX_HWIFS
-#endif
-
 #define IDE_ARCH_OBSOLETE_DEFAULTS
 
 static inline int ide_default_irq(unsigned long base)
diff --git a/include/asm-arm/arch-ixp4xx/hardware.h b/include/asm-arm/arch-ixp4xx/hardware.h
index 55d85ee..cfb413c 100644
--- a/include/asm-arm/arch-ixp4xx/hardware.h
+++ b/include/asm-arm/arch-ixp4xx/hardware.h
@@ -44,5 +44,6 @@
 #include "ixdp425.h"
 #include "coyote.h"
 #include "prpmc1100.h"
+#include "nslu2.h"
 
 #endif  /* _ASM_ARCH_HARDWARE_H */
diff --git a/include/asm-arm/arch-ixp4xx/irqs.h b/include/asm-arm/arch-ixp4xx/irqs.h
index ca80828..2cf4930 100644
--- a/include/asm-arm/arch-ixp4xx/irqs.h
+++ b/include/asm-arm/arch-ixp4xx/irqs.h
@@ -93,4 +93,11 @@
 #define	IRQ_COYOTE_PCI_SLOT1	IRQ_IXP4XX_GPIO11
 #define	IRQ_COYOTE_IDE		IRQ_IXP4XX_GPIO5
 
+/*
+ * NSLU2 board IRQs
+ */
+#define        IRQ_NSLU2_PCI_INTA      IRQ_IXP4XX_GPIO11
+#define        IRQ_NSLU2_PCI_INTB      IRQ_IXP4XX_GPIO10
+#define        IRQ_NSLU2_PCI_INTC      IRQ_IXP4XX_GPIO9
+
 #endif
diff --git a/include/asm-arm/arch-ixp4xx/nslu2.h b/include/asm-arm/arch-ixp4xx/nslu2.h
new file mode 100644
index 0000000..b8b347a
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/nslu2.h
@@ -0,0 +1,96 @@
+/*
+ * include/asm-arm/arch-ixp4xx/nslu2.h
+ *
+ * NSLU2 platform specific definitions
+ *
+ * Author: Mark Rakes <mrakes AT mac.com>
+ * Maintainers: http://www.nslu2-linux.org
+ *
+ * based on ixdp425.h:
+ *	Copyright 2004 (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.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H__
+#error "Do not include this directly, instead #include <asm/hardware.h>"
+#endif
+
+#define NSLU2_FLASH_BASE	IXP4XX_EXP_BUS_CS0_BASE_PHYS
+#define NSLU2_FLASH_SIZE	IXP4XX_EXP_BUS_CSX_REGION_SIZE
+
+#define NSLU2_SDA_PIN		7
+#define NSLU2_SCL_PIN		6
+
+/*
+ * NSLU2 PCI IRQs
+ */
+#define NSLU2_PCI_MAX_DEV	3
+#define NSLU2_PCI_IRQ_LINES	3
+
+
+/* PCI controller GPIO to IRQ pin mappings */
+#define NSLU2_PCI_INTA_PIN	11
+#define NSLU2_PCI_INTB_PIN	10
+#define NSLU2_PCI_INTC_PIN	9
+#define NSLU2_PCI_INTD_PIN	8
+
+
+/* NSLU2 Timer */
+#define NSLU2_FREQ 66000000
+#define NSLU2_CLOCK_TICK_RATE (((NSLU2_FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ)
+#define NSLU2_CLOCK_TICKS_PER_USEC ((NSLU2_CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
+
+/* GPIO */
+
+#define NSLU2_GPIO0		0
+#define NSLU2_GPIO1		1
+#define NSLU2_GPIO2		2
+#define NSLU2_GPIO3		3
+#define NSLU2_GPIO4		4
+#define NSLU2_GPIO5		5
+#define NSLU2_GPIO6		6
+#define NSLU2_GPIO7		7
+#define NSLU2_GPIO8		8
+#define NSLU2_GPIO9		9
+#define NSLU2_GPIO10		10
+#define NSLU2_GPIO11		11
+#define NSLU2_GPIO12		12
+#define NSLU2_GPIO13		13
+#define NSLU2_GPIO14		14
+#define NSLU2_GPIO15		15
+
+/* Buttons */
+
+#define NSLU2_PB_GPIO		NSLU2_GPIO5
+#define NSLU2_PO_GPIO		NSLU2_GPIO8	/* power off */
+#define NSLU2_RB_GPIO		NSLU2_GPIO12
+
+#define NSLU2_PB_IRQ		IRQ_IXP4XX_GPIO5
+#define NSLU2_RB_IRQ		IRQ_IXP4XX_GPIO12
+
+#define NSLU2_PB_BM		(1L << NSLU2_PB_GPIO)
+#define NSLU2_PO_BM		(1L << NSLU2_PO_GPIO)
+#define NSLU2_RB_BM		(1L << NSLU2_RB_GPIO)
+
+/* Buzzer */
+
+#define NSLU2_GPIO_BUZZ		4
+#define NSLU2_BZ_BM		(1L << NSLU2_GPIO_BUZZ)
+/* LEDs */
+
+#define NSLU2_LED_RED		NSLU2_GPIO0
+#define NSLU2_LED_GRN		NSLU2_GPIO1
+
+#define NSLU2_LED_RED_BM	(1L << NSLU2_LED_RED)
+#define NSLU2_LED_GRN_BM	(1L << NSLU2_LED_GRN)
+
+#define NSLU2_LED_DISK1		NSLU2_GPIO2
+#define NSLU2_LED_DISK2		NSLU2_GPIO3
+
+#define NSLU2_LED_DISK1_BM	(1L << NSLU2_GPIO2)
+#define NSLU2_LED_DISK2_BM	(1L << NSLU2_GPIO3)
+
+
diff --git a/include/asm-arm/arch-omap/board-h4.h b/include/asm-arm/arch-omap/board-h4.h
index d64ee92..33ea29a 100644
--- a/include/asm-arm/arch-omap/board-h4.h
+++ b/include/asm-arm/arch-omap/board-h4.h
@@ -34,5 +34,11 @@
 #define OMAP24XX_ETHR_START             0x08000300
 #define OMAP24XX_ETHR_GPIO_IRQ		92
 
+#define H4_CS0_BASE		     0x04000000
+
+#define H4_CS0_BASE		     0x04000000
+
+#define H4_CS0_BASE		     0x04000000
+
 #endif /*  __ASM_ARCH_OMAP_H4_H */
 
diff --git a/include/asm-arm/arch-omap/board-innovator.h b/include/asm-arm/arch-omap/board-innovator.h
index 79574e0..b3cf334 100644
--- a/include/asm-arm/arch-omap/board-innovator.h
+++ b/include/asm-arm/arch-omap/board-innovator.h
@@ -26,7 +26,7 @@
 #ifndef __ASM_ARCH_OMAP_INNOVATOR_H
 #define __ASM_ARCH_OMAP_INNOVATOR_H
 
-#if defined (CONFIG_ARCH_OMAP1510)
+#if defined (CONFIG_ARCH_OMAP15XX)
 
 #ifndef OMAP_SDRAM_DEVICE
 #define OMAP_SDRAM_DEVICE			D256M_1X16_4B
@@ -44,7 +44,7 @@
 unsigned char fpga_read(int reg);
 #endif
 
-#endif /* CONFIG_ARCH_OMAP1510 */
+#endif /* CONFIG_ARCH_OMAP15XX */
 
 #if defined (CONFIG_ARCH_OMAP16XX)
 
diff --git a/include/asm-arm/arch-omap/clock.h b/include/asm-arm/arch-omap/clock.h
new file mode 100644
index 0000000..740c297
--- /dev/null
+++ b/include/asm-arm/arch-omap/clock.h
@@ -0,0 +1,91 @@
+/*
+ *  linux/include/asm-arm/arch-omap/clock.h
+ *
+ *  Copyright (C) 2004 - 2005 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *  Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, 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 __ARCH_ARM_OMAP_CLOCK_H
+#define __ARCH_ARM_OMAP_CLOCK_H
+
+struct module;
+
+struct clk {
+	struct list_head	node;
+	struct module		*owner;
+	const char		*name;
+	struct clk		*parent;
+	unsigned long		rate;
+	__u32			flags;
+	void __iomem		*enable_reg;
+	__u8			enable_bit;
+	__u8			rate_offset;
+	__u8			src_offset;
+	__s8			usecount;
+	void			(*recalc)(struct clk *);
+	int			(*set_rate)(struct clk *, unsigned long);
+	long			(*round_rate)(struct clk *, unsigned long);
+	void			(*init)(struct clk *);
+	int			(*enable)(struct clk *);
+	void			(*disable)(struct clk *);
+};
+
+struct clk_functions {
+	int		(*clk_enable)(struct clk *clk);
+	void		(*clk_disable)(struct clk *clk);
+	int		(*clk_use)(struct clk *clk);
+	void		(*clk_unuse)(struct clk *clk);
+	long		(*clk_round_rate)(struct clk *clk, unsigned long rate);
+	int		(*clk_set_rate)(struct clk *clk, unsigned long rate);
+	int		(*clk_set_parent)(struct clk *clk, struct clk *parent);
+	struct clk *	(*clk_get_parent)(struct clk *clk);
+	void		(*clk_allow_idle)(struct clk *clk);
+	void		(*clk_deny_idle)(struct clk *clk);
+};
+
+extern unsigned int mpurate;
+extern struct list_head clocks;
+extern spinlock_t clockfw_lock;
+
+extern int clk_init(struct clk_functions * custom_clocks);
+extern int clk_register(struct clk *clk);
+extern void clk_unregister(struct clk *clk);
+extern void propagate_rate(struct clk *clk);
+extern void followparent_recalc(struct clk * clk);
+extern void clk_allow_idle(struct clk *clk);
+extern void clk_deny_idle(struct clk *clk);
+
+/* Clock flags */
+#define RATE_CKCTL		(1 << 0)	/* Main fixed ratio clocks */
+#define RATE_FIXED		(1 << 1)	/* Fixed clock rate */
+#define RATE_PROPAGATES		(1 << 2)	/* Program children too */
+#define VIRTUAL_CLOCK		(1 << 3)	/* Composite clock from table */
+#define ALWAYS_ENABLED		(1 << 4)	/* Clock cannot be disabled */
+#define ENABLE_REG_32BIT	(1 << 5)	/* Use 32-bit access */
+#define VIRTUAL_IO_ADDRESS	(1 << 6)	/* Clock in virtual address */
+#define CLOCK_IDLE_CONTROL	(1 << 7)
+#define CLOCK_NO_IDLE_PARENT	(1 << 8)
+#define DELAYED_APP		(1 << 9)	/* Delay application of clock */
+#define CONFIG_PARTICIPANT	(1 << 10)	/* Fundamental clock */
+#define CM_MPU_SEL1		(1 << 11)	/* Domain divider/source */
+#define CM_DSP_SEL1		(1 << 12)
+#define CM_GFX_SEL1		(1 << 13)
+#define CM_MODEM_SEL1		(1 << 14)
+#define CM_CORE_SEL1		(1 << 15)	/* Sets divider for many */
+#define CM_CORE_SEL2		(1 << 16)	/* sets parent for GPT */
+#define CM_WKUP_SEL1		(1 << 17)
+#define CM_PLL_SEL1		(1 << 18)
+#define CM_PLL_SEL2		(1 << 19)
+#define CM_SYSCLKOUT_SEL1	(1 << 20)
+#define CLOCK_IN_OMAP730	(1 << 21)
+#define CLOCK_IN_OMAP1510	(1 << 22)
+#define CLOCK_IN_OMAP16XX	(1 << 23)
+#define CLOCK_IN_OMAP242X	(1 << 24)
+#define CLOCK_IN_OMAP243X	(1 << 25)
+
+#endif
diff --git a/include/asm-arm/arch-omap/common.h b/include/asm-arm/arch-omap/common.h
index 2a676b4..08d58ab 100644
--- a/include/asm-arm/arch-omap/common.h
+++ b/include/asm-arm/arch-omap/common.h
@@ -31,6 +31,6 @@
 
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
-extern void omap_serial_init(int ports[]);
+extern void omap_serial_init(void);
 
 #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
diff --git a/include/asm-arm/arch-omap/cpu.h b/include/asm-arm/arch-omap/cpu.h
index 1119e2b..ec7eb67 100644
--- a/include/asm-arm/arch-omap/cpu.h
+++ b/include/asm-arm/arch-omap/cpu.h
@@ -28,12 +28,7 @@
 
 extern unsigned int system_rev;
 
-#define OMAP_DIE_ID_0		0xfffe1800
-#define OMAP_DIE_ID_1		0xfffe1804
-#define OMAP_PRODUCTION_ID_0	0xfffe2000
-#define OMAP_PRODUCTION_ID_1	0xfffe2004
-#define OMAP32_ID_0		0xfffed400
-#define OMAP32_ID_1		0xfffed404
+#define omap2_cpu_rev()		((system_rev >> 8) & 0x0f)
 
 /*
  * Test if multicore OMAP support is needed
@@ -50,7 +45,7 @@
 #  define OMAP_NAME omap730
 # endif
 #endif
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 # ifdef OMAP_NAME
 #  undef  MULTI_OMAP1
 #  define MULTI_OMAP1
@@ -79,9 +74,11 @@
  * Macros to group OMAP into cpu classes.
  * These can be used in most places.
  * cpu_is_omap7xx():	True for OMAP730
- * cpu_is_omap15xx():	True for OMAP1510 and OMAP5910
+ * cpu_is_omap15xx():	True for OMAP1510, OMAP5910 and OMAP310
  * cpu_is_omap16xx():	True for OMAP1610, OMAP5912 and OMAP1710
- * cpu_is_omap24xx():	True for OMAP2420
+ * cpu_is_omap24xx():	True for OMAP2420, OMAP2422, OMAP2423, OMAP2430
+ * cpu_is_omap242x():	True for OMAP2420, OMAP2422, OMAP2423
+ * cpu_is_omap243x():	True for OMAP2430
  */
 #define GET_OMAP_CLASS	(system_rev & 0xff)
 
@@ -91,22 +88,35 @@
 	return (GET_OMAP_CLASS == (id)) ? 1 : 0;	\
 }
 
+#define GET_OMAP_SUBCLASS	((system_rev >> 20) & 0x0fff)
+
+#define IS_OMAP_SUBCLASS(subclass, id)			\
+static inline int is_omap ##subclass (void)		\
+{							\
+	return (GET_OMAP_SUBCLASS == (id)) ? 1 : 0;	\
+}
+
 IS_OMAP_CLASS(7xx, 0x07)
 IS_OMAP_CLASS(15xx, 0x15)
 IS_OMAP_CLASS(16xx, 0x16)
 IS_OMAP_CLASS(24xx, 0x24)
 
+IS_OMAP_SUBCLASS(242x, 0x242)
+IS_OMAP_SUBCLASS(243x, 0x243)
+
 #define cpu_is_omap7xx()		0
 #define cpu_is_omap15xx()		0
 #define cpu_is_omap16xx()		0
 #define cpu_is_omap24xx()		0
+#define cpu_is_omap242x()		0
+#define cpu_is_omap243x()		0
 
 #if defined(MULTI_OMAP1)
 # if defined(CONFIG_ARCH_OMAP730)
 #  undef  cpu_is_omap7xx
 #  define cpu_is_omap7xx()		is_omap7xx()
 # endif
-# if defined(CONFIG_ARCH_OMAP1510)
+# if defined(CONFIG_ARCH_OMAP15XX)
 #  undef  cpu_is_omap15xx
 #  define cpu_is_omap15xx()		is_omap15xx()
 # endif
@@ -119,7 +129,7 @@
 #  undef  cpu_is_omap7xx
 #  define cpu_is_omap7xx()		1
 # endif
-# if defined(CONFIG_ARCH_OMAP1510)
+# if defined(CONFIG_ARCH_OMAP15XX)
 #  undef  cpu_is_omap15xx
 #  define cpu_is_omap15xx()		1
 # endif
@@ -129,13 +139,18 @@
 # endif
 # if defined(CONFIG_ARCH_OMAP24XX)
 #  undef  cpu_is_omap24xx
+#  undef  cpu_is_omap242x
+#  undef  cpu_is_omap243x
 #  define cpu_is_omap24xx()		1
+#  define cpu_is_omap242x()		is_omap242x()
+#  define cpu_is_omap243x()		is_omap243x()
 # endif
 #endif
 
 /*
  * Macros to detect individual cpu types.
  * These are only rarely needed.
+ * cpu_is_omap330():	True for OMAP330
  * cpu_is_omap730():	True for OMAP730
  * cpu_is_omap1510():	True for OMAP1510
  * cpu_is_omap1610():	True for OMAP1610
@@ -144,6 +159,9 @@
  * cpu_is_omap1621():	True for OMAP1621
  * cpu_is_omap1710():	True for OMAP1710
  * cpu_is_omap2420():	True for OMAP2420
+ * cpu_is_omap2422():	True for OMAP2422
+ * cpu_is_omap2423():	True for OMAP2423
+ * cpu_is_omap2430():	True for OMAP2430
  */
 #define GET_OMAP_TYPE	((system_rev >> 16) & 0xffff)
 
@@ -153,6 +171,7 @@
 	return (GET_OMAP_TYPE == (id)) ? 1 : 0;		\
 }
 
+IS_OMAP_TYPE(310, 0x0310)
 IS_OMAP_TYPE(730, 0x0730)
 IS_OMAP_TYPE(1510, 0x1510)
 IS_OMAP_TYPE(1610, 0x1610)
@@ -161,7 +180,11 @@
 IS_OMAP_TYPE(1621, 0x1621)
 IS_OMAP_TYPE(1710, 0x1710)
 IS_OMAP_TYPE(2420, 0x2420)
+IS_OMAP_TYPE(2422, 0x2422)
+IS_OMAP_TYPE(2423, 0x2423)
+IS_OMAP_TYPE(2430, 0x2430)
 
+#define cpu_is_omap310()		0
 #define cpu_is_omap730()		0
 #define cpu_is_omap1510()		0
 #define cpu_is_omap1610()		0
@@ -170,31 +193,33 @@
 #define cpu_is_omap1621()		0
 #define cpu_is_omap1710()		0
 #define cpu_is_omap2420()		0
+#define cpu_is_omap2422()		0
+#define cpu_is_omap2423()		0
+#define cpu_is_omap2430()		0
 
 #if defined(MULTI_OMAP1)
 # if defined(CONFIG_ARCH_OMAP730)
 #  undef  cpu_is_omap730
 #  define cpu_is_omap730()		is_omap730()
 # endif
-# if defined(CONFIG_ARCH_OMAP1510)
-#  undef  cpu_is_omap1510
-#  define cpu_is_omap1510()		is_omap1510()
-# endif
 #else
 # if defined(CONFIG_ARCH_OMAP730)
 #  undef  cpu_is_omap730
 #  define cpu_is_omap730()		1
 # endif
-# if defined(CONFIG_ARCH_OMAP1510)
-#  undef  cpu_is_omap1510
-#  define cpu_is_omap1510()		1
-# endif
 #endif
 
 /*
  * Whether we have MULTI_OMAP1 or not, we still need to distinguish
- * between 1611B/5912 and 1710.
+ * between 330 vs. 1510 and 1611B/5912 vs. 1710.
  */
+#if defined(CONFIG_ARCH_OMAP15XX)
+# undef  cpu_is_omap310
+# undef  cpu_is_omap1510
+# define cpu_is_omap310()		is_omap310()
+# define cpu_is_omap1510()		is_omap1510()
+#endif
+
 #if defined(CONFIG_ARCH_OMAP16XX)
 # undef  cpu_is_omap1610
 # undef  cpu_is_omap1611
@@ -208,9 +233,20 @@
 # define cpu_is_omap1710()		is_omap1710()
 #endif
 
-#if defined(CONFIG_ARCH_OMAP2420)
-#  undef  cpu_is_omap2420
-#  define cpu_is_omap2420()		1
+#if defined(CONFIG_ARCH_OMAP24XX)
+# undef  cpu_is_omap2420
+# undef  cpu_is_omap2422
+# undef  cpu_is_omap2423
+# undef  cpu_is_omap2430
+# define cpu_is_omap2420()		is_omap2420()
+# define cpu_is_omap2422()		is_omap2422()
+# define cpu_is_omap2423()		is_omap2423()
+# define cpu_is_omap2430()		is_omap2430()
 #endif
 
+/* Macros to detect if we have OMAP1 or OMAP2 */
+#define cpu_class_is_omap1()	(cpu_is_omap730() || cpu_is_omap15xx() || \
+				cpu_is_omap16xx())
+#define cpu_class_is_omap2()	cpu_is_omap24xx()
+
 #endif
diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h
index 04ebef5..ccbcb58 100644
--- a/include/asm-arm/arch-omap/dma.h
+++ b/include/asm-arm/arch-omap/dma.h
@@ -22,9 +22,109 @@
 #define __ASM_ARCH_DMA_H
 
 #define MAX_DMA_ADDRESS			0xffffffff
+#define MAX_DMA_CHANNELS		0
+
+/* Hardware registers for omap1 */
+#define OMAP_DMA_BASE			(0xfffed800)
+#define OMAP_DMA_GCR			(OMAP_DMA_BASE + 0x400)
+#define OMAP_DMA_GSCR			(OMAP_DMA_BASE + 0x404)
+#define OMAP_DMA_GRST			(OMAP_DMA_BASE + 0x408)
+#define OMAP_DMA_HW_ID			(OMAP_DMA_BASE + 0x442)
+#define OMAP_DMA_PCH2_ID		(OMAP_DMA_BASE + 0x444)
+#define OMAP_DMA_PCH0_ID		(OMAP_DMA_BASE + 0x446)
+#define OMAP_DMA_PCH1_ID		(OMAP_DMA_BASE + 0x448)
+#define OMAP_DMA_PCHG_ID		(OMAP_DMA_BASE + 0x44a)
+#define OMAP_DMA_PCHD_ID		(OMAP_DMA_BASE + 0x44c)
+#define OMAP_DMA_CAPS_0_U		(OMAP_DMA_BASE + 0x44e)
+#define OMAP_DMA_CAPS_0_L		(OMAP_DMA_BASE + 0x450)
+#define OMAP_DMA_CAPS_1_U		(OMAP_DMA_BASE + 0x452)
+#define OMAP_DMA_CAPS_1_L		(OMAP_DMA_BASE + 0x454)
+#define OMAP_DMA_CAPS_2			(OMAP_DMA_BASE + 0x456)
+#define OMAP_DMA_CAPS_3			(OMAP_DMA_BASE + 0x458)
+#define OMAP_DMA_CAPS_4			(OMAP_DMA_BASE + 0x45a)
+#define OMAP_DMA_PCH2_SR		(OMAP_DMA_BASE + 0x460)
+#define OMAP_DMA_PCH0_SR		(OMAP_DMA_BASE + 0x480)
+#define OMAP_DMA_PCH1_SR		(OMAP_DMA_BASE + 0x482)
+#define OMAP_DMA_PCHD_SR		(OMAP_DMA_BASE + 0x4c0)
+
+/* Hardware registers for omap2 */
+#define OMAP24XX_DMA_BASE		(L4_24XX_BASE + 0x56000)
+#define OMAP_DMA4_REVISION		(OMAP24XX_DMA_BASE + 0x00)
+#define OMAP_DMA4_GCR_REG		(OMAP24XX_DMA_BASE + 0x78)
+#define OMAP_DMA4_IRQSTATUS_L0		(OMAP24XX_DMA_BASE + 0x08)
+#define OMAP_DMA4_IRQSTATUS_L1		(OMAP24XX_DMA_BASE + 0x0c)
+#define OMAP_DMA4_IRQSTATUS_L2		(OMAP24XX_DMA_BASE + 0x10)
+#define OMAP_DMA4_IRQSTATUS_L3		(OMAP24XX_DMA_BASE + 0x14)
+#define OMAP_DMA4_IRQENABLE_L0		(OMAP24XX_DMA_BASE + 0x18)
+#define OMAP_DMA4_IRQENABLE_L1		(OMAP24XX_DMA_BASE + 0x1c)
+#define OMAP_DMA4_IRQENABLE_L2		(OMAP24XX_DMA_BASE + 0x20)
+#define OMAP_DMA4_IRQENABLE_L3		(OMAP24XX_DMA_BASE + 0x24)
+#define OMAP_DMA4_SYSSTATUS		(OMAP24XX_DMA_BASE + 0x28)
+#define OMAP_DMA4_CAPS_0		(OMAP24XX_DMA_BASE + 0x64)
+#define OMAP_DMA4_CAPS_2		(OMAP24XX_DMA_BASE + 0x6c)
+#define OMAP_DMA4_CAPS_3		(OMAP24XX_DMA_BASE + 0x70)
+#define OMAP_DMA4_CAPS_4		(OMAP24XX_DMA_BASE + 0x74)
+
+#ifdef CONFIG_ARCH_OMAP1
 
 #define OMAP_LOGICAL_DMA_CH_COUNT	17
 
+/* Common channel specific registers for omap1 */
+#define OMAP_DMA_CSDP_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x00)
+#define OMAP_DMA_CCR_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x02)
+#define OMAP_DMA_CICR_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x04)
+#define OMAP_DMA_CSR_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x06)
+#define OMAP_DMA_CEN_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x10)
+#define OMAP_DMA_CFN_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x12)
+#define OMAP_DMA_CSFI_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x14)
+#define OMAP_DMA_CSEI_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x16)
+#define OMAP_DMA_CSAC_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x18)
+#define OMAP_DMA_CDAC_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x1a)
+#define OMAP_DMA_CDEI_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x1c)
+#define OMAP_DMA_CDFI_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x1e)
+#define OMAP_DMA_CLNK_CTRL_REG(n)	__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x28)
+
+#else
+
+#define OMAP_LOGICAL_DMA_CH_COUNT	32	/* REVISIT: Is this 32 + 2? */
+
+/* Common channel specific registers for omap2 */
+#define OMAP_DMA_CCR_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x80)
+#define OMAP_DMA_CLNK_CTRL_REG(n)	__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x84)
+#define OMAP_DMA_CICR_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x88)
+#define OMAP_DMA_CSR_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x8c)
+#define OMAP_DMA_CSDP_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x90)
+#define OMAP_DMA_CEN_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x94)
+#define OMAP_DMA_CFN_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x98)
+#define OMAP_DMA_CSEI_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xa4)
+#define OMAP_DMA_CSFI_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xa8)
+#define OMAP_DMA_CDEI_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xac)
+#define OMAP_DMA_CDFI_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xb0)
+#define OMAP_DMA_CSAC_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xb4)
+#define OMAP_DMA_CDAC_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xb8)
+
+#endif
+
+/* Channel specific registers only on omap1 */
+#define OMAP1_DMA_CSSA_L_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x08)
+#define OMAP1_DMA_CSSA_U_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x0a)
+#define OMAP1_DMA_CDSA_L_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x0c)
+#define OMAP1_DMA_CDSA_U_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x0e)
+#define OMAP1_DMA_COLOR_L_REG(n)	__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x20)
+#define OMAP1_DMA_CCR2_REG(n)		__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x24)
+#define OMAP1_DMA_COLOR_U_REG(n)	__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x22)
+#define OMAP1_DMA_LCH_CTRL_REG(n)	__REG16(OMAP_DMA_BASE + 0x40 * (n) + 0x2a)
+
+/* Channel specific registers only on omap2 */
+#define OMAP2_DMA_CSSA_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0x9c)
+#define OMAP2_DMA_CDSA_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xa0)
+#define OMAP2_DMA_CCEN_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xbc)
+#define OMAP2_DMA_CCFN_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xc0)
+#define OMAP2_DMA_COLOR_REG(n)		__REG32(OMAP24XX_DMA_BASE + 0x60 * (n) + 0xc4)
+
+/*----------------------------------------------------------------------------*/
+
+/* DMA channels for omap1 */
 #define OMAP_DMA_NO_DEVICE		0
 #define OMAP_DMA_MCSI1_TX		1
 #define OMAP_DMA_MCSI1_RX		2
@@ -85,29 +185,72 @@
 #define OMAP_DMA_MMC2_RX		55
 #define OMAP_DMA_CRYPTO_DES_OUT		56
 
+/* DMA channels for 24xx */
+#define OMAP24XX_DMA_NO_DEVICE		0
+#define OMAP24XX_DMA_XTI_DMA		1	/* S_DMA_0 */
+#define OMAP24XX_DMA_EXT_NDMA_REQ0	2	/* S_DMA_1 */
+#define OMAP24XX_DMA_EXT_NDMA_REQ1	3	/* S_DMA_2 */
+#define OMAP24XX_DMA_GPMC		4	/* S_DMA_3 */
+#define OMAP24XX_DMA_GFX		5	/* S_DMA_4 */
+#define OMAP24XX_DMA_DSS		6	/* S_DMA_5 */
+#define OMAP24XX_DMA_VLYNQ_TX		7	/* S_DMA_6 */
+#define OMAP24XX_DMA_CWT		8	/* S_DMA_7 */
+#define OMAP24XX_DMA_AES_TX		9	/* S_DMA_8 */
+#define OMAP24XX_DMA_AES_RX		10	/* S_DMA_9 */
+#define OMAP24XX_DMA_DES_TX		11	/* S_DMA_10 */
+#define OMAP24XX_DMA_DES_RX		12	/* S_DMA_11 */
+#define OMAP24XX_DMA_SHA1MD5_RX		13	/* S_DMA_12 */
 
-#define OMAP_DMA_BASE			(0xfffed800)
-#define OMAP_DMA_GCR			(OMAP_DMA_BASE + 0x400)
-#define OMAP_DMA_GSCR			(OMAP_DMA_BASE + 0x404)
-#define OMAP_DMA_GRST			(OMAP_DMA_BASE + 0x408)
-#define OMAP_DMA_HW_ID			(OMAP_DMA_BASE + 0x442)
-#define OMAP_DMA_PCH2_ID		(OMAP_DMA_BASE + 0x444)
-#define OMAP_DMA_PCH0_ID		(OMAP_DMA_BASE + 0x446)
-#define OMAP_DMA_PCH1_ID		(OMAP_DMA_BASE + 0x448)
-#define OMAP_DMA_PCHG_ID		(OMAP_DMA_BASE + 0x44a)
-#define OMAP_DMA_PCHD_ID		(OMAP_DMA_BASE + 0x44c)
-#define OMAP_DMA_CAPS_0_U		(OMAP_DMA_BASE + 0x44e)
-#define OMAP_DMA_CAPS_0_L		(OMAP_DMA_BASE + 0x450)
-#define OMAP_DMA_CAPS_1_U		(OMAP_DMA_BASE + 0x452)
-#define OMAP_DMA_CAPS_1_L		(OMAP_DMA_BASE + 0x454)
-#define OMAP_DMA_CAPS_2			(OMAP_DMA_BASE + 0x456)
-#define OMAP_DMA_CAPS_3			(OMAP_DMA_BASE + 0x458)
-#define OMAP_DMA_CAPS_4			(OMAP_DMA_BASE + 0x45a)
-#define OMAP_DMA_PCH2_SR		(OMAP_DMA_BASE + 0x460)
-#define OMAP_DMA_PCH0_SR		(OMAP_DMA_BASE + 0x480)
-#define OMAP_DMA_PCH1_SR		(OMAP_DMA_BASE + 0x482)
-#define OMAP_DMA_PCHD_SR		(OMAP_DMA_BASE + 0x4c0)
+#define OMAP24XX_DMA_EAC_AC_RD		17	/* S_DMA_16 */
+#define OMAP24XX_DMA_EAC_AC_WR		18	/* S_DMA_17 */
+#define OMAP24XX_DMA_EAC_MD_UL_RD	19	/* S_DMA_18 */
+#define OMAP24XX_DMA_EAC_MD_UL_WR	20	/* S_DMA_19 */
+#define OMAP24XX_DMA_EAC_MD_DL_RD	21	/* S_DMA_20 */
+#define OMAP24XX_DMA_EAC_MD_DL_WR	22	/* S_DMA_21 */
+#define OMAP24XX_DMA_EAC_BT_UL_RD	23	/* S_DMA_22 */
+#define OMAP24XX_DMA_EAC_BT_UL_WR	24	/* S_DMA_23 */
+#define OMAP24XX_DMA_EAC_BT_DL_RD	25	/* S_DMA_24 */
+#define OMAP24XX_DMA_EAC_BT_DL_WR	26	/* S_DMA_25 */
+#define OMAP24XX_DMA_I2C1_TX		27	/* S_DMA_26 */
+#define OMAP24XX_DMA_I2C1_RX		28	/* S_DMA_27 */
+#define OMAP24XX_DMA_I2C2_TX		29	/* S_DMA_28 */
+#define OMAP24XX_DMA_I2C2_RX		30	/* S_DMA_29 */
+#define OMAP24XX_DMA_MCBSP1_TX		31	/* SDMA_30 */
+#define OMAP24XX_DMA_MCBSP1_RX		32	/* SDMA_31 */
+#define OMAP24XX_DMA_MCBSP2_TX		33	/* SDMA_32 */
+#define OMAP24XX_DMA_MCBSP2_RX		34	/* SDMA_33 */
+#define OMAP24XX_DMA_SPI1_TX0		35	/* SDMA_34 */
+#define OMAP24XX_DMA_SPI1_RX0		36	/* SDMA_35 */
+#define OMAP24XX_DMA_SPI1_TX1		37	/* SDMA_36 */
+#define OMAP24XX_DMA_SPI1_RX1		38	/* SDMA_37 */
+#define OMAP24XX_DMA_SPI1_TX2		39	/* SDMA_38 */
+#define OMAP24XX_DMA_SPI1_RX2		40	/* SDMA_39 */
+#define OMAP24XX_DMA_SPI1_TX3		41	/* SDMA_40 */
+#define OMAP24XX_DMA_SPI1_RX3		42	/* SDMA_41 */
+#define OMAP24XX_DMA_SPI2_TX0		43	/* SDMA_42 */
+#define OMAP24XX_DMA_SPI2_RX0		44	/* SDMA_43 */
+#define OMAP24XX_DMA_SPI2_TX1		45	/* SDMA_44 */
+#define OMAP24XX_DMA_SPI2_RX1		46	/* SDMA_45 */
 
+#define OMAP24XX_DMA_UART1_TX		49	/* SDMA_48 */
+#define OMAP24XX_DMA_UART1_RX		50	/* SDMA_49 */
+#define OMAP24XX_DMA_UART2_TX		51	/* SDMA_50 */
+#define OMAP24XX_DMA_UART2_RX		52	/* SDMA_51 */
+#define OMAP24XX_DMA_UART3_TX		53	/* SDMA_52 */
+#define OMAP24XX_DMA_UART3_RX		54	/* SDMA_53 */
+#define OMAP24XX_DMA_USB_W2FC_TX0	55	/* SDMA_54 */
+#define OMAP24XX_DMA_USB_W2FC_RX0	56	/* SDMA_55 */
+#define OMAP24XX_DMA_USB_W2FC_TX1	57	/* SDMA_56 */
+#define OMAP24XX_DMA_USB_W2FC_RX1	58	/* SDMA_57 */
+#define OMAP24XX_DMA_USB_W2FC_TX2	59	/* SDMA_58 */
+#define OMAP24XX_DMA_USB_W2FC_RX2	60	/* SDMA_59 */
+#define OMAP24XX_DMA_MMC1_TX		61	/* SDMA_60 */
+#define OMAP24XX_DMA_MMC1_RX		62	/* SDMA_61 */
+#define OMAP24XX_DMA_MS			63	/* SDMA_62 */
+
+/*----------------------------------------------------------------------------*/
+
+/* Hardware registers for LCD DMA */
 #define OMAP1510_DMA_LCD_BASE		(0xfffedb00)
 #define OMAP1510_DMA_LCD_CTRL		(OMAP1510_DMA_LCD_BASE + 0x00)
 #define OMAP1510_DMA_LCD_TOP_F1_L	(OMAP1510_DMA_LCD_BASE + 0x02)
@@ -116,7 +259,7 @@
 #define OMAP1510_DMA_LCD_BOT_F1_U	(OMAP1510_DMA_LCD_BASE + 0x08)
 
 #define OMAP1610_DMA_LCD_BASE		(0xfffee300)
-#define OMAP1610_DMA_LCD_CSDP      	(OMAP1610_DMA_LCD_BASE + 0xc0)
+#define OMAP1610_DMA_LCD_CSDP		(OMAP1610_DMA_LCD_BASE + 0xc0)
 #define OMAP1610_DMA_LCD_CCR		(OMAP1610_DMA_LCD_BASE + 0xc2)
 #define OMAP1610_DMA_LCD_CTRL		(OMAP1610_DMA_LCD_BASE + 0xc4)
 #define OMAP1610_DMA_LCD_TOP_B1_L	(OMAP1610_DMA_LCD_BASE + 0xc8)
@@ -134,37 +277,18 @@
 #define OMAP1610_DMA_LCD_LCH_CTRL	(OMAP1610_DMA_LCD_BASE + 0xea)
 #define OMAP1610_DMA_LCD_SRC_FI_B1_U	(OMAP1610_DMA_LCD_BASE + 0xf4)
 
-
-/* Every LCh has its own set of the registers below */
-#define OMAP_DMA_CSDP(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x00)
-#define OMAP_DMA_CCR(n)			(OMAP_DMA_BASE + 0x40 * (n) + 0x02)
-#define OMAP_DMA_CICR(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x04)
-#define OMAP_DMA_CSR(n)			(OMAP_DMA_BASE + 0x40 * (n) + 0x06)
-#define OMAP_DMA_CSSA_L(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x08)
-#define OMAP_DMA_CSSA_U(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x0a)
-#define OMAP_DMA_CDSA_L(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x0c)
-#define OMAP_DMA_CDSA_U(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x0e)
-#define OMAP_DMA_CEN(n)			(OMAP_DMA_BASE + 0x40 * (n) + 0x10)
-#define OMAP_DMA_CFN(n)			(OMAP_DMA_BASE + 0x40 * (n) + 0x12)
-#define OMAP_DMA_CSFI(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x14)
-#define OMAP_DMA_CSEI(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x16)
-#define OMAP_DMA_CSAC(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x18)
-#define OMAP_DMA_CDAC(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x1a)
-#define OMAP_DMA_CDEI(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x1c)
-#define OMAP_DMA_CDFI(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x1e)
-#define OMAP_DMA_COLOR_L(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x20)
-#define OMAP_DMA_COLOR_U(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x22)
-#define OMAP_DMA_CCR2(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x24)
-#define OMAP_DMA_CLNK_CTRL(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x28)
-#define OMAP_DMA_LCH_CTRL(n)		(OMAP_DMA_BASE + 0x40 * (n) + 0x2a)
-
-#define OMAP_DMA_TOUT_IRQ		(1 << 0)
+#define OMAP_DMA_TOUT_IRQ		(1 << 0)	/* Only on omap1 */
 #define OMAP_DMA_DROP_IRQ		(1 << 1)
 #define OMAP_DMA_HALF_IRQ		(1 << 2)
 #define OMAP_DMA_FRAME_IRQ		(1 << 3)
 #define OMAP_DMA_LAST_IRQ		(1 << 4)
 #define OMAP_DMA_BLOCK_IRQ		(1 << 5)
-#define OMAP_DMA_SYNC_IRQ		(1 << 6)
+#define OMAP1_DMA_SYNC_IRQ		(1 << 6)
+#define OMAP2_DMA_PKT_IRQ		(1 << 7)
+#define OMAP2_DMA_TRANS_ERR_IRQ		(1 << 8)
+#define OMAP2_DMA_SECURE_ERR_IRQ	(1 << 9)
+#define OMAP2_DMA_SUPERVISOR_ERR_IRQ	(1 << 10)
+#define OMAP2_DMA_MISALIGNED_ERR_IRQ	(1 << 11)
 
 #define OMAP_DMA_DATA_TYPE_S8		0x00
 #define OMAP_DMA_DATA_TYPE_S16		0x01
@@ -194,6 +318,7 @@
 	OMAP_LCD_DMA_B2_BOTTOM
 };
 
+/* REVISIT: Check if BURST_4 is really 1 (or 2) */
 enum omap_dma_burst_mode {
 	OMAP_DMA_DATA_BURST_DIS = 0,
 	OMAP_DMA_DATA_BURST_4,
@@ -206,6 +331,31 @@
 	OMAP_DMA_TRANSPARENT_COPY
 };
 
+struct omap_dma_channel_params {
+	int data_type;		/* data type 8,16,32 */
+	int elem_count;		/* number of elements in a frame */
+	int frame_count;	/* number of frames in a element */
+
+	int src_port;		/* Only on OMAP1 REVISIT: Is this needed? */
+	int src_amode;		/* constant , post increment, indexed , double indexed */
+	int src_start;		/* source address : physical */
+	int src_ei;		/* source element index */
+	int src_fi;		/* source frame index */
+
+	int dst_port;		/* Only on OMAP1 REVISIT: Is this needed? */
+	int dst_amode;		/* constant , post increment, indexed , double indexed */
+	int dst_start;		/* source address : physical */
+	int dst_ei;		/* source element index */
+	int dst_fi;		/* source frame index */
+
+	int trigger;		/* trigger attached if the channel is synchronized */
+	int sync_mode;		/* sycn on element, frame , block or packet */
+	int src_or_dst_synch;	/* source synch(1) or destination synch(0) */
+
+	int ie;			/* interrupt enabled */
+};
+
+
 extern void omap_set_dma_priority(int dst_port, int priority);
 extern int omap_request_dma(int dev_id, const char *dev_name,
 			    void (* callback)(int lch, u16 ch_status, void *data),
@@ -217,24 +367,30 @@
 extern void omap_stop_dma(int lch);
 extern void omap_set_dma_transfer_params(int lch, int data_type,
 					 int elem_count, int frame_count,
-					 int sync_mode);
+					 int sync_mode,
+					 int dma_trigger, int src_or_dst_synch);
 extern void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode,
 				    u32 color);
 
 extern void omap_set_dma_src_params(int lch, int src_port, int src_amode,
-				    unsigned long src_start);
+				    unsigned long src_start,
+				    int src_ei, int src_fi);
 extern void omap_set_dma_src_index(int lch, int eidx, int fidx);
 extern void omap_set_dma_src_data_pack(int lch, int enable);
 extern void omap_set_dma_src_burst_mode(int lch,
 					enum omap_dma_burst_mode burst_mode);
 
 extern void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
-				     unsigned long dest_start);
+				     unsigned long dest_start,
+				     int dst_ei, int dst_fi);
 extern void omap_set_dma_dest_index(int lch, int eidx, int fidx);
 extern void omap_set_dma_dest_data_pack(int lch, int enable);
 extern void omap_set_dma_dest_burst_mode(int lch,
 					 enum omap_dma_burst_mode burst_mode);
 
+extern void omap_set_dma_params(int lch,
+				struct omap_dma_channel_params * params);
+
 extern void omap_dma_link_lch (int lch_head, int lch_queue);
 extern void omap_dma_unlink_lch (int lch_head, int lch_queue);
 
@@ -244,9 +400,6 @@
 extern void omap_clear_dma(int lch);
 extern int omap_dma_running(void);
 
-/* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */
-extern int omap_dma_in_1510_mode(void);
-
 /* LCD DMA functions */
 extern int omap_request_lcd_dma(void (* callback)(u16 status, void *data),
 				void *data);
diff --git a/include/asm-arm/arch-omap/entry-macro.S b/include/asm-arm/arch-omap/entry-macro.S
index 0d29b9c..f8814a8 100644
--- a/include/asm-arm/arch-omap/entry-macro.S
+++ b/include/asm-arm/arch-omap/entry-macro.S
@@ -10,6 +10,20 @@
 
 #if defined(CONFIG_ARCH_OMAP1)
 
+#if defined(CONFIG_ARCH_OMAP730) && \
+	(defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX))
+#error "FIXME: OMAP730 doesn't support multiple-OMAP"
+#elif defined(CONFIG_ARCH_OMAP730)
+#define INT_IH2_IRQ		INT_730_IH2_IRQ
+#elif defined(CONFIG_ARCH_OMAP15XX)
+#define INT_IH2_IRQ		INT_1510_IH2_IRQ
+#elif defined(CONFIG_ARCH_OMAP16XX)
+#define INT_IH2_IRQ		INT_1610_IH2_IRQ
+#else
+#warning "IH2 IRQ defaulted"
+#define INT_IH2_IRQ		INT_1510_IH2_IRQ
+#endif
+
  		.macro	disable_fiq
 		.endm
 
diff --git a/include/asm-arm/arch-omap/fpga.h b/include/asm-arm/arch-omap/fpga.h
index 676807d..6a883e0 100644
--- a/include/asm-arm/arch-omap/fpga.h
+++ b/include/asm-arm/arch-omap/fpga.h
@@ -19,7 +19,7 @@
 #ifndef __ASM_ARCH_OMAP_FPGA_H
 #define __ASM_ARCH_OMAP_FPGA_H
 
-#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP1510)
+#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX)
 extern void omap1510_fpga_init_irq(void);
 #else
 #define omap1510_fpga_init_irq()	(0)
@@ -77,6 +77,8 @@
 #define H2P2_DBG_FPGA_LOAD_METER_SIZE	11
 #define H2P2_DBG_FPGA_LOAD_METER_MASK	((1 << H2P2_DBG_FPGA_LOAD_METER_SIZE) - 1)
 
+#define H2P2_DBG_FPGA_P2_LED_TIMER		(1 << 0)
+#define H2P2_DBG_FPGA_P2_LED_IDLE		(1 << 1)
 
 /*
  * ---------------------------------------------------------------------------
diff --git a/include/asm-arm/arch-omap/gpio.h b/include/asm-arm/arch-omap/gpio.h
index 74cb2b9..1b38857 100644
--- a/include/asm-arm/arch-omap/gpio.h
+++ b/include/asm-arm/arch-omap/gpio.h
@@ -67,7 +67,7 @@
 
 #define OMAP_GPIO_IRQ(nr)	(OMAP_GPIO_IS_MPUIO(nr) ? \
 				 IH_MPUIO_BASE + ((nr) & 0x0f) : \
-				 IH_GPIO_BASE + ((nr) & 0x3f))
+				 IH_GPIO_BASE + (nr))
 
 extern int omap_gpio_init(void);	/* Call from board init only */
 extern int omap_request_gpio(int gpio);
diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h
index 60201e1..5406b87 100644
--- a/include/asm-arm/arch-omap/hardware.h
+++ b/include/asm-arm/arch-omap/hardware.h
@@ -267,8 +267,6 @@
 #define OMAP_LPG2_LCR			(OMAP_LPG2_BASE + 0x00)
 #define OMAP_LPG2_PMR			(OMAP_LPG2_BASE + 0x04)
 
-#ifndef __ASSEMBLER__
-
 /*
  * ---------------------------------------------------------------------------
  * Processor specific defines
@@ -277,13 +275,11 @@
 
 #include "omap730.h"
 #include "omap1510.h"
-
-#ifdef CONFIG_ARCH_OMAP24XX
 #include "omap24xx.h"
-#endif
-
 #include "omap16xx.h"
 
+#ifndef __ASSEMBLER__
+
 /*
  * ---------------------------------------------------------------------------
  * Board specific defines
diff --git a/include/asm-arm/arch-omap/io.h b/include/asm-arm/arch-omap/io.h
index 3d5bcd5..f5bcc9a 100644
--- a/include/asm-arm/arch-omap/io.h
+++ b/include/asm-arm/arch-omap/io.h
@@ -52,23 +52,33 @@
  * ----------------------------------------------------------------------------
  */
 
+#define PCIO_BASE	0
+
 #if defined(CONFIG_ARCH_OMAP1)
+
 #define IO_PHYS		0xFFFB0000
-#define IO_OFFSET      -0x01000000	/* Virtual IO = 0xfefb0000 */
+#define IO_OFFSET	0x01000000	/* Virtual IO = 0xfefb0000 */
 #define IO_SIZE		0x40000
+#define IO_VIRT		(IO_PHYS - IO_OFFSET)
+#define IO_ADDRESS(pa)	((pa) - IO_OFFSET)
+#define io_p2v(pa)	((pa) - IO_OFFSET)
+#define io_v2p(va)	((va) + IO_OFFSET)
 
 #elif defined(CONFIG_ARCH_OMAP2)
-#define IO_PHYS		0x48000000	/* L4 peripherals; other stuff has to be mapped *
-					 * manually. */
-#define IO_OFFSET	0x90000000	/* Virtual IO = 0xd8000000 */
-#define IO_SIZE		0x08000000
-#endif
 
-#define IO_VIRT		(IO_PHYS + IO_OFFSET)
-#define IO_ADDRESS(x)	((x) + IO_OFFSET)
-#define PCIO_BASE	0
-#define io_p2v(x)	((x) + IO_OFFSET)
-#define io_v2p(x)	((x) - IO_OFFSET)
+/* We map both L3 and L4 on OMAP2 */
+#define L3_24XX_PHYS	L3_24XX_BASE	/* 0x68000000 */
+#define L3_24XX_VIRT	0xf8000000
+#define L3_24XX_SIZE	SZ_1M		/* 44kB of 128MB used, want 1MB sect */
+#define L4_24XX_PHYS	L4_24XX_BASE	/* 0x48000000 */
+#define L4_24XX_VIRT	0xd8000000
+#define L4_24XX_SIZE	SZ_1M		/* 1MB of 128MB used, want 1MB sect */
+#define IO_OFFSET	0x90000000
+#define IO_ADDRESS(pa)	((pa) + IO_OFFSET)	/* Works for L3 and L4 */
+#define io_p2v(pa)	((pa) + IO_OFFSET)	/* Works for L3 and L4 */
+#define io_v2p(va)	((va) - IO_OFFSET)	/* Works for L3 and L4 */
+
+#endif
 
 #ifndef __ASSEMBLER__
 
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index 74e108c..9779686 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -22,8 +22,8 @@
  *	 are different.
  */
 
-#ifndef __ASM_ARCH_OMAP1510_IRQS_H
-#define __ASM_ARCH_OMAP1510_IRQS_H
+#ifndef __ASM_ARCH_OMAP15XX_IRQS_H
+#define __ASM_ARCH_OMAP15XX_IRQS_H
 
 /*
  * IRQ numbers for interrupt handler 1
@@ -31,7 +31,6 @@
  * NOTE: See also the OMAP-1510 and 1610 specific IRQ numbers below
  *
  */
-#define INT_IH2_IRQ		0
 #define INT_CAMERA		1
 #define INT_FIQ			3
 #define INT_RTDX		6
@@ -60,6 +59,7 @@
 /*
  * OMAP-1510 specific IRQ numbers for interrupt handler 1
  */
+#define INT_1510_IH2_IRQ	0
 #define INT_1510_RES2		2
 #define INT_1510_SPI_TX		4
 #define INT_1510_SPI_RX		5
@@ -71,6 +71,7 @@
 /*
  * OMAP-1610 specific IRQ numbers for interrupt handler 1
  */
+#define INT_1610_IH2_IRQ	0
 #define INT_1610_IH2_FIQ	2
 #define INT_1610_McBSP2_TX	4
 #define INT_1610_McBSP2_RX	5
@@ -231,6 +232,12 @@
 #define INT_730_DMA_CH15	(62 + IH2_BASE)
 #define INT_730_NAND		(63 + IH2_BASE)
 
+#define INT_24XX_SYS_NIRQ	7
+#define INT_24XX_SDMA_IRQ0	12
+#define INT_24XX_SDMA_IRQ1	13
+#define INT_24XX_SDMA_IRQ2	14
+#define INT_24XX_SDMA_IRQ3	15
+#define INT_24XX_DSS_IRQ	25
 #define INT_24XX_GPIO_BANK1	29
 #define INT_24XX_GPIO_BANK2	30
 #define INT_24XX_GPIO_BANK3	31
diff --git a/include/asm-arm/arch-omap/memory.h b/include/asm-arm/arch-omap/memory.h
index bf545b6..df50dd5 100644
--- a/include/asm-arm/arch-omap/memory.h
+++ b/include/asm-arm/arch-omap/memory.h
@@ -61,7 +61,7 @@
  * Note that the is_lbus_device() test is not very efficient on 1510
  * because of the strncmp().
  */
-#ifdef CONFIG_ARCH_OMAP1510
+#ifdef CONFIG_ARCH_OMAP15XX
 
 /*
  * OMAP-1510 Local Bus address offset
@@ -84,7 +84,7 @@
 					virt_to_lbus(addr) : \
 					__virt_to_bus(addr);})
 
-#endif	/* CONFIG_ARCH_OMAP1510 */
+#endif	/* CONFIG_ARCH_OMAP15XX */
 
 #endif
 
diff --git a/include/asm-arm/arch-omap/menelaus.h b/include/asm-arm/arch-omap/menelaus.h
new file mode 100644
index 0000000..46be8b8
--- /dev/null
+++ b/include/asm-arm/arch-omap/menelaus.h
@@ -0,0 +1,22 @@
+/*
+ * linux/include/asm-arm/arch-omap/menelaus.h
+ *
+ * Functions to access Menelaus power management chip
+ */
+
+#ifndef __ASM_ARCH_MENELAUS_H
+#define __ASM_ARCH_MENELAUS_H
+
+extern void menelaus_mmc_register(void (*callback)(u8 card_mask),
+				  unsigned long data);
+extern void menelaus_mmc_remove(void);
+extern void menelaus_mmc_opendrain(int enable);
+
+#if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_MENELAUS)
+#define omap_has_menelaus()	1
+#else
+#define omap_has_menelaus()	0
+#endif
+
+#endif
+
diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h
index 1b1ad41..13415a9a 100644
--- a/include/asm-arm/arch-omap/mux.h
+++ b/include/asm-arm/arch-omap/mux.h
@@ -4,7 +4,7 @@
  * Table of the Omap register configurations for the FUNC_MUX and
  * PULL_DWN combinations.
  *
- * Copyright (C) 2003 Nokia Corporation
+ * Copyright (C) 2003 - 2005 Nokia Corporation
  *
  * Written by Tony Lindgren <tony.lindgren@nokia.com>
  *
@@ -58,6 +58,16 @@
 					.pu_pd_reg = PU_PD_SEL_##reg, \
 					.pu_pd_val = status,
 
+#define MUX_REG_730(reg, mode_offset, mode) .mux_reg_name = "OMAP730_IO_CONF_"#reg, \
+					.mux_reg = OMAP730_IO_CONF_##reg, \
+					.mask_offset = mode_offset, \
+					.mask = mode,
+
+#define PULL_REG_730(reg, bit, status)	.pull_name = "OMAP730_IO_CONF_"#reg, \
+					.pull_reg = OMAP730_IO_CONF_##reg, \
+					.pull_bit = bit, \
+					.pull_val = status,
+
 #else
 
 #define MUX_REG(reg, mode_offset, mode) .mux_reg = FUNC_MUX_CTRL_##reg, \
@@ -71,6 +81,15 @@
 #define PU_PD_REG(reg, status)		.pu_pd_reg = PU_PD_SEL_##reg, \
 					.pu_pd_val = status,
 
+#define MUX_REG_730(reg, mode_offset, mode) \
+					.mux_reg = OMAP730_IO_CONF_##reg, \
+					.mask_offset = mode_offset, \
+					.mask = mode,
+
+#define PULL_REG_730(reg, bit, status)	.pull_reg = OMAP730_IO_CONF_##reg, \
+					.pull_bit = bit, \
+					.pull_val = status,
+
 #endif /* CONFIG_OMAP_MUX_DEBUG */
 
 #define MUX_CFG(desc, mux_reg, mode_offset, mode,	\
@@ -84,13 +103,44 @@
 	PU_PD_REG(pu_pd_reg, pu_pd_status)		\
 },
 
+
+/*
+ * OMAP730 has a slightly different config for the pin mux.
+ * - config regs are the OMAP730_IO_CONF_x regs (see omap730.h) regs and
+ *   not the FUNC_MUX_CTRL_x regs from hardware.h
+ * - for pull-up/down, only has one enable bit which is is in the same register
+ *   as mux config
+ */
+#define MUX_CFG_730(desc, mux_reg, mode_offset, mode,	\
+		   pull_reg, pull_bit, pull_status,	\
+		   pu_pd_reg, pu_pd_status, debug_status)\
+{							\
+	.name =	 desc,					\
+	.debug = debug_status,				\
+	MUX_REG_730(mux_reg, mode_offset, mode)		\
+	PULL_REG_730(mux_reg, pull_bit, pull_status)	\
+	PU_PD_REG(pu_pd_reg, pu_pd_status)		\
+},
+
+#define MUX_CFG_24XX(desc, reg_offset, mode,			\
+				pull_en, pull_mode, dbg)	\
+{								\
+	.name		= desc,					\
+	.debug		= dbg,					\
+	.mux_reg	= reg_offset,				\
+	.mask		= mode,					\
+	.pull_val	= pull_en,				\
+	.pu_pd_val	= pull_mode,				\
+},
+
+
 #define PULL_DISABLED	0
 #define PULL_ENABLED	1
 
 #define PULL_DOWN	0
 #define PULL_UP		1
 
-typedef struct {
+struct pin_config {
 	char *name;
 	unsigned char busy;
 	unsigned char debug;
@@ -108,13 +158,23 @@
 	const char *pu_pd_name;
 	const unsigned int pu_pd_reg;
 	const unsigned char pu_pd_val;
-} reg_cfg_set;
+};
 
-/*
- * Lookup table for FUNC_MUX and PULL_DWN register combinations for each
- * device. See also reg_cfg_table below for the register values.
- */
-typedef enum {
+enum omap730_index {
+	/* OMAP 730 keyboard */
+	E2_730_KBR0,
+	J7_730_KBR1,
+	E1_730_KBR2,
+	F3_730_KBR3,
+	D2_730_KBR4,
+	C2_730_KBC0,
+	D3_730_KBC1,
+	E4_730_KBC2,
+	F4_730_KBC3,
+	E3_730_KBC4,
+};
+
+enum omap1xxx_index {
 	/* UART1 (BT_UART_GATING)*/
 	UART1_TX = 0,
 	UART1_RTS,
@@ -331,245 +391,34 @@
 	V10_1610_CF_IREQ,
 	W10_1610_CF_RESET,
 	W11_1610_CF_CD1,
-} reg_cfg_t;
-
-#if defined(__MUX_C__) && defined(CONFIG_OMAP_MUX)
-
-/*
- * Table of various FUNC_MUX and PULL_DWN combinations for each device.
- * See also reg_cfg_t above for the lookup table.
- */
-static const reg_cfg_set __initdata_or_module
-reg_cfg_table[] = {
-/*
- *	 description		mux  mode   mux	 pull pull  pull  pu_pd	 pu  dbg
- *				reg  offset mode reg  bit   ena	  reg
- */
-MUX_CFG("UART1_TX",		 9,   21,    1,	  2,   3,   0,	 NA,	 0,  0)
-MUX_CFG("UART1_RTS",		 9,   12,    1,	  2,   0,   0,	 NA,	 0,  0)
-
-/* UART2 (COM_UART_GATING), conflicts with USB2 */
-MUX_CFG("UART2_TX",		 C,   27,    1,	  3,   3,   0,	 NA,	 0,  0)
-MUX_CFG("UART2_RX",		 C,   18,    0,	  3,   1,   1,	 NA,	 0,  0)
-MUX_CFG("UART2_CTS",		 C,   21,    0,	  3,   1,   1,	 NA,	 0,  0)
-MUX_CFG("UART2_RTS",		 C,   24,    1,	  3,   2,   0,	 NA,	 0,  0)
-
-/* UART3 (GIGA_UART_GATING) */
-MUX_CFG("UART3_TX",		 6,    0,    1,	  0,  30,   0,	 NA,	 0,  0)
-MUX_CFG("UART3_RX",		 6,    3,    0,	  0,  31,   1,	 NA,	 0,  0)
-MUX_CFG("UART3_CTS",		 5,   12,    2,	  0,  24,   0,	 NA,	 0,  0)
-MUX_CFG("UART3_RTS",		 5,   15,    2,	  0,  25,   0,	 NA,	 0,  0)
-MUX_CFG("UART3_CLKREQ",		 9,   27,    0,	  2,   5,   0,	 NA,	 0,  0)
-MUX_CFG("UART3_BCLK",		 A,    0,    0,	  2,   6,   0,	 NA,	 0,  0)
-MUX_CFG("Y15_1610_UART3_RTS",	 A,    0,    1,	  2,   6,   0,	 NA,	 0,  0)
-
-/* PWT & PWL, conflicts with UART3 */
-MUX_CFG("PWT",		 	 6,    0,    2,	  0,  30,   0,	 NA,	 0,  0)
-MUX_CFG("PWL",		 	 6,    3,    1,	  0,  31,   1,	 NA,	 0,  0)
-
-/* USB internal master generic */
-MUX_CFG("R18_USB_VBUS",		 7,    9,    2,	  1,  11,   0,	 NA,	 0,  1)
-MUX_CFG("R18_1510_USB_GPIO0",	 7,    9,    0,	  1,  11,   1,	 NA,	 0,  1)
-/* works around erratum:  W4_USB_PUEN and W4_USB_PUDIS are switched! */
-MUX_CFG("W4_USB_PUEN",		 D,    3,    3,	  3,   5,   1,	 NA,	 0,  1)
-MUX_CFG("W4_USB_CLKO",		 D,    3,    1,	  3,   5,   0,	 NA,	 0,  1)
-MUX_CFG("W4_USB_HIGHZ",		 D,    3,    4,	  3,   5,   0,	  3,	 0,  1)
-MUX_CFG("W4_GPIO58",		 D,    3,    7,	  3,   5,   0,	  3,	 0,  1)
-
-/* USB1 master */
-MUX_CFG("USB1_SUSP",		 8,   27,    2,	  1,  27,   0,	 NA,	 0,  1)
-MUX_CFG("USB1_SE0",		 9,    0,    2,	  1,  28,   0,	 NA,	 0,  1)
-MUX_CFG("W13_1610_USB1_SE0",	 9,    0,    4,	  1,  28,   0,	 NA,	 0,  1)
-MUX_CFG("USB1_TXEN",		 9,    3,    2,	  1,  29,   0,	 NA,	 0,  1)
-MUX_CFG("USB1_TXD",		 9,   24,    1,	  2,   4,   0,	 NA,	 0,  1)
-MUX_CFG("USB1_VP",		 A,    3,    1,	  2,   7,   0,	 NA,	 0,  1)
-MUX_CFG("USB1_VM",		 A,    6,    1,	  2,   8,   0,	 NA,	 0,  1)
-MUX_CFG("USB1_RCV",		 A,    9,    1,	  2,   9,   0,	 NA,	 0,  1)
-MUX_CFG("USB1_SPEED",		 A,   12,    2,	  2,  10,   0,	 NA,	 0,  1)
-MUX_CFG("R13_1610_USB1_SPEED",	 A,   12,    5,	  2,  10,   0,	 NA,	 0,  1)
-MUX_CFG("R13_1710_USB1_SEO",	 A,   12,    5,   2,  10,   0,   NA,     0,  1)
-
-/* USB2 master */
-MUX_CFG("USB2_SUSP",		 B,    3,    1,	  2,  17,   0,	 NA,	 0,  1)
-MUX_CFG("USB2_VP",		 B,    6,    1,	  2,  18,   0,	 NA,	 0,  1)
-MUX_CFG("USB2_TXEN",		 B,    9,    1,	  2,  19,   0,	 NA,	 0,  1)
-MUX_CFG("USB2_VM",		 C,   18,    1,	  3,   0,   0,	 NA,	 0,  1)
-MUX_CFG("USB2_RCV",		 C,   21,    1,	  3,   1,   0,	 NA,	 0,  1)
-MUX_CFG("USB2_SE0",		 C,   24,    2,	  3,   2,   0,	 NA,	 0,  1)
-MUX_CFG("USB2_TXD",		 C,   27,    2,	  3,   3,   0,	 NA,	 0,  1)
-
-/* OMAP-1510 GPIO */
-MUX_CFG("R18_1510_GPIO0",	 7,    9,    0,   1,  11,   1,    0,     0,  1)
-MUX_CFG("R19_1510_GPIO1",	 7,    6,    0,   1,  10,   1,    0,     0,  1)
-MUX_CFG("M14_1510_GPIO2",	 7,    3,    0,   1,   9,   1,    0,     0,  1)
-
-/* OMAP1610 GPIO */
-MUX_CFG("P18_1610_GPIO3",	 7,    0,    0,   1,   8,   0,   NA,     0,  1)
-MUX_CFG("Y15_1610_GPIO17",	 A,    0,    7,   2,   6,   0,   NA,     0,  1)
-
-/* OMAP-1710 GPIO */
-MUX_CFG("R18_1710_GPIO0",        7,    9,    0,   1,  11,   1,    1,     1,  1)
-MUX_CFG("V2_1710_GPIO10",        F,   27,    1,   4,   3,   1,    4,     1,  1)
-MUX_CFG("N21_1710_GPIO14",       6,    9,    0,   1,   1,   1,    1,     1,  1)
-MUX_CFG("W15_1710_GPIO40",       9,   27,    7,   2,   5,   1,    2,     1,  1)
-
-/* MPUIO */
-MUX_CFG("MPUIO2",		 7,   18,    0,	  1,  14,   1,	 NA,	 0,  1)
-MUX_CFG("N15_1610_MPUIO2",	 7,   18,    0,	  1,  14,   1,	  1,	 0,  1)
-MUX_CFG("MPUIO4",		 7,   15,    0,	  1,  13,   1,	 NA,	 0,  1)
-MUX_CFG("MPUIO5",		 7,   12,    0,	  1,  12,   1,	 NA,	 0,  1)
-
-MUX_CFG("T20_1610_MPUIO5",	 7,   12,    0,	  1,  12,   0,	  3,	 0,  1)
-MUX_CFG("W11_1610_MPUIO6",	10,   15,    2,	  3,   8,   0,	  3,	 0,  1)
-MUX_CFG("V10_1610_MPUIO7",	 A,   24,    2,	  2,  14,   0,	  2,	 0,  1)
-MUX_CFG("W11_1610_MPUIO9",	10,   15,    1,	  3,   8,   0,	  3,	 0,  1)
-MUX_CFG("V10_1610_MPUIO10",	 A,   24,    1,	  2,  14,   0,	  2,	 0,  1)
-MUX_CFG("W10_1610_MPUIO11",	 A,   18,    2,	  2,  11,   0,	  2,	 0,  1)
-MUX_CFG("E20_1610_MPUIO13",	 3,   21,    1,	  0,   7,   0,	  0,	 0,  1)
-MUX_CFG("U20_1610_MPUIO14",	 9,    6,    6,	  0,  30,   0,	  0,	 0,  1)
-MUX_CFG("E19_1610_MPUIO15",	 3,   18,    1,	  0,   6,   0,	  0,	 0,  1)
-
-/* MCBSP2 */
-MUX_CFG("MCBSP2_CLKR",		 C,    6,    0,	  2,  27,   1,	 NA,	 0,  1)
-MUX_CFG("MCBSP2_CLKX",		 C,    9,    0,	  2,  29,   1,	 NA,	 0,  1)
-MUX_CFG("MCBSP2_DR",		 C,    0,    0,	  2,  26,   1,	 NA,	 0,  1)
-MUX_CFG("MCBSP2_DX",		 C,   15,    0,	  2,  31,   1,	 NA,	 0,  1)
-MUX_CFG("MCBSP2_FSR",		 C,   12,    0,	  2,  30,   1,	 NA,	 0,  1)
-MUX_CFG("MCBSP2_FSX",		 C,    3,    0,	  2,  27,   1,	 NA,	 0,  1)
-
-/* MCBSP3 NOTE: Mode must 1 for clock */
-MUX_CFG("MCBSP3_CLKX",		 9,    3,    1,	  1,  29,   0,	 NA,	 0,  1)
-
-/* Misc ballouts */
-MUX_CFG("BALLOUT_V8_ARMIO3",	 B,   18,    0,	  2,  25,   1,	 NA,	 0,  1)
-MUX_CFG("N20_HDQ",	       6,   18,    1,   1,   4,   0,    1,     4,  0)
-
-/* OMAP-1610 MMC2 */
-MUX_CFG("W8_1610_MMC2_DAT0",	 B,   21,    6,	  2,  23,   1,	  2,	 1,  1)
-MUX_CFG("V8_1610_MMC2_DAT1",	 B,   27,    6,	  2,  25,   1,	  2,	 1,  1)
-MUX_CFG("W15_1610_MMC2_DAT2",	 9,   12,    6,	  2,   5,   1,	  2,	 1,  1)
-MUX_CFG("R10_1610_MMC2_DAT3",	 B,   18,    6,	  2,  22,   1,	  2,	 1,  1)
-MUX_CFG("Y10_1610_MMC2_CLK",	 B,    3,    6,	  2,  17,   0,	  2,	 0,  1)
-MUX_CFG("Y8_1610_MMC2_CMD",	 B,   24,    6,	  2,  24,   1,	  2,	 1,  1)
-MUX_CFG("V9_1610_MMC2_CMDDIR",	 B,   12,    6,	  2,  20,   0,	  2,	 1,  1)
-MUX_CFG("V5_1610_MMC2_DATDIR0",	 B,   15,    6,	  2,  21,   0,	  2,	 1,  1)
-MUX_CFG("W19_1610_MMC2_DATDIR1", 8,   15,    6,	  1,  23,   0,	  1,	 1,  1)
-MUX_CFG("R18_1610_MMC2_CLKIN",	 7,    9,    6,	  1,  11,   0,	  1,	11,  1)
-
-/* OMAP-1610 External Trace Interface */
-MUX_CFG("M19_1610_ETM_PSTAT0",	 5,   27,    1,	  0,  29,   0,	  0,	 0,  1)
-MUX_CFG("L15_1610_ETM_PSTAT1",	 5,   24,    1,	  0,  28,   0,	  0,	 0,  1)
-MUX_CFG("L18_1610_ETM_PSTAT2",	 5,   21,    1,	  0,  27,   0,	  0,	 0,  1)
-MUX_CFG("L19_1610_ETM_D0",	 5,   18,    1,	  0,  26,   0,	  0,	 0,  1)
-MUX_CFG("J19_1610_ETM_D6",	 5,    0,    1,	  0,  20,   0,	  0,	 0,  1)
-MUX_CFG("J18_1610_ETM_D7",	 5,   27,    1,	  0,  19,   0,	  0,	 0,  1)
-
-/* OMAP16XX GPIO */
-MUX_CFG("P20_1610_GPIO4",	 6,   27,    0,	  1,   7,   0,	  1,	 1,  1)
-MUX_CFG("V9_1610_GPIO7",	 B,   12,    1,	  2,  20,   0,	  2,	 1,  1)
-MUX_CFG("W8_1610_GPIO9",	 B,   21,    0,	  2,  23,   0,	  2,	 1,  1)
-MUX_CFG("N20_1610_GPIO11",       6,   18,    0,   1,   4,   0,    1,     1,  1)
-MUX_CFG("N19_1610_GPIO13",	 6,   12,    0,	  1,   2,   0,	  1,	 1,  1)
-MUX_CFG("P10_1610_GPIO22",	 C,    0,    7,	  2,  26,   0,	  2,	 1,  1)
-MUX_CFG("V5_1610_GPIO24",	 B,   15,    7,	  2,  21,   0,	  2,	 1,  1)
-MUX_CFG("AA20_1610_GPIO_41",	 9,    9,    7,	  1,  31,   0,	  1,	 1,  1)
-MUX_CFG("W19_1610_GPIO48",	 8,   15,    7,   1,  23,   1,    1,     0,  1)
-MUX_CFG("M7_1610_GPIO62",	10,    0,    0,   4,  24,   0,    4,     0,  1)
-MUX_CFG("V14_16XX_GPIO37",	 9,   18,    7,	  2,   2,   0,	  2,	 2,  0)
-MUX_CFG("R9_16XX_GPIO18",	 C,   18,    7,   3,   0,   0,    3,     0,  0)
-MUX_CFG("L14_16XX_GPIO49",	 6,    3,    7,   0,  31,   0,    0,    31,  0)
-
-/* OMAP-1610 uWire */
-MUX_CFG("V19_1610_UWIRE_SCLK",	 8,    6,    0,	  1,  20,   0,	  1,	 1,  1)
-MUX_CFG("U18_1610_UWIRE_SDI",	 8,    0,    0,	  1,  18,   0,	  1,	 1,  1)
-MUX_CFG("W21_1610_UWIRE_SDO",	 8,    3,    0,	  1,  19,   0,	  1,	 1,  1)
-MUX_CFG("N14_1610_UWIRE_CS0",	 8,    9,    1,	  1,  21,   0,	  1,	 1,  1)
-MUX_CFG("P15_1610_UWIRE_CS3",	 8,   12,    1,	  1,  22,   0,	  1,	 1,  1)
-MUX_CFG("N15_1610_UWIRE_CS1",	 7,   18,    2,	  1,  14,   0,	 NA,	 0,  1)
-
-/* OMAP-1610 Flash */
-MUX_CFG("L3_1610_FLASH_CS2B_OE",10,    6,    1,	 NA,   0,   0,	 NA,	 0,  1)
-MUX_CFG("M8_1610_FLASH_CS2B_WE",10,    3,    1,	 NA,   0,   0,	 NA,	 0,  1)
-
-/* First MMC interface, same on 1510, 1610 and 1710 */
-MUX_CFG("MMC_CMD",		 A,   27,    0,	  2,  15,   1,	  2,	 1,  1)
-MUX_CFG("MMC_DAT1",		 A,   24,    0,	  2,  14,   1,	  2,	 1,  1)
-MUX_CFG("MMC_DAT2",		 A,   18,    0,	  2,  12,   1,	  2,	 1,  1)
-MUX_CFG("MMC_DAT0",		 B,    0,    0,	  2,  16,   1,	  2,	 1,  1)
-MUX_CFG("MMC_CLK",		 A,   21,    0,	 NA,   0,   0,	 NA,	 0,  1)
-MUX_CFG("MMC_DAT3",		10,   15,    0,	  3,   8,   1,	  3,	 1,  1)
-MUX_CFG("M15_1710_MMC_CLKI",	 6,   21,    2,   0,   0,   0,   NA,     0,  1)
-MUX_CFG("P19_1710_MMC_CMDDIR",	 6,   24,    6,   0,   0,   0,   NA,     0,  1)
-MUX_CFG("P20_1710_MMC_DATDIR0",	 6,   27,    5,   0,   0,   0,   NA,     0,  1)
-
-/* OMAP-1610 USB0 alternate configuration */
-MUX_CFG("W9_USB0_TXEN",		 B,   9,     5,	  2,  19,   0,	  2,	 0,  1)
-MUX_CFG("AA9_USB0_VP",		 B,   6,     5,	  2,  18,   0,	  2,	 0,  1)
-MUX_CFG("Y5_USB0_RCV",		 C,  21,     5,	  3,   1,   0,	  1,	 0,  1)
-MUX_CFG("R9_USB0_VM",		 C,  18,     5,	  3,   0,   0,	  3,	 0,  1)
-MUX_CFG("V6_USB0_TXD",		 C,  27,     5,	  3,   3,   0,	  3,	 0,  1)
-MUX_CFG("W5_USB0_SE0",		 C,  24,     5,	  3,   2,   0,	  3,	 0,  1)
-MUX_CFG("V9_USB0_SPEED",	 B,  12,     5,	  2,  20,   0,	  2,	 0,  1)
-MUX_CFG("Y10_USB0_SUSP",	 B,   3,     5,	  2,  17,   0,	  2,	 0,  1)
-
-/* USB2 interface */
-MUX_CFG("W9_USB2_TXEN",		 B,   9,     1,	 NA,   0,   0,	 NA,	 0,  1)
-MUX_CFG("AA9_USB2_VP",		 B,   6,     1,	 NA,   0,   0,	 NA,	 0,  1)
-MUX_CFG("Y5_USB2_RCV",		 C,  21,     1,	 NA,   0,   0,	 NA,	 0,  1)
-MUX_CFG("R9_USB2_VM",		 C,  18,     1,	 NA,   0,   0,	 NA,	 0,  1)
-MUX_CFG("V6_USB2_TXD",		 C,  27,     2,	 NA,   0,   0,	 NA,	 0,  1)
-MUX_CFG("W5_USB2_SE0",		 C,  24,     2,	 NA,   0,   0,	 NA,	 0,  1)
-
-/* 16XX UART */
-MUX_CFG("R13_1610_UART1_TX",	 A,  12,     6,	  2,  10,   0,	  2,	10,  1)
-MUX_CFG("V14_16XX_UART1_RX",	 9,  18,     0,	  2,   2,   0,	  2,	 2,  1)
-MUX_CFG("R14_1610_UART1_CTS",	 9,  15,     0,	  2,   1,   0,	  2,	 1,  1)
-MUX_CFG("AA15_1610_UART1_RTS",	 9,  12,     1,	  2,   0,   0,	  2,	 0,  1)
-MUX_CFG("R9_16XX_UART2_RX",	 C,  18,     0,   3,   0,   0,    3,     0,  1)
-MUX_CFG("L14_16XX_UART3_RX",	 6,   3,     0,   0,  31,   0,    0,    31,  1)
-
-/* I2C interface */
-MUX_CFG("I2C_SCL",		 7,  24,     0,	 NA,   0,   0,	 NA,	 0,  0)
-MUX_CFG("I2C_SDA",		 7,  27,     0,	 NA,   0,   0,	 NA,	 0,  0)
-
-/* Keypad */
-MUX_CFG("F18_1610_KBC0",	 3,  15,     0,	  0,   5,   1,	  0,	 0,  0)
-MUX_CFG("D20_1610_KBC1",	 3,  12,     0,	  0,   4,   1,	  0,	 0,  0)
-MUX_CFG("D19_1610_KBC2",	 3,   9,     0,	  0,   3,   1,	  0,	 0,  0)
-MUX_CFG("E18_1610_KBC3",	 3,   6,     0,	  0,   2,   1,	  0,	 0,  0)
-MUX_CFG("C21_1610_KBC4",	 3,   3,     0,	  0,   1,   1,	  0,	 0,  0)
-MUX_CFG("G18_1610_KBR0",	 4,   0,     0,	  0,   10,  1,	  0,	 1,  0)
-MUX_CFG("F19_1610_KBR1",	 3,   27,    0,	  0,   9,   1,	  0,	 1,  0)
-MUX_CFG("H14_1610_KBR2",	 3,   24,    0,	  0,   8,   1,	  0,	 1,  0)
-MUX_CFG("E20_1610_KBR3",	 3,   21,    0,	  0,   7,   1,	  0,	 1,  0)
-MUX_CFG("E19_1610_KBR4",	 3,   18,    0,	  0,   6,   1,	  0,	 1,  0)
-MUX_CFG("N19_1610_KBR5",	 6,  12,     1,	  1,   2,   1,	  1,	 1,  0)
-
-/* Power management */
-MUX_CFG("T20_1610_LOW_PWR",	 7,   12,    1,	  NA,   0,   0,   NA,	 0,  0)
-
-/* MCLK Settings */
-MUX_CFG("V5_1710_MCLK_ON",	 B,   15,    0,	  NA,   0,   0,   NA,	 0,  0)
-MUX_CFG("V5_1710_MCLK_OFF",	 B,   15,    6,	  NA,   0,   0,   NA,	 0,  0)
-MUX_CFG("R10_1610_MCLK_ON",	 B,   18,    0,	  NA,  22,   0,	  NA,	 1,  0)
-MUX_CFG("R10_1610_MCLK_OFF",	 B,   18,    6,	  2,   22,   1,	  2,	 1,  1)
-
-/* CompactFlash controller, conflicts with MMC1 */
-MUX_CFG("P11_1610_CF_CD2",	 A,   27,    3,	  2,   15,   1,	  2,	 1,  1)
-MUX_CFG("R11_1610_CF_IOIS16",	 B,    0,    3,	  2,   16,   1,	  2,	 1,  1)
-MUX_CFG("V10_1610_CF_IREQ",	 A,   24,    3,	  2,   14,   0,	  2,	 0,  1)
-MUX_CFG("W10_1610_CF_RESET",	 A,   18,    3,	  2,   12,   1,	  2,	 1,  1)
-MUX_CFG("W11_1610_CF_CD1",	10,   15,    3,	  3,    8,   1,	  3,	 1,  1)
 };
 
-#endif	/* __MUX_C__ */
+enum omap24xx_index {
+	/* 24xx I2C */
+	M19_24XX_I2C1_SCL,
+	L15_24XX_I2C1_SDA,
+	J15_24XX_I2C2_SCL,
+	H19_24XX_I2C2_SDA,
+
+	/* 24xx Menelaus interrupt */
+	W19_24XX_SYS_NIRQ,
+
+	/* 24xx GPIO */
+	Y20_24XX_GPIO60,
+	M15_24XX_GPIO92,
+};
 
 #ifdef	CONFIG_OMAP_MUX
 /* setup pin muxing in Linux */
-extern int omap_cfg_reg(reg_cfg_t reg_cfg);
+extern int omap1_mux_init(void);
+extern int omap2_mux_init(void);
+extern int omap_mux_register(struct pin_config * pins, unsigned long size);
+extern int omap_cfg_reg(unsigned long reg_cfg);
 #else
 /* boot loader does it all (no warnings from CONFIG_OMAP_MUX_WARNINGS) */
-static inline int omap_cfg_reg(reg_cfg_t reg_cfg) { return 0; }
+static inline int omap1_mux_init(void) { return 0; }
+static inline int omap2_mux_init(void) { return 0; }
+static inline int omap_cfg_reg(unsigned long reg_cfg) { return 0; }
 #endif
 
 #endif
diff --git a/include/asm-arm/arch-omap/omap1510.h b/include/asm-arm/arch-omap/omap1510.h
index f086a39..c575d35 100644
--- a/include/asm-arm/arch-omap/omap1510.h
+++ b/include/asm-arm/arch-omap/omap1510.h
@@ -25,8 +25,8 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifndef __ASM_ARCH_OMAP1510_H
-#define __ASM_ARCH_OMAP1510_H
+#ifndef __ASM_ARCH_OMAP15XX_H
+#define __ASM_ARCH_OMAP15XX_H
 
 /*
  * ----------------------------------------------------------------------------
@@ -44,5 +44,5 @@
 #define OMAP1510_DSPREG_SIZE	SZ_128K
 #define OMAP1510_DSPREG_START	0xE1000000
 
-#endif /*  __ASM_ARCH_OMAP1510_H */
+#endif /*  __ASM_ARCH_OMAP15XX_H */
 
diff --git a/include/asm-arm/arch-omap/omap24xx.h b/include/asm-arm/arch-omap/omap24xx.h
index a910546..6e59805 100644
--- a/include/asm-arm/arch-omap/omap24xx.h
+++ b/include/asm-arm/arch-omap/omap24xx.h
@@ -1,15 +1,24 @@
 #ifndef __ASM_ARCH_OMAP24XX_H
 #define __ASM_ARCH_OMAP24XX_H
 
-#define OMAP24XX_L4_IO_BASE	0x48000000
+/*
+ * Please place only base defines here and put the rest in device
+ * specific headers. Note also that some of these defines are needed
+ * for omap1 to compile without adding ifdefs.
+ */
+
+#define L4_24XX_BASE		0x48000000
+#define L3_24XX_BASE		0x68000000
 
 /* interrupt controller */
-#define OMAP24XX_IC_BASE	(OMAP24XX_L4_IO_BASE + 0xfe000)
+#define OMAP24XX_IC_BASE	(L4_24XX_BASE + 0xfe000)
 #define VA_IC_BASE		IO_ADDRESS(OMAP24XX_IC_BASE)
-
 #define OMAP24XX_IVA_INTC_BASE	0x40000000
-
 #define IRQ_SIR_IRQ		0x0040
 
+#define OMAP24XX_32KSYNCT_BASE	(L4_24XX_BASE + 0x4000)
+#define OMAP24XX_PRCM_BASE	(L4_24XX_BASE + 0x8000)
+#define OMAP24XX_SDRC_BASE	(L3_24XX_BASE + 0x9000)
+
 #endif /* __ASM_ARCH_OMAP24XX_H */
 
diff --git a/include/asm-arm/arch-omap/omapfb.h b/include/asm-arm/arch-omap/omapfb.h
new file mode 100644
index 0000000..4ba2622
--- /dev/null
+++ b/include/asm-arm/arch-omap/omapfb.h
@@ -0,0 +1,281 @@
+/*
+ * File: include/asm-arm/arch-omap/omapfb.h
+ *
+ * Framebuffer driver for TI OMAP boards
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.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 __OMAPFB_H
+#define __OMAPFB_H
+
+/* IOCTL commands. */
+
+#define OMAP_IOW(num, dtype)	_IOW('O', num, dtype)
+#define OMAP_IOR(num, dtype)	_IOR('O', num, dtype)
+#define OMAP_IOWR(num, dtype)	_IOWR('O', num, dtype)
+#define OMAP_IO(num)		_IO('O', num)
+
+#define OMAPFB_MIRROR		OMAP_IOW(31, int)
+#define OMAPFB_SYNC_GFX		OMAP_IO(37)
+#define OMAPFB_VSYNC		OMAP_IO(38)
+#define OMAPFB_SET_UPDATE_MODE	OMAP_IOW(40, enum omapfb_update_mode)
+#define OMAPFB_GET_CAPS		OMAP_IOR(42, unsigned long)
+#define OMAPFB_GET_UPDATE_MODE	OMAP_IOW(43, enum omapfb_update_mode)
+#define OMAPFB_LCD_TEST		OMAP_IOW(45, int)
+#define OMAPFB_CTRL_TEST	OMAP_IOW(46, int)
+#define OMAPFB_UPDATE_WINDOW	OMAP_IOW(47, struct omapfb_update_window)
+#define OMAPFB_SETUP_PLANE	OMAP_IOW(48, struct omapfb_setup_plane)
+#define OMAPFB_ENABLE_PLANE	OMAP_IOW(49, struct omapfb_enable_plane)
+#define OMAPFB_SET_COLOR_KEY	OMAP_IOW(50, struct omapfb_color_key)
+
+#define OMAPFB_CAPS_GENERIC_MASK	0x00000fff
+#define OMAPFB_CAPS_LCDC_MASK		0x00fff000
+#define OMAPFB_CAPS_PANEL_MASK		0xff000000
+
+#define OMAPFB_CAPS_MANUAL_UPDATE	0x00001000
+#define OMAPFB_CAPS_SET_BACKLIGHT	0x01000000
+
+/* Values from DSP must map to lower 16-bits */
+#define OMAPFB_FORMAT_MASK         0x00ff
+#define OMAPFB_FORMAT_FLAG_DOUBLE  0x0100
+
+enum omapfb_color_format {
+	OMAPFB_COLOR_RGB565 = 0,
+	OMAPFB_COLOR_YUV422,
+	OMAPFB_COLOR_YUV420,
+	OMAPFB_COLOR_CLUT_8BPP,
+	OMAPFB_COLOR_CLUT_4BPP,
+	OMAPFB_COLOR_CLUT_2BPP,
+	OMAPFB_COLOR_CLUT_1BPP,
+};
+
+struct omapfb_update_window {
+	u32 x, y;
+	u32 width, height;
+	u32 format;
+};
+
+enum omapfb_plane {
+	OMAPFB_PLANE_GFX = 0,
+	OMAPFB_PLANE_VID1,
+	OMAPFB_PLANE_VID2,
+};
+
+enum omapfb_channel_out {
+	OMAPFB_CHANNEL_OUT_LCD = 0,
+	OMAPFB_CHANNEL_OUT_DIGIT,
+};
+
+struct omapfb_setup_plane {
+	u8  plane;
+	u8  channel_out;
+	u32 offset;
+	u32 pos_x, pos_y;
+	u32 width, height;
+	u32 color_mode;
+};
+
+struct omapfb_enable_plane {
+	u8  plane;
+	u8  enable;
+};
+
+enum omapfb_color_key_type {
+	OMAPFB_COLOR_KEY_DISABLED = 0,
+	OMAPFB_COLOR_KEY_GFX_DST,
+	OMAPFB_COLOR_KEY_VID_SRC,
+};
+
+struct omapfb_color_key {
+	u8  channel_out;
+	u32 background;
+	u32 trans_key;
+	u8  key_type;
+};
+
+enum omapfb_update_mode {
+	OMAPFB_UPDATE_DISABLED = 0,
+	OMAPFB_AUTO_UPDATE,
+	OMAPFB_MANUAL_UPDATE
+};
+
+#ifdef __KERNEL__
+
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+
+#define OMAP_LCDC_INV_VSYNC             0x0001
+#define OMAP_LCDC_INV_HSYNC             0x0002
+#define OMAP_LCDC_INV_PIX_CLOCK         0x0004
+#define OMAP_LCDC_INV_OUTPUT_EN         0x0008
+#define OMAP_LCDC_HSVS_RISING_EDGE      0x0010
+#define OMAP_LCDC_HSVS_OPPOSITE         0x0020
+
+#define OMAP_LCDC_SIGNAL_MASK		0x003f
+
+#define OMAP_LCDC_PANEL_TFT		0x0100
+
+#ifdef CONFIG_ARCH_OMAP1
+#define OMAPFB_PLANE_NUM		1
+#else
+#define OMAPFB_PLANE_NUM		3
+#endif
+
+struct omapfb_device;
+
+struct lcd_panel {
+	const char	*name;
+	int		config;		/* TFT/STN, signal inversion */
+	int		bpp;		/* Pixel format in fb mem */
+	int		data_lines;	/* Lines on LCD HW interface */
+
+	int		x_res, y_res;
+	int		pixel_clock;	/* In kHz */
+	int		hsw;		/* Horizontal synchronization
+					   pulse width */
+	int		hfp;		/* Horizontal front porch */
+	int		hbp;		/* Horizontal back porch */
+	int		vsw;		/* Vertical synchronization
+					   pulse width */
+	int		vfp;		/* Vertical front porch */
+	int		vbp;		/* Vertical back porch */
+	int		acb;		/* ac-bias pin frequency */
+	int		pcd;		/* pixel clock divider.
+					   Obsolete use pixel_clock instead */
+
+	int		(*init)		(struct omapfb_device *fbdev);
+	void		(*cleanup)	(void);
+	int		(*enable)	(void);
+	void		(*disable)	(void);
+	unsigned long	(*get_caps)	(void);
+	int		(*set_bklight_level)(unsigned int level);
+	unsigned int	(*get_bklight_level)(void);
+	unsigned int	(*get_bklight_max)  (void);
+	int		(*run_test)	(int test_num);
+};
+
+struct omapfb_device;
+
+struct extif_timings {
+	int cs_on_time;
+	int cs_off_time;
+	int we_on_time;
+	int we_off_time;
+	int re_on_time;
+	int re_off_time;
+	int we_cycle_time;
+	int re_cycle_time;
+	int cs_pulse_width;
+	int access_time;
+};
+
+struct lcd_ctrl_extif {
+	int  (*init)		(void);
+	void (*cleanup)		(void);
+	void (*set_timings)	(const struct extif_timings *timings);
+	void (*write_command)	(u32 cmd);
+	u32  (*read_data)	(void);
+	void (*write_data)	(u32 data);
+	void (*transfer_area)	(int width, int height,
+				 void (callback)(void * data), void *data);
+};
+
+struct lcd_ctrl {
+	const char	*name;
+	void		*data;
+
+	int		(*init)		  (struct omapfb_device *fbdev,
+					   int ext_mode, int req_vram_size);
+	void		(*cleanup)	  (void);
+	void		(*get_vram_layout)(unsigned long *size,
+					   void **virt_base,
+					   dma_addr_t *phys_base);
+	unsigned long	(*get_caps)	  (void);
+	int		(*set_update_mode)(enum omapfb_update_mode mode);
+	enum omapfb_update_mode (*get_update_mode)(void);
+	int		(*setup_plane)	  (int plane, int channel_out,
+					   unsigned long offset,
+					   int screen_width,
+					   int pos_x, int pos_y, int width,
+					   int height, int color_mode);
+	int		(*enable_plane)	  (int plane, int enable);
+	int		(*update_window)  (struct omapfb_update_window *win,
+					   void (*callback)(void *),
+					   void *callback_data);
+	void		(*sync)		  (void);
+	void		(*suspend)	  (void);
+	void		(*resume)	  (void);
+	int		(*run_test)	  (int test_num);
+	int		(*setcolreg)	  (u_int regno, u16 red, u16 green,
+					   u16 blue, u16 transp,
+					   int update_hw_mem);
+	int		(*set_color_key)  (struct omapfb_color_key *ck);
+
+};
+
+enum omapfb_state {
+	OMAPFB_DISABLED	= 0,
+	OMAPFB_SUSPENDED= 99,
+	OMAPFB_ACTIVE	= 100
+};
+
+struct omapfb_device {
+	int			state;
+	int                     ext_lcdc;               /* Using external
+                                                           LCD controller */
+	struct semaphore	rqueue_sema;
+
+	void			*vram_virt_base;
+	dma_addr_t		vram_phys_base;
+	unsigned long		vram_size;
+
+	int			color_mode;
+	int			palette_size;
+	int			mirror;
+	u32			pseudo_palette[17];
+
+	struct lcd_panel	*panel;			/* LCD panel */
+	struct lcd_ctrl         *ctrl;			/* LCD controller */
+	struct lcd_ctrl		*int_ctrl;		/* internal LCD ctrl */
+	struct lcd_ctrl_extif	*ext_if;		/* LCD ctrl external
+							   interface */
+	struct fb_info		*fb_info;
+
+	struct device		*dev;
+};
+
+extern struct lcd_panel h3_panel;
+extern struct lcd_panel h2_panel;
+extern struct lcd_panel p2_panel;
+extern struct lcd_panel osk_panel;
+extern struct lcd_panel innovator1610_panel;
+extern struct lcd_panel innovator1510_panel;
+
+#ifdef CONFIG_ARCH_OMAP1
+extern struct lcd_ctrl omap1_lcd_ctrl;
+#else
+extern struct lcd_ctrl omap2_disp_ctrl;
+#endif
+
+extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
+
+#endif /* __KERNEL__ */
+
+#endif /* __OMAPFB_H */
diff --git a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h
index fbd742d..7c79042 100644
--- a/include/asm-arm/arch-omap/pm.h
+++ b/include/asm-arm/arch-omap/pm.h
@@ -98,7 +98,14 @@
 #define OMAP1610_IDLECT3		0xfffece24
 #define OMAP1610_IDLE_LOOP_REQUEST	0x0400
 
-#if     !defined(CONFIG_ARCH_OMAP1510) && \
+#define OMAP730_IDLECT1_SLEEP_VAL	0x16c7
+#define OMAP730_IDLECT2_SLEEP_VAL	0x09c7
+#define OMAP730_IDLECT3_VAL		0x3f
+#define OMAP730_IDLECT3		0xfffece24
+#define OMAP730_IDLE_LOOP_REQUEST	0x0C00
+
+#if     !defined(CONFIG_ARCH_OMAP730) && \
+	!defined(CONFIG_ARCH_OMAP15XX) && \
 	!defined(CONFIG_ARCH_OMAP16XX) && \
 	!defined(CONFIG_ARCH_OMAP24XX)
 #error "Power management for this processor not implemented yet"
@@ -107,8 +114,10 @@
 #ifndef __ASSEMBLER__
 extern void omap_pm_idle(void);
 extern void omap_pm_suspend(void);
+extern void omap730_cpu_suspend(unsigned short, unsigned short);
 extern void omap1510_cpu_suspend(unsigned short, unsigned short);
 extern void omap1610_cpu_suspend(unsigned short, unsigned short);
+extern void omap730_idle_loop_suspend(void);
 extern void omap1510_idle_loop_suspend(void);
 extern void omap1610_idle_loop_suspend(void);
 
@@ -118,6 +127,8 @@
 #define omap_serial_wake_trigger(x)	{}
 #endif	/* CONFIG_OMAP_SERIAL_WAKE */
 
+extern unsigned int omap730_cpu_suspend_sz;
+extern unsigned int omap730_idle_loop_suspend_sz;
 extern unsigned int omap1510_cpu_suspend_sz;
 extern unsigned int omap1510_idle_loop_suspend_sz;
 extern unsigned int omap1610_cpu_suspend_sz;
@@ -131,6 +142,10 @@
 #define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
 #define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
 
+#define MPUI730_SAVE(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x] = omap_readl(x)
+#define MPUI730_RESTORE(x) omap_writel((mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]), (x))
+#define MPUI730_SHOW(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]
+
 #define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x)
 #define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x))
 #define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]
@@ -188,13 +203,34 @@
 	MPUI1510_SLEEP_SAVE_EMIFS_CONFIG,
 	MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR,
 	MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR,
-#if defined(CONFIG_ARCH_OMAP1510)
+#if defined(CONFIG_ARCH_OMAP15XX)
 	MPUI1510_SLEEP_SAVE_SIZE
 #else
 	MPUI1510_SLEEP_SAVE_SIZE = 0
 #endif
 };
 
+enum mpui730_save_state {
+	MPUI730_SLEEP_SAVE_START = 0,
+	/*
+	 * MPUI registers 32 bits
+	 */
+	MPUI730_SLEEP_SAVE_MPUI_CTRL,
+	MPUI730_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+	MPUI730_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+	MPUI730_SLEEP_SAVE_MPUI_DSP_STATUS,
+	MPUI730_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+	MPUI730_SLEEP_SAVE_EMIFS_CONFIG,
+	MPUI730_SLEEP_SAVE_OMAP_IH1_MIR,
+	MPUI730_SLEEP_SAVE_OMAP_IH2_0_MIR,
+	MPUI730_SLEEP_SAVE_OMAP_IH2_1_MIR,
+#if defined(CONFIG_ARCH_OMAP730)
+	MPUI730_SLEEP_SAVE_SIZE
+#else
+	MPUI730_SLEEP_SAVE_SIZE = 0
+#endif
+};
+
 enum mpui1610_save_state {
 	MPUI1610_SLEEP_SAVE_START = 0,
 	/*
diff --git a/include/asm-arm/arch-omap/prcm.h b/include/asm-arm/arch-omap/prcm.h
new file mode 100644
index 0000000..7b48a5c
--- /dev/null
+++ b/include/asm-arm/arch-omap/prcm.h
@@ -0,0 +1,429 @@
+/*
+ * prcm.h - Access definations for use in OMAP24XX clock and power management
+ *
+ * Copyright (C) 2005 Texas Instruments, 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.
+ *
+ * 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 __ASM_ARM_ARCH_DPM_PRCM_H
+#define __ASM_ARM_ARCH_DPM_PRCM_H
+
+/* SET_PERFORMANCE_LEVEL PARAMETERS */
+#define PRCM_HALF_SPEED 1
+#define PRCM_FULL_SPEED 2
+
+#ifndef __ASSEMBLER__
+
+#define PRCM_REG32(offset)	__REG32(OMAP24XX_PRCM_BASE + (offset))
+
+#define PRCM_REVISION		PRCM_REG32(0x000)
+#define PRCM_SYSCONFIG		PRCM_REG32(0x010)
+#define PRCM_IRQSTATUS_MPU	PRCM_REG32(0x018)
+#define PRCM_IRQENABLE_MPU	PRCM_REG32(0x01C)
+#define PRCM_VOLTCTRL		PRCM_REG32(0x050)
+#define PRCM_VOLTST		PRCM_REG32(0x054)
+#define PRCM_CLKSRC_CTRL	PRCM_REG32(0x060)
+#define PRCM_CLKOUT_CTRL	PRCM_REG32(0x070)
+#define PRCM_CLKEMUL_CTRL	PRCM_REG32(0x078)
+#define PRCM_CLKCFG_CTRL	PRCM_REG32(0x080)
+#define PRCM_CLKCFG_STATUS	PRCM_REG32(0x084)
+#define PRCM_VOLTSETUP		PRCM_REG32(0x090)
+#define PRCM_CLKSSETUP		PRCM_REG32(0x094)
+#define PRCM_POLCTRL		PRCM_REG32(0x098)
+
+/* GENERAL PURPOSE */
+#define GENERAL_PURPOSE1	PRCM_REG32(0x0B0)
+#define GENERAL_PURPOSE2	PRCM_REG32(0x0B4)
+#define GENERAL_PURPOSE3	PRCM_REG32(0x0B8)
+#define GENERAL_PURPOSE4	PRCM_REG32(0x0BC)
+#define GENERAL_PURPOSE5	PRCM_REG32(0x0C0)
+#define GENERAL_PURPOSE6	PRCM_REG32(0x0C4)
+#define GENERAL_PURPOSE7	PRCM_REG32(0x0C8)
+#define GENERAL_PURPOSE8	PRCM_REG32(0x0CC)
+#define GENERAL_PURPOSE9	PRCM_REG32(0x0D0)
+#define GENERAL_PURPOSE10	PRCM_REG32(0x0D4)
+#define GENERAL_PURPOSE11	PRCM_REG32(0x0D8)
+#define GENERAL_PURPOSE12	PRCM_REG32(0x0DC)
+#define GENERAL_PURPOSE13	PRCM_REG32(0x0E0)
+#define GENERAL_PURPOSE14	PRCM_REG32(0x0E4)
+#define GENERAL_PURPOSE15	PRCM_REG32(0x0E8)
+#define GENERAL_PURPOSE16	PRCM_REG32(0x0EC)
+#define GENERAL_PURPOSE17	PRCM_REG32(0x0F0)
+#define GENERAL_PURPOSE18	PRCM_REG32(0x0F4)
+#define GENERAL_PURPOSE19	PRCM_REG32(0x0F8)
+#define GENERAL_PURPOSE20	PRCM_REG32(0x0FC)
+
+/* MPU */
+#define CM_CLKSEL_MPU		PRCM_REG32(0x140)
+#define CM_CLKSTCTRL_MPU	PRCM_REG32(0x148)
+#define RM_RSTST_MPU		PRCM_REG32(0x158)
+#define PM_WKDEP_MPU		PRCM_REG32(0x1C8)
+#define PM_EVGENCTRL_MPU	PRCM_REG32(0x1D4)
+#define PM_EVEGENONTIM_MPU	PRCM_REG32(0x1D8)
+#define PM_EVEGENOFFTIM_MPU	PRCM_REG32(0x1DC)
+#define PM_PWSTCTRL_MPU		PRCM_REG32(0x1E0)
+#define PM_PWSTST_MPU		PRCM_REG32(0x1E4)
+
+/* CORE */
+#define CM_FCLKEN1_CORE		PRCM_REG32(0x200)
+#define CM_FCLKEN2_CORE		PRCM_REG32(0x204)
+#define CM_FCLKEN3_CORE		PRCM_REG32(0x208)
+#define CM_ICLKEN1_CORE		PRCM_REG32(0x210)
+#define CM_ICLKEN2_CORE		PRCM_REG32(0x214)
+#define CM_ICLKEN3_CORE		PRCM_REG32(0x218)
+#define CM_ICLKEN4_CORE		PRCM_REG32(0x21C)
+#define CM_IDLEST1_CORE		PRCM_REG32(0x220)
+#define CM_IDLEST2_CORE		PRCM_REG32(0x224)
+#define CM_IDLEST3_CORE		PRCM_REG32(0x228)
+#define CM_IDLEST4_CORE		PRCM_REG32(0x22C)
+#define CM_AUTOIDLE1_CORE	PRCM_REG32(0x230)
+#define CM_AUTOIDLE2_CORE	PRCM_REG32(0x234)
+#define CM_AUTOIDLE3_CORE	PRCM_REG32(0x238)
+#define CM_AUTOIDLE4_CORE	PRCM_REG32(0x23C)
+#define CM_CLKSEL1_CORE		PRCM_REG32(0x240)
+#define CM_CLKSEL2_CORE		PRCM_REG32(0x244)
+#define CM_CLKSTCTRL_CORE	PRCM_REG32(0x248)
+#define PM_WKEN1_CORE		PRCM_REG32(0x2A0)
+#define PM_WKEN2_CORE		PRCM_REG32(0x2A4)
+#define PM_WKST1_CORE		PRCM_REG32(0x2B0)
+#define PM_WKST2_CORE		PRCM_REG32(0x2B4)
+#define PM_WKDEP_CORE		PRCM_REG32(0x2C8)
+#define PM_PWSTCTRL_CORE	PRCM_REG32(0x2E0)
+#define PM_PWSTST_CORE		PRCM_REG32(0x2E4)
+
+/* GFX */
+#define CM_FCLKEN_GFX		PRCM_REG32(0x300)
+#define CM_ICLKEN_GFX		PRCM_REG32(0x310)
+#define CM_IDLEST_GFX		PRCM_REG32(0x320)
+#define CM_CLKSEL_GFX		PRCM_REG32(0x340)
+#define CM_CLKSTCTRL_GFX	PRCM_REG32(0x348)
+#define RM_RSTCTRL_GFX		PRCM_REG32(0x350)
+#define RM_RSTST_GFX		PRCM_REG32(0x358)
+#define PM_WKDEP_GFX		PRCM_REG32(0x3C8)
+#define PM_PWSTCTRL_GFX		PRCM_REG32(0x3E0)
+#define PM_PWSTST_GFX		PRCM_REG32(0x3E4)
+
+/* WAKE-UP */
+#define CM_FCLKEN_WKUP		PRCM_REG32(0x400)
+#define CM_ICLKEN_WKUP		PRCM_REG32(0x410)
+#define CM_IDLEST_WKUP		PRCM_REG32(0x420)
+#define CM_AUTOIDLE_WKUP	PRCM_REG32(0x430)
+#define CM_CLKSEL_WKUP		PRCM_REG32(0x440)
+#define RM_RSTCTRL_WKUP		PRCM_REG32(0x450)
+#define RM_RSTTIME_WKUP		PRCM_REG32(0x454)
+#define RM_RSTST_WKUP		PRCM_REG32(0x458)
+#define PM_WKEN_WKUP		PRCM_REG32(0x4A0)
+#define PM_WKST_WKUP		PRCM_REG32(0x4B0)
+
+/* CLOCKS */
+#define CM_CLKEN_PLL		PRCM_REG32(0x500)
+#define CM_IDLEST_CKGEN		PRCM_REG32(0x520)
+#define CM_AUTOIDLE_PLL		PRCM_REG32(0x530)
+#define CM_CLKSEL1_PLL		PRCM_REG32(0x540)
+#define CM_CLKSEL2_PLL		PRCM_REG32(0x544)
+
+/* DSP */
+#define CM_FCLKEN_DSP		PRCM_REG32(0x800)
+#define CM_ICLKEN_DSP		PRCM_REG32(0x810)
+#define CM_IDLEST_DSP		PRCM_REG32(0x820)
+#define CM_AUTOIDLE_DSP		PRCM_REG32(0x830)
+#define CM_CLKSEL_DSP		PRCM_REG32(0x840)
+#define CM_CLKSTCTRL_DSP	PRCM_REG32(0x848)
+#define RM_RSTCTRL_DSP		PRCM_REG32(0x850)
+#define RM_RSTST_DSP		PRCM_REG32(0x858)
+#define PM_WKEN_DSP		PRCM_REG32(0x8A0)
+#define PM_WKDEP_DSP		PRCM_REG32(0x8C8)
+#define PM_PWSTCTRL_DSP		PRCM_REG32(0x8E0)
+#define PM_PWSTST_DSP		PRCM_REG32(0x8E4)
+#define PRCM_IRQSTATUS_DSP	PRCM_REG32(0x8F0)
+#define PRCM_IRQENABLE_DSP	PRCM_REG32(0x8F4)
+
+/* IVA */
+#define PRCM_IRQSTATUS_IVA	PRCM_REG32(0x8F8)
+#define PRCM_IRQENABLE_IVA	PRCM_REG32(0x8FC)
+
+/* Modem on 2430 */
+#define CM_FCLKEN_MDM		PRCM_REG32(0xC00)
+#define CM_ICLKEN_MDM		PRCM_REG32(0xC10)
+#define CM_IDLEST_MDM		PRCM_REG32(0xC20)
+#define CM_CLKSEL_MDM		PRCM_REG32(0xC40)
+
+/* FIXME: Move to header for 2430 */
+#define DISP_BASE		(OMAP24XX_L4_IO_BASE+0x50000)
+#define DISP_REG32(offset)	__REG32(DISP_BASE + (offset))
+
+#define OMAP24XX_GPMC_BASE	(L3_24XX_BASE + 0xa000)
+#define GPMC_BASE		(OMAP24XX_GPMC_BASE)
+#define GPMC_REG32(offset)	__REG32(GPMC_BASE + (offset))
+
+#define GPT1_BASE		(OMAP24XX_GPT1)
+#define GPT1_REG32(offset)	__REG32(GPT1_BASE + (offset))
+
+/* Misc sysconfig */
+#define DISPC_SYSCONFIG		DISP_REG32(0x410)
+#define SPI_BASE		(OMAP24XX_L4_IO_BASE+0x98000)
+#define MCSPI1_SYSCONFIG	__REG32(SPI_BASE + 0x10)
+#define MCSPI2_SYSCONFIG	__REG32(SPI_BASE+0x2000 + 0x10)
+
+//#define DSP_MMU_SYSCONFIG	0x5A000010
+#define CAMERA_MMU_SYSCONFIG	__REG32(DISP_BASE+0x2C10)
+//#define IVA_MMU_SYSCONFIG	0x5D000010
+//#define DSP_DMA_SYSCONFIG	0x00FCC02C
+#define CAMERA_DMA_SYSCONFIG	__REG32(DISP_BASE+0x282C)
+#define SYSTEM_DMA_SYSCONFIG	__REG32(DISP_BASE+0x602C)
+#define GPMC_SYSCONFIG		GPMC_REG32(0x010)
+#define MAILBOXES_SYSCONFIG	__REG32(OMAP24XX_L4_IO_BASE+0x94010)
+#define UART1_SYSCONFIG		__REG32(OMAP24XX_L4_IO_BASE+0x6A054)
+#define UART2_SYSCONFIG		__REG32(OMAP24XX_L4_IO_BASE+0x6C054)
+#define UART3_SYSCONFIG		__REG32(OMAP24XX_L4_IO_BASE+0x6E054)
+//#define IVA_SYSCONFIG		0x5C060010
+#define SDRC_SYSCONFIG		__REG32(OMAP24XX_SDRC_BASE+0x10)
+#define SMS_SYSCONFIG		__REG32(OMAP24XX_SMS_BASE+0x10)
+#define SSI_SYSCONFIG		__REG32(DISP_BASE+0x8010)
+//#define VLYNQ_SYSCONFIG	0x67FFFE10
+
+/* rkw - good cannidates for PM_ to start what nm was trying */
+#define OMAP24XX_GPT2		(OMAP24XX_L4_IO_BASE+0x2A000)
+#define OMAP24XX_GPT3		(OMAP24XX_L4_IO_BASE+0x78000)
+#define OMAP24XX_GPT4		(OMAP24XX_L4_IO_BASE+0x7A000)
+#define OMAP24XX_GPT5		(OMAP24XX_L4_IO_BASE+0x7C000)
+#define OMAP24XX_GPT6		(OMAP24XX_L4_IO_BASE+0x7E000)
+#define OMAP24XX_GPT7		(OMAP24XX_L4_IO_BASE+0x80000)
+#define OMAP24XX_GPT8		(OMAP24XX_L4_IO_BASE+0x82000)
+#define OMAP24XX_GPT9		(OMAP24XX_L4_IO_BASE+0x84000)
+#define OMAP24XX_GPT10		(OMAP24XX_L4_IO_BASE+0x86000)
+#define OMAP24XX_GPT11		(OMAP24XX_L4_IO_BASE+0x88000)
+#define OMAP24XX_GPT12		(OMAP24XX_L4_IO_BASE+0x8A000)
+
+#define GPTIMER1_SYSCONFIG	GPT1_REG32(0x010)
+#define GPTIMER2_SYSCONFIG	__REG32(OMAP24XX_GPT2 + 0x10)
+#define GPTIMER3_SYSCONFIG	__REG32(OMAP24XX_GPT3 + 0x10)
+#define GPTIMER4_SYSCONFIG	__REG32(OMAP24XX_GPT4 + 0x10)
+#define GPTIMER5_SYSCONFIG	__REG32(OMAP24XX_GPT5 + 0x10)
+#define GPTIMER6_SYSCONFIG	__REG32(OMAP24XX_GPT6 + 0x10)
+#define GPTIMER7_SYSCONFIG	__REG32(OMAP24XX_GPT7 + 0x10)
+#define GPTIMER8_SYSCONFIG	__REG32(OMAP24XX_GPT8 + 0x10)
+#define GPTIMER9_SYSCONFIG	__REG32(OMAP24XX_GPT9 + 0x10)
+#define GPTIMER10_SYSCONFIG	__REG32(OMAP24XX_GPT10 + 0x10)
+#define GPTIMER11_SYSCONFIG	__REG32(OMAP24XX_GPT11 + 0x10)
+#define GPTIMER12_SYSCONFIG	__REG32(OMAP24XX_GPT12 + 0x10)
+
+#define GPIOX_BASE(X)		(OMAP24XX_GPIO_BASE+(0x2000*((X)-1)))
+
+#define GPIO1_SYSCONFIG		__REG32((GPIOX_BASE(1)+0x10))
+#define GPIO2_SYSCONFIG		__REG32((GPIOX_BASE(2)+0x10))
+#define GPIO3_SYSCONFIG		__REG32((GPIOX_BASE(3)+0x10))
+#define GPIO4_SYSCONFIG		__REG32((GPIOX_BASE(4)+0x10))
+
+/* GP TIMER 1 */
+#define GPTIMER1_TISTAT		GPT1_REG32(0x014)
+#define GPTIMER1_TISR		GPT1_REG32(0x018)
+#define GPTIMER1_TIER		GPT1_REG32(0x01C)
+#define GPTIMER1_TWER		GPT1_REG32(0x020)
+#define GPTIMER1_TCLR		GPT1_REG32(0x024)
+#define GPTIMER1_TCRR		GPT1_REG32(0x028)
+#define GPTIMER1_TLDR		GPT1_REG32(0x02C)
+#define GPTIMER1_TTGR		GPT1_REG32(0x030)
+#define GPTIMER1_TWPS		GPT1_REG32(0x034)
+#define GPTIMER1_TMAR		GPT1_REG32(0x038)
+#define GPTIMER1_TCAR1		GPT1_REG32(0x03C)
+#define GPTIMER1_TSICR		GPT1_REG32(0x040)
+#define GPTIMER1_TCAR2		GPT1_REG32(0x044)
+
+/* rkw -- base fix up please... */
+#define GPTIMER3_TISR		__REG32(OMAP24XX_L4_IO_BASE+0x78018)
+
+/* SDRC */
+#define SDRC_DLLA_CTRL		__REG32(OMAP24XX_SDRC_BASE+0x060)
+#define SDRC_DLLA_STATUS	__REG32(OMAP24XX_SDRC_BASE+0x064)
+#define SDRC_DLLB_CTRL		__REG32(OMAP24XX_SDRC_BASE+0x068)
+#define SDRC_DLLB_STATUS	__REG32(OMAP24XX_SDRC_BASE+0x06C)
+#define SDRC_POWER		__REG32(OMAP24XX_SDRC_BASE+0x070)
+#define SDRC_MR_0		__REG32(OMAP24XX_SDRC_BASE+0x084)
+
+/* GPIO 1 */
+#define GPIO1_BASE		GPIOX_BASE(1)
+#define GPIO1_REG32(offset)	__REG32(GPIO1_BASE + (offset))
+#define GPIO1_IRQENABLE1	GPIO1_REG32(0x01C)
+#define GPIO1_IRQSTATUS1	GPIO1_REG32(0x018)
+#define GPIO1_IRQENABLE2	GPIO1_REG32(0x02C)
+#define GPIO1_IRQSTATUS2	GPIO1_REG32(0x028)
+#define GPIO1_WAKEUPENABLE	GPIO1_REG32(0x020)
+#define GPIO1_RISINGDETECT	GPIO1_REG32(0x048)
+#define GPIO1_DATAIN		GPIO1_REG32(0x038)
+#define GPIO1_OE		GPIO1_REG32(0x034)
+#define GPIO1_DATAOUT		GPIO1_REG32(0x03C)
+
+/* GPIO2 */
+#define GPIO2_BASE		GPIOX_BASE(2)
+#define GPIO2_REG32(offset)	__REG32(GPIO2_BASE + (offset))
+#define GPIO2_IRQENABLE1	GPIO2_REG32(0x01C)
+#define GPIO2_IRQSTATUS1	GPIO2_REG32(0x018)
+#define GPIO2_IRQENABLE2	GPIO2_REG32(0x02C)
+#define GPIO2_IRQSTATUS2	GPIO2_REG32(0x028)
+#define GPIO2_WAKEUPENABLE	GPIO2_REG32(0x020)
+#define GPIO2_RISINGDETECT	GPIO2_REG32(0x048)
+#define GPIO2_DATAIN		GPIO2_REG32(0x038)
+#define GPIO2_OE		GPIO2_REG32(0x034)
+#define GPIO2_DATAOUT		GPIO2_REG32(0x03C)
+
+/* GPIO 3 */
+#define GPIO3_BASE		GPIOX_BASE(3)
+#define GPIO3_REG32(offset)	__REG32(GPIO3_BASE + (offset))
+#define GPIO3_IRQENABLE1	GPIO3_REG32(0x01C)
+#define GPIO3_IRQSTATUS1	GPIO3_REG32(0x018)
+#define GPIO3_IRQENABLE2	GPIO3_REG32(0x02C)
+#define GPIO3_IRQSTATUS2	GPIO3_REG32(0x028)
+#define GPIO3_WAKEUPENABLE	GPIO3_REG32(0x020)
+#define GPIO3_RISINGDETECT	GPIO3_REG32(0x048)
+#define GPIO3_FALLINGDETECT	GPIO3_REG32(0x04C)
+#define GPIO3_DATAIN		GPIO3_REG32(0x038)
+#define GPIO3_OE		GPIO3_REG32(0x034)
+#define GPIO3_DATAOUT		GPIO3_REG32(0x03C)
+#define GPIO3_DEBOUNCENABLE	GPIO3_REG32(0x050)
+#define GPIO3_DEBOUNCINGTIME	GPIO3_REG32(0x054)
+
+/* GPIO 4 */
+#define GPIO4_BASE		GPIOX_BASE(4)
+#define GPIO4_REG32(offset)	__REG32(GPIO4_BASE + (offset))
+#define GPIO4_IRQENABLE1	GPIO4_REG32(0x01C)
+#define GPIO4_IRQSTATUS1	GPIO4_REG32(0x018)
+#define GPIO4_IRQENABLE2	GPIO4_REG32(0x02C)
+#define GPIO4_IRQSTATUS2	GPIO4_REG32(0x028)
+#define GPIO4_WAKEUPENABLE	GPIO4_REG32(0x020)
+#define GPIO4_RISINGDETECT	GPIO4_REG32(0x048)
+#define GPIO4_FALLINGDETECT	GPIO4_REG32(0x04C)
+#define GPIO4_DATAIN		GPIO4_REG32(0x038)
+#define GPIO4_OE		GPIO4_REG32(0x034)
+#define GPIO4_DATAOUT		GPIO4_REG32(0x03C)
+#define GPIO4_DEBOUNCENABLE	GPIO4_REG32(0x050)
+#define GPIO4_DEBOUNCINGTIME	GPIO4_REG32(0x054)
+
+
+/* IO CONFIG */
+#define CONTROL_BASE		(OMAP24XX_CTRL_BASE)
+#define CONTROL_REG32(offset)	__REG32(CONTROL_BASE + (offset))
+
+#define CONTROL_PADCONF_SPI1_NCS2	CONTROL_REG32(0x104)
+#define CONTROL_PADCONF_SYS_XTALOUT	CONTROL_REG32(0x134)
+#define CONTROL_PADCONF_UART1_RX	CONTROL_REG32(0x0C8)
+#define CONTROL_PADCONF_MCBSP1_DX	CONTROL_REG32(0x10C)
+#define CONTROL_PADCONF_GPMC_NCS4	CONTROL_REG32(0x090)
+#define CONTROL_PADCONF_DSS_D5		CONTROL_REG32(0x0B8)
+#define CONTROL_PADCONF_DSS_D9		CONTROL_REG32(0x0BC)
+#define CONTROL_PADCONF_DSS_D13		CONTROL_REG32(0x0C0)
+#define CONTROL_PADCONF_DSS_VSYNC	CONTROL_REG32(0x0CC)
+
+/* CONTROL */
+#define CONTROL_DEVCONF		CONTROL_REG32(0x274)
+
+/* INTERRUPT CONTROLLER */
+#define INTC_BASE		(OMAP24XX_L4_IO_BASE+0xfe000)
+#define INTC_REG32(offset)	__REG32(INTC_BASE + (offset))
+
+#define INTC1_U_BASE		INTC_REG32(0x000)
+#define INTC_MIR0		INTC_REG32(0x084)
+#define INTC_MIR_SET0		INTC_REG32(0x08C)
+#define INTC_MIR_CLEAR0		INTC_REG32(0x088)
+#define INTC_ISR_CLEAR0		INTC_REG32(0x094)
+#define INTC_MIR1		INTC_REG32(0x0A4)
+#define INTC_MIR_SET1		INTC_REG32(0x0AC)
+#define INTC_MIR_CLEAR1		INTC_REG32(0x0A8)
+#define INTC_ISR_CLEAR1		INTC_REG32(0x0B4)
+#define INTC_MIR2		INTC_REG32(0x0C4)
+#define INTC_MIR_SET2		INTC_REG32(0x0CC)
+#define INTC_MIR_CLEAR2		INTC_REG32(0x0C8)
+#define INTC_ISR_CLEAR2		INTC_REG32(0x0D4)
+#define INTC_SIR_IRQ		INTC_REG32(0x040)
+#define INTC_CONTROL		INTC_REG32(0x048)
+#define INTC_ILR11		INTC_REG32(0x12C)
+#define INTC_ILR32		INTC_REG32(0x180)
+#define INTC_ILR37		INTC_REG32(0x194)
+#define INTC_SYSCONFIG		INTC_REG32(0x010)
+
+/* RAM FIREWALL */
+#define RAMFW_BASE		(0x68005000)
+#define RAMFW_REG32(offset)	__REG32(RAMFW_BASE + (offset))
+
+#define RAMFW_REQINFOPERM0	RAMFW_REG32(0x048)
+#define RAMFW_READPERM0		RAMFW_REG32(0x050)
+#define RAMFW_WRITEPERM0	RAMFW_REG32(0x058)
+
+/* GPMC CS1 FPGA ON USER INTERFACE MODULE */
+//#define DEBUG_BOARD_LED_REGISTER 0x04000014
+
+/* GPMC CS0 */
+#define GPMC_CONFIG1_0		GPMC_REG32(0x060)
+#define GPMC_CONFIG2_0		GPMC_REG32(0x064)
+#define GPMC_CONFIG3_0		GPMC_REG32(0x068)
+#define GPMC_CONFIG4_0		GPMC_REG32(0x06C)
+#define GPMC_CONFIG5_0		GPMC_REG32(0x070)
+#define GPMC_CONFIG6_0		GPMC_REG32(0x074)
+#define GPMC_CONFIG7_0		GPMC_REG32(0x078)
+
+/* GPMC CS1 */
+#define GPMC_CONFIG1_1		GPMC_REG32(0x090)
+#define GPMC_CONFIG2_1		GPMC_REG32(0x094)
+#define GPMC_CONFIG3_1		GPMC_REG32(0x098)
+#define GPMC_CONFIG4_1		GPMC_REG32(0x09C)
+#define GPMC_CONFIG5_1		GPMC_REG32(0x0a0)
+#define GPMC_CONFIG6_1		GPMC_REG32(0x0a4)
+#define GPMC_CONFIG7_1		GPMC_REG32(0x0a8)
+
+/* DSS */
+#define DSS_CONTROL		DISP_REG32(0x040)
+#define DISPC_CONTROL		DISP_REG32(0x440)
+#define DISPC_SYSSTATUS		DISP_REG32(0x414)
+#define DISPC_IRQSTATUS		DISP_REG32(0x418)
+#define DISPC_IRQENABLE		DISP_REG32(0x41C)
+#define DISPC_CONFIG		DISP_REG32(0x444)
+#define DISPC_DEFAULT_COLOR0	DISP_REG32(0x44C)
+#define DISPC_DEFAULT_COLOR1	DISP_REG32(0x450)
+#define DISPC_TRANS_COLOR0	DISP_REG32(0x454)
+#define DISPC_TRANS_COLOR1	DISP_REG32(0x458)
+#define DISPC_LINE_NUMBER	DISP_REG32(0x460)
+#define DISPC_TIMING_H		DISP_REG32(0x464)
+#define DISPC_TIMING_V		DISP_REG32(0x468)
+#define DISPC_POL_FREQ		DISP_REG32(0x46C)
+#define DISPC_DIVISOR		DISP_REG32(0x470)
+#define DISPC_SIZE_DIG		DISP_REG32(0x478)
+#define DISPC_SIZE_LCD		DISP_REG32(0x47C)
+#define DISPC_GFX_BA0		DISP_REG32(0x480)
+#define DISPC_GFX_BA1		DISP_REG32(0x484)
+#define DISPC_GFX_POSITION	DISP_REG32(0x488)
+#define DISPC_GFX_SIZE		DISP_REG32(0x48C)
+#define DISPC_GFX_ATTRIBUTES	DISP_REG32(0x4A0)
+#define DISPC_GFX_FIFO_THRESHOLD	DISP_REG32(0x4A4)
+#define DISPC_GFX_ROW_INC	DISP_REG32(0x4AC)
+#define DISPC_GFX_PIXEL_INC	DISP_REG32(0x4B0)
+#define DISPC_GFX_WINDOW_SKIP	DISP_REG32(0x4B4)
+#define DISPC_GFX_TABLE_BA	DISP_REG32(0x4B8)
+#define DISPC_DATA_CYCLE1	DISP_REG32(0x5D4)
+#define DISPC_DATA_CYCLE2	DISP_REG32(0x5D8)
+#define DISPC_DATA_CYCLE3	DISP_REG32(0x5DC)
+
+/* Wake up define for board */
+#define GPIO97			(1 << 1)
+#define GPIO88			(1 << 24)
+
+#endif /* __ASSEMBLER__ */
+
+#endif
+
+
+
+
+
diff --git a/include/asm-arm/arch-omap/sram.h b/include/asm-arm/arch-omap/sram.h
new file mode 100644
index 0000000..e72ccbf
--- /dev/null
+++ b/include/asm-arm/arch-omap/sram.h
@@ -0,0 +1,38 @@
+/*
+ * linux/include/asm-arm/arch-omap/sram.h
+ *
+ * Interface for functions that need to be run in internal SRAM
+ *
+ * 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 __ARCH_ARM_OMAP_SRAM_H
+#define __ARCH_ARM_OMAP_SRAM_H
+
+extern void * omap_sram_push(void * start, unsigned long size);
+extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
+
+extern void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
+				u32 base_cs, u32 force_unlock);
+extern void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
+				      u32 mem_type);
+extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
+
+
+/* Do not use these */
+extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
+extern unsigned long sram_reprogram_clock_sz;
+
+extern void sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
+			  u32 base_cs, u32 force_unlock);
+extern unsigned long sram_ddr_init_sz;
+
+extern u32 sram_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
+extern unsigned long sram_set_prcm_sz;
+
+extern void sram_reprogram_sdrc(u32 perf_level, u32 dll_val, u32 mem_type);
+extern unsigned long sram_reprogram_sdrc_sz;
+
+#endif
diff --git a/include/asm-arm/arch-omap/system.h b/include/asm-arm/arch-omap/system.h
index ff37bc2..b43cdd2 100644
--- a/include/asm-arm/arch-omap/system.h
+++ b/include/asm-arm/arch-omap/system.h
@@ -6,18 +6,21 @@
 #define __ASM_ARCH_SYSTEM_H
 #include <linux/config.h>
 #include <asm/mach-types.h>
+#include <asm/hardware/clock.h>
 #include <asm/arch/hardware.h>
-#include <asm/mach-types.h>
+#include <asm/arch/prcm.h>
+
+#ifndef CONFIG_MACH_VOICEBLUE
+#define voiceblue_reset()		do {} while (0)
+#endif
 
 static inline void arch_idle(void)
 {
 	cpu_do_idle();
 }
 
-static inline void arch_reset(char mode)
+static inline void omap1_arch_reset(char mode)
 {
-
-#ifdef CONFIG_ARCH_OMAP16XX
 	/*
 	 * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
 	 * "Global Software Reset Affects Traffic Controller Frequency".
@@ -27,13 +30,31 @@
 				 DPLL_CTL);
 		omap_writew(0x8, ARM_RSTCT1);
 	}
-#endif
-#ifdef CONFIG_MACH_VOICEBLUE
+
 	if (machine_is_voiceblue())
 		voiceblue_reset();
 	else
-#endif
 		omap_writew(1, ARM_RSTCT1);
 }
 
+static inline void omap2_arch_reset(char mode)
+{
+	u32 rate;
+	struct clk *vclk, *sclk;
+
+	vclk = clk_get(NULL, "virt_prcm_set");
+	sclk = clk_get(NULL, "sys_ck");
+	rate = clk_get_rate(sclk);
+	clk_set_rate(vclk, rate);	/* go to bypass for OMAP limitation */
+	RM_RSTCTRL_WKUP |= 2;
+}
+
+static inline void arch_reset(char mode)
+{
+	if (!cpu_is_omap24xx())
+		omap1_arch_reset(mode);
+	else
+		omap2_arch_reset(mode);
+}
+
 #endif
diff --git a/include/asm-arm/arch-omap/timex.h b/include/asm-arm/arch-omap/timex.h
index b61ddb4..21f2e36 100644
--- a/include/asm-arm/arch-omap/timex.h
+++ b/include/asm-arm/arch-omap/timex.h
@@ -28,6 +28,14 @@
 #if !defined(__ASM_ARCH_OMAP_TIMEX_H)
 #define __ASM_ARCH_OMAP_TIMEX_H
 
+/*
+ * OMAP 32KHz timer updates time one jiffie at a time from a secondary timer,
+ * and that's why the CLOCK_TICK_RATE is not 32768.
+ */
+#ifdef CONFIG_OMAP_32K_TIMER
+#define CLOCK_TICK_RATE		(CONFIG_OMAP_32K_TIMER_HZ)
+#else
 #define CLOCK_TICK_RATE		(HZ * 100000UL)
+#endif
 
 #endif /* __ASM_ARCH_OMAP_TIMEX_H */
diff --git a/include/asm-arm/arch-omap/uncompress.h b/include/asm-arm/arch-omap/uncompress.h
index 3545c86..c718264 100644
--- a/include/asm-arm/arch-omap/uncompress.h
+++ b/include/asm-arm/arch-omap/uncompress.h
@@ -36,10 +36,14 @@
 	volatile u8 * uart = 0;
 	int shift = 2;
 
+#ifdef CONFIG_MACH_OMAP_PALMTE
+	return;
+#endif
+
 #ifdef CONFIG_ARCH_OMAP
 #ifdef	CONFIG_OMAP_LL_DEBUG_UART3
 	uart = (volatile u8 *)(OMAP_UART3_BASE);
-#elif	CONFIG_OMAP_LL_DEBUG_UART2
+#elif defined(CONFIG_OMAP_LL_DEBUG_UART2)
 	uart = (volatile u8 *)(OMAP_UART2_BASE);
 #else
 	uart = (volatile u8 *)(OMAP_UART1_BASE);
diff --git a/include/asm-arm/arch-pxa/sharpsl.h b/include/asm-arm/arch-pxa/sharpsl.h
index 311f2bb..0b43495 100644
--- a/include/asm-arm/arch-pxa/sharpsl.h
+++ b/include/asm-arm/arch-pxa/sharpsl.h
@@ -21,12 +21,18 @@
 	void (*wait_hsync)(void);
 };
 
+
 /*
  * SharpSL Backlight
  */
-
 struct corgibl_machinfo {
 	int max_intensity;
 	void (*set_bl_intensity)(int intensity);
 };
+extern void corgibl_limit_intensity(int limit);
 
+
+/*
+ * SharpSL Battery/PM Driver
+ */
+extern void sharpsl_battery_kick(void);
diff --git a/include/asm-arm/arch-pxa/ssp.h b/include/asm-arm/arch-pxa/ssp.h
index 6ec67b0..949878c 100644
--- a/include/asm-arm/arch-pxa/ssp.h
+++ b/include/asm-arm/arch-pxa/ssp.h
@@ -18,6 +18,11 @@
 #ifndef SSP_H
 #define SSP_H
 
+/*
+ * SSP initialisation flags
+ */
+#define SSP_NO_IRQ	0x1		/* don't register an irq handler in SSP driver */
+
 struct ssp_state {
 	u32	cr0;
 	u32 cr1;
@@ -31,6 +36,7 @@
 	u32 flags;
 	u32 psp_flags;
 	u32 speed;
+	int irq;
 };
 
 int ssp_write_word(struct ssp_dev *dev, u32 data);
@@ -40,7 +46,7 @@
 void ssp_disable(struct ssp_dev *dev);
 void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp);
 void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp);
-int ssp_init(struct ssp_dev *dev, u32 port);
+int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags);
 int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed);
 void ssp_exit(struct ssp_dev *dev);
 
diff --git a/include/asm-arm/arch-realview/entry-macro.S b/include/asm-arm/arch-realview/entry-macro.S
index 4df469b..6288fad 100644
--- a/include/asm-arm/arch-realview/entry-macro.S
+++ b/include/asm-arm/arch-realview/entry-macro.S
@@ -61,3 +61,14 @@
 		strcc	\irqstat, [\base, #GIC_CPU_EOI]
 		cmpcs	\irqnr, \irqnr
 		.endm
+
+		/* As above, this assumes that irqstat and base are preserved.. */
+
+		.macro test_for_ltirq, irqnr, irqstat, base, tmp
+		bic	\irqnr, \irqstat, #0x1c00
+		mov 	\tmp, #0
+		cmp	\irqnr, #29
+		moveq	\tmp, #1
+		streq	\irqstat, [\base, #GIC_CPU_EOI]
+		cmp	\tmp, #0
+		.endm
diff --git a/include/asm-arm/arch-realview/irqs.h b/include/asm-arm/arch-realview/irqs.h
index ff37649..c16223c 100644
--- a/include/asm-arm/arch-realview/irqs.h
+++ b/include/asm-arm/arch-realview/irqs.h
@@ -21,6 +21,9 @@
 
 #include <asm/arch/platform.h>
 
+#define IRQ_LOCALTIMER			29
+#define IRQ_LOCALWDOG			30
+
 /* 
  *  IRQ interrupts definitions are the same the INT definitions
  *  held within platform.h
diff --git a/include/asm-arm/arch-realview/platform.h b/include/asm-arm/arch-realview/platform.h
index aef9b36..18d7c18 100644
--- a/include/asm-arm/arch-realview/platform.h
+++ b/include/asm-arm/arch-realview/platform.h
@@ -209,6 +209,8 @@
 #else
 #define REALVIEW_MPCORE_SCU_BASE	0x10100000	/*  SCU registers */
 #define REALVIEW_GIC_CPU_BASE		0x10100100	/* Generic interrupt controller CPU interface */
+#define REALVIEW_TWD_BASE		0x10100700
+#define REALVIEW_TWD_SIZE		0x00000100
 #define REALVIEW_GIC_DIST_BASE		0x10101000	/* Generic interrupt controller distributor */
 #endif
 #define REALVIEW_SMC_BASE             0x10080000	/* SMC */
@@ -305,9 +307,6 @@
 #define INT_TSPENINT			30	/* Touchscreen pen */
 #define INT_TSKPADINT			31	/* Touchscreen keypad */
 #else
-#define INT_LOCALTIMER			29
-#define INT_LOCALWDOG			30
-
 #define INT_AACI			0
 #define INT_TIMERINT0_1			1
 #define INT_TIMERINT2_3			2
diff --git a/include/asm-arm/arch-s3c2410/uncompress.h b/include/asm-arm/arch-s3c2410/uncompress.h
index d7a4a83..ddd1578 100644
--- a/include/asm-arm/arch-s3c2410/uncompress.h
+++ b/include/asm-arm/arch-s3c2410/uncompress.h
@@ -116,6 +116,8 @@
 	}
 }
 
+#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0)
+
 /* CONFIG_S3C2410_BOOT_WATCHDOG
  *
  * Simple boot-time watchdog setup, to reboot the system if there is
@@ -126,8 +128,6 @@
 
 #define WDOG_COUNT (0xff00)
 
-#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0)
-
 static inline void arch_decomp_wdog(void)
 {
 	__raw_writel(WDOG_COUNT, S3C2410_WTCNT);
@@ -145,6 +145,24 @@
 #define arch_decomp_wdog()
 #endif
 
+#ifdef CONFIG_S3C2410_BOOT_ERROR_RESET
+
+static void arch_decomp_error(const char *x)
+{
+	putstr("\n\n");
+	putstr(x);
+	putstr("\n\n -- System resetting\n");
+
+	__raw_writel(0x4000, S3C2410_WTDAT);
+	__raw_writel(0x4000, S3C2410_WTCNT);
+	__raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
+
+	while(1);
+}
+
+#define arch_error arch_decomp_error
+#endif
+
 static void error(char *err);
 
 static void
diff --git a/include/asm-arm/assembler.h b/include/asm-arm/assembler.h
index 69a28f9..f31ac92 100644
--- a/include/asm-arm/assembler.h
+++ b/include/asm-arm/assembler.h
@@ -83,10 +83,13 @@
  * Save the current IRQ state and disable IRQs.  Note that this macro
  * assumes FIQs are enabled, and that the processor is in SVC mode.
  */
-	.macro	save_and_disable_irqs, oldcpsr, temp
+	.macro	save_and_disable_irqs, oldcpsr
 	mrs	\oldcpsr, cpsr
-	mov	\temp, #PSR_I_BIT | MODE_SVC
-	msr	cpsr_c, \temp
+#if __LINUX_ARM_ARCH__ >= 6
+	cpsid	i
+#else
+	msr	cpsr_c, #PSR_I_BIT | MODE_SVC
+#endif
 	.endm
 
 /*
diff --git a/include/asm-arm/hardirq.h b/include/asm-arm/hardirq.h
index e5ccb6b..1cbb173 100644
--- a/include/asm-arm/hardirq.h
+++ b/include/asm-arm/hardirq.h
@@ -8,6 +8,7 @@
 
 typedef struct {
 	unsigned int __softirq_pending;
+	unsigned int local_timer_irqs;
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
diff --git a/include/asm-arm/hardware/scoop.h b/include/asm-arm/hardware/scoop.h
index a8f1013..d37bf74 100644
--- a/include/asm-arm/hardware/scoop.h
+++ b/include/asm-arm/hardware/scoop.h
@@ -52,8 +52,14 @@
 	unsigned char keep_rd;
 };
 
-extern int scoop_num;
-extern struct scoop_pcmcia_dev *scoop_devs;
+struct scoop_pcmcia_config {
+	struct scoop_pcmcia_dev *devs;
+	int num_devs;
+	void (*pcmcia_init)(void);
+	void (*power_ctrl)(struct device *scoop, unsigned short cpr, int nr);
+};
+
+extern struct scoop_pcmcia_config *platform_scoop_config;
 
 void reset_scoop(struct device *dev);
 unsigned short set_scoop_gpio(struct device *dev, unsigned short bit);
diff --git a/include/asm-arm/mach/flash.h b/include/asm-arm/mach/flash.h
index cd57436..05b029e 100644
--- a/include/asm-arm/mach/flash.h
+++ b/include/asm-arm/mach/flash.h
@@ -11,6 +11,7 @@
 #define ASMARM_MACH_FLASH_H
 
 struct mtd_partition;
+struct mtd_info;
 
 /*
  * map_name:	the map probe function name
@@ -19,6 +20,7 @@
  * init:	method called at driver/device initialisation
  * exit:	method called at driver/device removal
  * set_vpp:	method called to enable or disable VPP
+ * mmcontrol:	method called to enable or disable Sync. Burst Read in OneNAND
  * parts:	optional array of mtd_partitions for static partitioning
  * nr_parts:	number of mtd_partitions for static partitoning
  */
@@ -29,6 +31,7 @@
 	int		(*init)(void);
 	void		(*exit)(void);
 	void		(*set_vpp)(int on);
+	void		(*mmcontrol)(struct mtd_info *mtd, int sync_read);
 	struct mtd_partition *parts;
 	unsigned int	nr_parts;
 };
diff --git a/include/asm-arm/smp.h b/include/asm-arm/smp.h
index 551cd3c..5a72e50 100644
--- a/include/asm-arm/smp.h
+++ b/include/asm-arm/smp.h
@@ -37,6 +37,11 @@
 extern void show_ipi_list(struct seq_file *p);
 
 /*
+ * Called from assembly code, this handles an IPI.
+ */
+asmlinkage void do_IPI(struct pt_regs *regs);
+
+/*
  * Move global data into per-processor storage.
  */
 extern void smp_store_cpu_info(unsigned int cpuid);
@@ -47,12 +52,23 @@
 extern void smp_cross_call(cpumask_t callmap);
 
 /*
+ * Broadcast a timer interrupt to the other CPUs.
+ */
+extern void smp_send_timer(void);
+
+/*
  * Boot a secondary CPU, and assign it the specified idle task.
  * This also gives us the initial stack to use for this CPU.
  */
 extern int boot_secondary(unsigned int cpu, struct task_struct *);
 
 /*
+ * Called from platform specific assembly code, this is the
+ * secondary CPU entry point.
+ */
+asmlinkage void secondary_start_kernel(void);
+
+/*
  * Perform platform specific initialisation of the specified CPU.
  */
 extern void platform_secondary_init(unsigned int cpu);
@@ -76,4 +92,42 @@
 extern int platform_cpu_kill(unsigned int cpu);
 extern void platform_cpu_enable(unsigned int cpu);
 
+#ifdef CONFIG_LOCAL_TIMERS
+/*
+ * Setup a local timer interrupt for a CPU.
+ */
+extern void local_timer_setup(unsigned int cpu);
+
+/*
+ * Stop a local timer interrupt.
+ */
+extern void local_timer_stop(unsigned int cpu);
+
+/*
+ * Platform provides this to acknowledge a local timer IRQ
+ */
+extern int local_timer_ack(void);
+
+#else
+
+static inline void local_timer_setup(unsigned int cpu)
+{
+}
+
+static inline void local_timer_stop(unsigned int cpu)
+{
+}
+
+#endif
+
+/*
+ * show local interrupt info
+ */
+extern void show_local_irqs(struct seq_file *);
+
+/*
+ * Called from assembly, this is the local timer IRQ handler
+ */
+asmlinkage void do_local_timer(struct pt_regs *);
+
 #endif /* ifndef __ASM_ARM_SMP_H */
diff --git a/include/asm-i386/ide.h b/include/asm-i386/ide.h
index 79dfab8..4544401 100644
--- a/include/asm-i386/ide.h
+++ b/include/asm-i386/ide.h
@@ -41,6 +41,12 @@
 
 static __inline__ unsigned long ide_default_io_base(int index)
 {
+	/*
+	 *	If PCI is present then it is not safe to poke around
+	 *	the other legacy IDE ports. Only 0x1f0 and 0x170 are
+	 *	defined compatibility mode ports for PCI. A user can 
+	 *	override this using ide= but we must default safe.
+	 */
 	if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) {
 		switch(index) {
 			case 2: return 0x1e8;
diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h
index b853930..f041d44 100644
--- a/include/asm-i386/msi.h
+++ b/include/asm-i386/msi.h
@@ -10,13 +10,6 @@
 #include <mach_apic.h>
 
 #define LAST_DEVICE_VECTOR		232
-#define MSI_DEST_MODE			MSI_LOGICAL_MODE
-#define MSI_TARGET_CPU_SHIFT		12
-
-#ifdef CONFIG_SMP
-#define MSI_TARGET_CPU		logical_smp_processor_id()
-#else
-#define MSI_TARGET_CPU	cpu_to_logical_apicid(first_cpu(cpu_online_map))
-#endif
+#define MSI_TARGET_CPU_SHIFT	12
 
 #endif /* ASM_MSI_H */
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 1325019..61d3ab9 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -45,6 +45,8 @@
 #define MAX_APICID 256
 extern u8 x86_cpu_to_apicid[];
 
+#define cpu_physical_id(cpu)	x86_cpu_to_apicid[cpu]
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern void cpu_exit_clear(void);
 extern void cpu_uninit(void);
@@ -92,6 +94,10 @@
 extern void __cpu_die(unsigned int cpu);
 #endif /* !__ASSEMBLY__ */
 
+#else /* CONFIG_SMP */
+
+#define cpu_physical_id(cpu)		boot_cpu_physical_apicid
+
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
 #endif
diff --git a/include/asm-ia64/kdebug.h b/include/asm-ia64/kdebug.h
index 4d376e1..8b01a08 100644
--- a/include/asm-ia64/kdebug.h
+++ b/include/asm-ia64/kdebug.h
@@ -22,6 +22,9 @@
  * 2005-Apr     Rusty Lynch <rusty.lynch@intel.com> and Anil S Keshavamurthy
  *              <anil.s.keshavamurthy@intel.com> adopted from
  *              include/asm-x86_64/kdebug.h
+ *
+ * 2005-Oct	Keith Owens <kaos@sgi.com>.  Expand notify_die to cover more
+ *		events.
  */
 #include <linux/notifier.h>
 
@@ -35,13 +38,36 @@
 	int signr;
 };
 
-int register_die_notifier(struct notifier_block *nb);
+extern int register_die_notifier(struct notifier_block *);
+extern int unregister_die_notifier(struct notifier_block *);
 extern struct notifier_block *ia64die_chain;
 
 enum die_val {
 	DIE_BREAK = 1,
-	DIE_SS,
+	DIE_FAULT,
+	DIE_OOPS,
 	DIE_PAGE_FAULT,
+	DIE_MACHINE_HALT,
+	DIE_MACHINE_RESTART,
+	DIE_MCA_MONARCH_ENTER,
+	DIE_MCA_MONARCH_PROCESS,
+	DIE_MCA_MONARCH_LEAVE,
+	DIE_MCA_SLAVE_ENTER,
+	DIE_MCA_SLAVE_PROCESS,
+	DIE_MCA_SLAVE_LEAVE,
+	DIE_MCA_RENDZVOUS_ENTER,
+	DIE_MCA_RENDZVOUS_PROCESS,
+	DIE_MCA_RENDZVOUS_LEAVE,
+	DIE_INIT_MONARCH_ENTER,
+	DIE_INIT_MONARCH_PROCESS,
+	DIE_INIT_MONARCH_LEAVE,
+	DIE_INIT_SLAVE_ENTER,
+	DIE_INIT_SLAVE_PROCESS,
+	DIE_INIT_SLAVE_LEAVE,
+	DIE_KDEBUG_ENTER,
+	DIE_KDEBUG_LEAVE,
+	DIE_KDUMP_ENTER,
+	DIE_KDUMP_LEAVE,
 };
 
 static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs,
diff --git a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h
index 8d6e72f..b5c6508 100644
--- a/include/asm-ia64/mmu_context.h
+++ b/include/asm-ia64/mmu_context.h
@@ -7,12 +7,13 @@
  */
 
 /*
- * Routines to manage the allocation of task context numbers.  Task context numbers are
- * used to reduce or eliminate the need to perform TLB flushes due to context switches.
- * Context numbers are implemented using ia-64 region ids.  Since the IA-64 TLB does not
- * consider the region number when performing a TLB lookup, we need to assign a unique
- * region id to each region in a process.  We use the least significant three bits in a
- * region id for this purpose.
+ * Routines to manage the allocation of task context numbers.  Task context
+ * numbers are used to reduce or eliminate the need to perform TLB flushes
+ * due to context switches.  Context numbers are implemented using ia-64
+ * region ids.  Since the IA-64 TLB does not consider the region number when
+ * performing a TLB lookup, we need to assign a unique region id to each
+ * region in a process.  We use the least significant three bits in aregion
+ * id for this purpose.
  */
 
 #define IA64_REGION_ID_KERNEL	0 /* the kernel's region id (tlb.c depends on this being 0) */
@@ -32,13 +33,17 @@
 struct ia64_ctx {
 	spinlock_t lock;
 	unsigned int next;	/* next context number to use */
-	unsigned int limit;	/* next >= limit => must call wrap_mmu_context() */
-	unsigned int max_ctx;	/* max. context value supported by all CPUs */
+	unsigned int limit;     /* available free range */
+	unsigned int max_ctx;   /* max. context value supported by all CPUs */
+				/* call wrap_mmu_context when next >= max */
+	unsigned long *bitmap;  /* bitmap size is max_ctx+1 */
+	unsigned long *flushmap;/* pending rid to be flushed */
 };
 
 extern struct ia64_ctx ia64_ctx;
 DECLARE_PER_CPU(u8, ia64_need_tlb_flush);
 
+extern void mmu_context_init (void);
 extern void wrap_mmu_context (struct mm_struct *mm);
 
 static inline void
@@ -47,10 +52,10 @@
 }
 
 /*
- * When the context counter wraps around all TLBs need to be flushed because an old
- * context number might have been reused. This is signalled by the ia64_need_tlb_flush
- * per-CPU variable, which is checked in the routine below. Called by activate_mm().
- * <efocht@ess.nec.de>
+ * When the context counter wraps around all TLBs need to be flushed because
+ * an old context number might have been reused. This is signalled by the
+ * ia64_need_tlb_flush per-CPU variable, which is checked in the routine
+ * below. Called by activate_mm(). <efocht@ess.nec.de>
  */
 static inline void
 delayed_tlb_flush (void)
@@ -60,11 +65,9 @@
 
 	if (unlikely(__ia64_per_cpu_var(ia64_need_tlb_flush))) {
 		spin_lock_irqsave(&ia64_ctx.lock, flags);
-		{
-			if (__ia64_per_cpu_var(ia64_need_tlb_flush)) {
-				local_flush_tlb_all();
-				__ia64_per_cpu_var(ia64_need_tlb_flush) = 0;
-			}
+		if (__ia64_per_cpu_var(ia64_need_tlb_flush)) {
+			local_flush_tlb_all();
+			__ia64_per_cpu_var(ia64_need_tlb_flush) = 0;
 		}
 		spin_unlock_irqrestore(&ia64_ctx.lock, flags);
 	}
@@ -76,20 +79,27 @@
 	unsigned long flags;
 	nv_mm_context_t context = mm->context;
 
-	if (unlikely(!context)) {
-		spin_lock_irqsave(&ia64_ctx.lock, flags);
-		{
-			/* re-check, now that we've got the lock: */
-			context = mm->context;
-			if (context == 0) {
-				cpus_clear(mm->cpu_vm_mask);
-				if (ia64_ctx.next >= ia64_ctx.limit)
-					wrap_mmu_context(mm);
-				mm->context = context = ia64_ctx.next++;
-			}
+	if (likely(context))
+		goto out;
+
+	spin_lock_irqsave(&ia64_ctx.lock, flags);
+	/* re-check, now that we've got the lock: */
+	context = mm->context;
+	if (context == 0) {
+		cpus_clear(mm->cpu_vm_mask);
+		if (ia64_ctx.next >= ia64_ctx.limit) {
+			ia64_ctx.next = find_next_zero_bit(ia64_ctx.bitmap,
+					ia64_ctx.max_ctx, ia64_ctx.next);
+			ia64_ctx.limit = find_next_bit(ia64_ctx.bitmap,
+					ia64_ctx.max_ctx, ia64_ctx.next);
+			if (ia64_ctx.next >= ia64_ctx.max_ctx)
+				wrap_mmu_context(mm);
 		}
-		spin_unlock_irqrestore(&ia64_ctx.lock, flags);
+		mm->context = context = ia64_ctx.next++;
+		__set_bit(context, ia64_ctx.bitmap);
 	}
+	spin_unlock_irqrestore(&ia64_ctx.lock, flags);
+out:
 	/*
 	 * Ensure we're not starting to use "context" before any old
 	 * uses of it are gone from our TLB.
@@ -100,8 +110,8 @@
 }
 
 /*
- * Initialize context number to some sane value.  MM is guaranteed to be a brand-new
- * address-space, so no TLB flushing is needed, ever.
+ * Initialize context number to some sane value.  MM is guaranteed to be a
+ * brand-new address-space, so no TLB flushing is needed, ever.
  */
 static inline int
 init_new_context (struct task_struct *p, struct mm_struct *mm)
@@ -162,7 +172,10 @@
 		if (!cpu_isset(smp_processor_id(), mm->cpu_vm_mask))
 			cpu_set(smp_processor_id(), mm->cpu_vm_mask);
 		reload_context(context);
-		/* in the unlikely event of a TLB-flush by another thread, redo the load: */
+		/*
+		 * in the unlikely event of a TLB-flush by another thread,
+		 * redo the load.
+		 */
 	} while (unlikely(context != mm->context));
 }
 
@@ -175,8 +188,8 @@
 activate_mm (struct mm_struct *prev, struct mm_struct *next)
 {
 	/*
-	 * We may get interrupts here, but that's OK because interrupt handlers cannot
-	 * touch user-space.
+	 * We may get interrupts here, but that's OK because interrupt
+	 * handlers cannot touch user-space.
 	 */
 	ia64_set_kr(IA64_KR_PT_BASE, __pa(next->pgd));
 	activate_context(next);
diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h
index 60f2137..97890f7 100644
--- a/include/asm-ia64/msi.h
+++ b/include/asm-ia64/msi.h
@@ -12,9 +12,6 @@
 static inline void set_intr_gate (int nr, void *func) {}
 #define IO_APIC_VECTOR(irq)	(irq)
 #define ack_APIC_irq		ia64_eoi
-#define cpu_mask_to_apicid(mask) cpu_physical_id(first_cpu(mask))
-#define MSI_DEST_MODE		MSI_PHYSICAL_MODE
-#define MSI_TARGET_CPU	((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff)
 #define MSI_TARGET_CPU_SHIFT	4
 
 #endif /* ASM_MSI_H */
diff --git a/include/asm-ia64/tlbflush.h b/include/asm-ia64/tlbflush.h
index b65c627..a35b323 100644
--- a/include/asm-ia64/tlbflush.h
+++ b/include/asm-ia64/tlbflush.h
@@ -51,6 +51,7 @@
 	if (!mm)
 		return;
 
+	set_bit(mm->context, ia64_ctx.flushmap);
 	mm->context = 0;
 
 	if (atomic_read(&mm->mm_users) == 0)
diff --git a/include/asm-ppc64/abs_addr.h b/include/asm-powerpc/abs_addr.h
similarity index 94%
rename from include/asm-ppc64/abs_addr.h
rename to include/asm-powerpc/abs_addr.h
index dc3fc3f..1841510 100644
--- a/include/asm-ppc64/abs_addr.h
+++ b/include/asm-powerpc/abs_addr.h
@@ -1,5 +1,5 @@
-#ifndef _ABS_ADDR_H
-#define _ABS_ADDR_H
+#ifndef _ASM_POWERPC_ABS_ADDR_H
+#define _ASM_POWERPC_ABS_ADDR_H
 
 #include <linux/config.h>
 
@@ -70,4 +70,4 @@
 #define iseries_hv_addr(virtaddr)	\
 	(0x8000000000000000 | virt_to_abs(virtaddr))
 
-#endif /* _ABS_ADDR_H */
+#endif /* _ASM_POWERPC_ABS_ADDR_H */
diff --git a/include/asm-powerpc/asm-compat.h b/include/asm-powerpc/asm-compat.h
new file mode 100644
index 0000000..8b133ef
--- /dev/null
+++ b/include/asm-powerpc/asm-compat.h
@@ -0,0 +1,55 @@
+#ifndef _ASM_POWERPC_ASM_COMPAT_H
+#define _ASM_POWERPC_ASM_COMPAT_H
+
+#include <linux/config.h>
+#include <asm/types.h>
+
+#ifdef __ASSEMBLY__
+#  define stringify_in_c(...)	__VA_ARGS__
+#  define ASM_CONST(x)		x
+#else
+/* This version of stringify will deal with commas... */
+#  define __stringify_in_c(...)	#__VA_ARGS__
+#  define stringify_in_c(...)	__stringify_in_c(__VA_ARGS__) " "
+#  define __ASM_CONST(x)	x##UL
+#  define ASM_CONST(x)		__ASM_CONST(x)
+#endif
+
+#ifdef __powerpc64__
+
+/* operations for longs and pointers */
+#define PPC_LL		stringify_in_c(ld)
+#define PPC_STL		stringify_in_c(std)
+#define PPC_LCMPI	stringify_in_c(cmpdi)
+#define PPC_LONG	stringify_in_c(.llong)
+#define PPC_TLNEI	stringify_in_c(tdnei)
+#define PPC_LLARX	stringify_in_c(ldarx)
+#define PPC_STLCX	stringify_in_c(stdcx.)
+#define PPC_CNTLZL	stringify_in_c(cntlzd)
+
+#else /* 32-bit */
+
+/* operations for longs and pointers */
+#define PPC_LL		stringify_in_c(lwz)
+#define PPC_STL		stringify_in_c(stw)
+#define PPC_LCMPI	stringify_in_c(cmpwi)
+#define PPC_LONG	stringify_in_c(.long)
+#define PPC_TLNEI	stringify_in_c(twnei)
+#define PPC_LLARX	stringify_in_c(lwarx)
+#define PPC_STLCX	stringify_in_c(stwcx.)
+#define PPC_CNTLZL	stringify_in_c(cntlzw)
+
+#endif
+
+#ifdef CONFIG_IBM405_ERR77
+/* Erratum #77 on the 405 means we need a sync or dcbt before every
+ * stwcx.  The old ATOMIC_SYNC_FIX covered some but not all of this.
+ */
+#define PPC405_ERR77(ra,rb)	stringify_in_c(dcbt	ra, rb;)
+#define	PPC405_ERR77_SYNC	stringify_in_c(sync;)
+#else
+#define PPC405_ERR77(ra,rb)
+#define PPC405_ERR77_SYNC
+#endif
+
+#endif /* _ASM_POWERPC_ASM_COMPAT_H */
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h
index ed4b345..9c0b372 100644
--- a/include/asm-powerpc/atomic.h
+++ b/include/asm-powerpc/atomic.h
@@ -9,21 +9,13 @@
 
 #ifdef __KERNEL__
 #include <asm/synch.h>
+#include <asm/asm-compat.h>
 
 #define ATOMIC_INIT(i)		{ (i) }
 
 #define atomic_read(v)		((v)->counter)
 #define atomic_set(v,i)		(((v)->counter) = (i))
 
-/* Erratum #77 on the 405 means we need a sync or dcbt before every stwcx.
- * The old ATOMIC_SYNC_FIX covered some but not all of this.
- */
-#ifdef CONFIG_IBM405_ERR77
-#define PPC405_ERR77(ra,rb)	"dcbt " #ra "," #rb ";"
-#else
-#define PPC405_ERR77(ra,rb)
-#endif
-
 static __inline__ void atomic_add(int a, atomic_t *v)
 {
 	int t;
@@ -205,5 +197,183 @@
 #define smp_mb__before_atomic_inc()     smp_mb()
 #define smp_mb__after_atomic_inc()      smp_mb()
 
+#ifdef __powerpc64__
+
+typedef struct { volatile long counter; } atomic64_t;
+
+#define ATOMIC64_INIT(i)	{ (i) }
+
+#define atomic64_read(v)	((v)->counter)
+#define atomic64_set(v,i)	(((v)->counter) = (i))
+
+static __inline__ void atomic64_add(long a, atomic64_t *v)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%3		# atomic64_add\n\
+	add	%0,%2,%0\n\
+	stdcx.	%0,0,%3 \n\
+	bne-	1b"
+	: "=&r" (t), "=m" (v->counter)
+	: "r" (a), "r" (&v->counter), "m" (v->counter)
+	: "cc");
+}
+
+static __inline__ long atomic64_add_return(long a, atomic64_t *v)
+{
+	long t;
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	ldarx	%0,0,%2		# atomic64_add_return\n\
+	add	%0,%1,%0\n\
+	stdcx.	%0,0,%2 \n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (t)
+	: "r" (a), "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+#define atomic64_add_negative(a, v)	(atomic64_add_return((a), (v)) < 0)
+
+static __inline__ void atomic64_sub(long a, atomic64_t *v)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%3		# atomic64_sub\n\
+	subf	%0,%2,%0\n\
+	stdcx.	%0,0,%3 \n\
+	bne-	1b"
+	: "=&r" (t), "=m" (v->counter)
+	: "r" (a), "r" (&v->counter), "m" (v->counter)
+	: "cc");
+}
+
+static __inline__ long atomic64_sub_return(long a, atomic64_t *v)
+{
+	long t;
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	ldarx	%0,0,%2		# atomic64_sub_return\n\
+	subf	%0,%1,%0\n\
+	stdcx.	%0,0,%2 \n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (t)
+	: "r" (a), "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+static __inline__ void atomic64_inc(atomic64_t *v)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%2		# atomic64_inc\n\
+	addic	%0,%0,1\n\
+	stdcx.	%0,0,%2 \n\
+	bne-	1b"
+	: "=&r" (t), "=m" (v->counter)
+	: "r" (&v->counter), "m" (v->counter)
+	: "cc");
+}
+
+static __inline__ long atomic64_inc_return(atomic64_t *v)
+{
+	long t;
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	ldarx	%0,0,%1		# atomic64_inc_return\n\
+	addic	%0,%0,1\n\
+	stdcx.	%0,0,%1 \n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+/*
+ * atomic64_inc_and_test - increment and test
+ * @v: pointer of type atomic64_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
+
+static __inline__ void atomic64_dec(atomic64_t *v)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%2		# atomic64_dec\n\
+	addic	%0,%0,-1\n\
+	stdcx.	%0,0,%2\n\
+	bne-	1b"
+	: "=&r" (t), "=m" (v->counter)
+	: "r" (&v->counter), "m" (v->counter)
+	: "cc");
+}
+
+static __inline__ long atomic64_dec_return(atomic64_t *v)
+{
+	long t;
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	ldarx	%0,0,%1		# atomic64_dec_return\n\
+	addic	%0,%0,-1\n\
+	stdcx.	%0,0,%1\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+#define atomic64_sub_and_test(a, v)	(atomic64_sub_return((a), (v)) == 0)
+#define atomic64_dec_and_test(v)	(atomic64_dec_return((v)) == 0)
+
+/*
+ * Atomically test *v and decrement if it is greater than 0.
+ * The function returns the old value of *v minus 1.
+ */
+static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
+{
+	long t;
+
+	__asm__ __volatile__(
+	EIEIO_ON_SMP
+"1:	ldarx	%0,0,%1		# atomic64_dec_if_positive\n\
+	addic.	%0,%0,-1\n\
+	blt-	2f\n\
+	stdcx.	%0,0,%1\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	"\n\
+2:"	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+#endif /* __powerpc64__ */
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_ATOMIC_H_ */
diff --git a/include/asm-powerpc/auxvec.h b/include/asm-powerpc/auxvec.h
index 79d8c47..19a099b 100644
--- a/include/asm-powerpc/auxvec.h
+++ b/include/asm-powerpc/auxvec.h
@@ -14,8 +14,6 @@
 /* The vDSO location. We have to use the same value as x86 for glibc's
  * sake :-)
  */
-#ifdef __powerpc64__
 #define AT_SYSINFO_EHDR		33
-#endif
 
 #endif
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h
index dc25c53..5727229 100644
--- a/include/asm-powerpc/bitops.h
+++ b/include/asm-powerpc/bitops.h
@@ -40,6 +40,7 @@
 
 #include <linux/compiler.h>
 #include <asm/atomic.h>
+#include <asm/asm-compat.h>
 #include <asm/synch.h>
 
 /*
@@ -52,16 +53,6 @@
 #define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
 #define BITOP_LE_SWIZZLE	((BITS_PER_LONG-1) & ~0x7)
 
-#ifdef CONFIG_PPC64
-#define LARXL		"ldarx"
-#define STCXL		"stdcx."
-#define CNTLZL		"cntlzd"
-#else
-#define LARXL		"lwarx"
-#define STCXL		"stwcx."
-#define CNTLZL		"cntlzw"
-#endif
-
 static __inline__ void set_bit(int nr, volatile unsigned long *addr)
 {
 	unsigned long old;
@@ -69,10 +60,10 @@
 	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
 
 	__asm__ __volatile__(
-"1:"	LARXL "	%0,0,%3	# set_bit\n"
+"1:"	PPC_LLARX "%0,0,%3	# set_bit\n"
 	"or	%0,%0,%2\n"
 	PPC405_ERR77(0,%3)
-	STCXL "	%0,0,%3\n"
+	PPC_STLCX "%0,0,%3\n"
 	"bne-	1b"
 	: "=&r"(old), "=m"(*p)
 	: "r"(mask), "r"(p), "m"(*p)
@@ -86,10 +77,10 @@
 	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
 
 	__asm__ __volatile__(
-"1:"	LARXL "	%0,0,%3	# set_bit\n"
+"1:"	PPC_LLARX "%0,0,%3	# clear_bit\n"
 	"andc	%0,%0,%2\n"
 	PPC405_ERR77(0,%3)
-	STCXL "	%0,0,%3\n"
+	PPC_STLCX "%0,0,%3\n"
 	"bne-	1b"
 	: "=&r"(old), "=m"(*p)
 	: "r"(mask), "r"(p), "m"(*p)
@@ -103,10 +94,10 @@
 	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
 
 	__asm__ __volatile__(
-"1:"	LARXL "	%0,0,%3	# set_bit\n"
+"1:"	PPC_LLARX "%0,0,%3	# change_bit\n"
 	"xor	%0,%0,%2\n"
 	PPC405_ERR77(0,%3)
-	STCXL "	%0,0,%3\n"
+	PPC_STLCX "%0,0,%3\n"
 	"bne-	1b"
 	: "=&r"(old), "=m"(*p)
 	: "r"(mask), "r"(p), "m"(*p)
@@ -122,10 +113,10 @@
 
 	__asm__ __volatile__(
 	EIEIO_ON_SMP
-"1:"	LARXL "	%0,0,%3		# test_and_set_bit\n"
+"1:"	PPC_LLARX "%0,0,%3		# test_and_set_bit\n"
 	"or	%1,%0,%2 \n"
 	PPC405_ERR77(0,%3)
-	STCXL "	%1,0,%3 \n"
+	PPC_STLCX "%1,0,%3 \n"
 	"bne-	1b"
 	ISYNC_ON_SMP
 	: "=&r" (old), "=&r" (t)
@@ -144,10 +135,10 @@
 
 	__asm__ __volatile__(
 	EIEIO_ON_SMP
-"1:"	LARXL "	%0,0,%3		# test_and_clear_bit\n"
+"1:"	PPC_LLARX "%0,0,%3		# test_and_clear_bit\n"
 	"andc	%1,%0,%2 \n"
 	PPC405_ERR77(0,%3)
-	STCXL "	%1,0,%3 \n"
+	PPC_STLCX "%1,0,%3 \n"
 	"bne-	1b"
 	ISYNC_ON_SMP
 	: "=&r" (old), "=&r" (t)
@@ -166,10 +157,10 @@
 
 	__asm__ __volatile__(
 	EIEIO_ON_SMP
-"1:"	LARXL "	%0,0,%3		# test_and_change_bit\n"
+"1:"	PPC_LLARX "%0,0,%3		# test_and_change_bit\n"
 	"xor	%1,%0,%2 \n"
 	PPC405_ERR77(0,%3)
-	STCXL "	%1,0,%3 \n"
+	PPC_STLCX "%1,0,%3 \n"
 	"bne-	1b"
 	ISYNC_ON_SMP
 	: "=&r" (old), "=&r" (t)
@@ -184,9 +175,9 @@
         unsigned long old;
 
 	__asm__ __volatile__(
-"1:"	LARXL "	%0,0,%3         # set_bit\n"
+"1:"	PPC_LLARX "%0,0,%3         # set_bits\n"
 	"or	%0,%0,%2\n"
-	STCXL "	%0,0,%3\n"
+	PPC_STLCX "%0,0,%3\n"
 	"bne-	1b"
 	: "=&r" (old), "=m" (*addr)
 	: "r" (mask), "r" (addr), "m" (*addr)
@@ -268,7 +259,7 @@
 {
 	int lz;
 
-	asm (CNTLZL " %0,%1" : "=r" (lz) : "r" (x));
+	asm (PPC_CNTLZL "%0,%1" : "=r" (lz) : "r" (x));
 	return BITS_PER_LONG - 1 - lz;
 }
 
diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h
index d625ee5..b001ecb 100644
--- a/include/asm-powerpc/bug.h
+++ b/include/asm-powerpc/bug.h
@@ -1,6 +1,7 @@
 #ifndef _ASM_POWERPC_BUG_H
 #define _ASM_POWERPC_BUG_H
 
+#include <asm/asm-compat.h>
 /*
  * Define an illegal instr to trap on the bug.
  * We don't use 0 because that marks the end of a function
@@ -11,14 +12,6 @@
 
 #ifndef __ASSEMBLY__
 
-#ifdef __powerpc64__
-#define BUG_TABLE_ENTRY		".llong"
-#define BUG_TRAP_OP		"tdnei"
-#else 
-#define BUG_TABLE_ENTRY		".long"
-#define BUG_TRAP_OP		"twnei"
-#endif /* __powerpc64__ */
-
 struct bug_entry {
 	unsigned long	bug_addr;
 	long		line;
@@ -40,16 +33,16 @@
 	__asm__ __volatile__(						 \
 		"1:	twi 31,0,0\n"					 \
 		".section __bug_table,\"a\"\n"				 \
-		"\t"BUG_TABLE_ENTRY"	1b,%0,%1,%2\n"			 \
+		"\t"PPC_LONG"	1b,%0,%1,%2\n"			 \
 		".previous"						 \
 		: : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \
 } while (0)
 
 #define BUG_ON(x) do {						\
 	__asm__ __volatile__(					\
-		"1:	"BUG_TRAP_OP"	%0,0\n"			\
+		"1:	"PPC_TLNEI"	%0,0\n"			\
 		".section __bug_table,\"a\"\n"			\
-		"\t"BUG_TABLE_ENTRY"	1b,%1,%2,%3\n"		\
+		"\t"PPC_LONG"	1b,%1,%2,%3\n"		\
 		".previous"					\
 		: : "r" ((long)(x)), "i" (__LINE__),		\
 		    "i" (__FILE__), "i" (__FUNCTION__));	\
@@ -57,9 +50,9 @@
 
 #define WARN_ON(x) do {						\
 	__asm__ __volatile__(					\
-		"1:	"BUG_TRAP_OP"	%0,0\n"			\
+		"1:	"PPC_TLNEI"	%0,0\n"			\
 		".section __bug_table,\"a\"\n"			\
-		"\t"BUG_TABLE_ENTRY"	1b,%1,%2,%3\n"		\
+		"\t"PPC_LONG"	1b,%1,%2,%3\n"		\
 		".previous"					\
 		: : "r" ((long)(x)),				\
 		    "i" (__LINE__ + BUG_WARNING_TRAP),		\
diff --git a/include/asm-powerpc/cache.h b/include/asm-powerpc/cache.h
new file mode 100644
index 0000000..26ce502
--- /dev/null
+++ b/include/asm-powerpc/cache.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_POWERPC_CACHE_H
+#define _ASM_POWERPC_CACHE_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+/* bytes per L1 cache line */
+#if defined(CONFIG_8xx) || defined(CONFIG_403GCX)
+#define L1_CACHE_SHIFT		4
+#define MAX_COPY_PREFETCH	1
+#elif defined(CONFIG_PPC32)
+#define L1_CACHE_SHIFT		5
+#define MAX_COPY_PREFETCH	4
+#else /* CONFIG_PPC64 */
+#define L1_CACHE_SHIFT		7
+#endif
+
+#define	L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
+
+#define	SMP_CACHE_BYTES		L1_CACHE_BYTES
+#define L1_CACHE_SHIFT_MAX	7 /* largest L1 which this arch supports */
+
+#if defined(__powerpc64__) && !defined(__ASSEMBLY__)
+struct ppc64_caches {
+	u32	dsize;			/* L1 d-cache size */
+	u32	dline_size;		/* L1 d-cache line size	*/
+	u32	log_dline_size;
+	u32	dlines_per_page;
+	u32	isize;			/* L1 i-cache size */
+	u32	iline_size;		/* L1 i-cache line size	*/
+	u32	log_iline_size;
+	u32	ilines_per_page;
+};
+
+extern struct ppc64_caches ppc64_caches;
+#endif /* __powerpc64__ && ! __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_CACHE_H */
diff --git a/include/asm-powerpc/cacheflush.h b/include/asm-powerpc/cacheflush.h
new file mode 100644
index 0000000..8a740c8
--- /dev/null
+++ b/include/asm-powerpc/cacheflush.h
@@ -0,0 +1,68 @@
+/*
+ *  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.
+ */
+#ifndef _ASM_POWERPC_CACHEFLUSH_H
+#define _ASM_POWERPC_CACHEFLUSH_H
+
+#ifdef __KERNEL__
+
+#include <linux/mm.h>
+#include <asm/cputable.h>
+
+/*
+ * No cache flushing is required when address mappings are changed,
+ * because the caches on PowerPCs are physically addressed.
+ */
+#define flush_cache_all()			do { } while (0)
+#define flush_cache_mm(mm)			do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define flush_icache_page(vma, page)		do { } while (0)
+#define flush_cache_vmap(start, end)		do { } while (0)
+#define flush_cache_vunmap(start, end)		do { } while (0)
+
+extern void flush_dcache_page(struct page *page);
+#define flush_dcache_mmap_lock(mapping)		do { } while (0)
+#define flush_dcache_mmap_unlock(mapping)	do { } while (0)
+
+extern void __flush_icache_range(unsigned long, unsigned long);
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+	if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
+		__flush_icache_range(start, stop);
+}
+
+extern void flush_icache_user_range(struct vm_area_struct *vma,
+				    struct page *page, unsigned long addr,
+				    int len);
+extern void __flush_dcache_icache(void *page_va);
+extern void flush_dcache_icache_page(struct page *page);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_BOOKE)
+extern void __flush_dcache_icache_phys(unsigned long physaddr);
+#endif /* CONFIG_PPC32 && !CONFIG_BOOKE */
+
+extern void flush_dcache_range(unsigned long start, unsigned long stop);
+#ifdef CONFIG_PPC32
+extern void clean_dcache_range(unsigned long start, unsigned long stop);
+extern void invalidate_dcache_range(unsigned long start, unsigned long stop);
+#endif /* CONFIG_PPC32 */
+#ifdef CONFIG_PPC64
+extern void flush_inval_dcache_range(unsigned long start, unsigned long stop);
+extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
+#endif
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+	do { \
+		memcpy(dst, src, len); \
+		flush_icache_user_range(vma, page, vaddr, len); \
+	} while (0)
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+	memcpy(dst, src, len)
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_POWERPC_CACHEFLUSH_H */
diff --git a/include/asm-ppc64/compat.h b/include/asm-powerpc/compat.h
similarity index 97%
rename from include/asm-ppc64/compat.h
rename to include/asm-powerpc/compat.h
index 6ec62cd..4db4360 100644
--- a/include/asm-ppc64/compat.h
+++ b/include/asm-powerpc/compat.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_PPC64_COMPAT_H
-#define _ASM_PPC64_COMPAT_H
+#ifndef _ASM_POWERPC_COMPAT_H
+#define _ASM_POWERPC_COMPAT_H
 /*
  * Architecture specific compatibility types
  */
@@ -49,7 +49,7 @@
 	compat_dev_t	st_dev;
 	compat_ino_t	st_ino;
 	compat_mode_t	st_mode;
-	compat_nlink_t	st_nlink;	
+	compat_nlink_t	st_nlink;
 	__compat_uid32_t	st_uid;
 	__compat_gid32_t	st_gid;
 	compat_dev_t	st_rdev;
@@ -202,4 +202,4 @@
 	compat_ulong_t __unused6;
 };
 
-#endif /* _ASM_PPC64_COMPAT_H */
+#endif /* _ASM_POWERPC_COMPAT_H */
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index 79a0556..04e2726 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -2,7 +2,7 @@
 #define __ASM_POWERPC_CPUTABLE_H
 
 #include <linux/config.h>
-#include <asm/ppc_asm.h> /* for ASM_CONST */
+#include <asm/asm-compat.h>
 
 #define PPC_FEATURE_32			0x80000000
 #define PPC_FEATURE_64			0x40000000
@@ -16,6 +16,10 @@
 #define PPC_FEATURE_HAS_EFP_SINGLE	0x00400000
 #define PPC_FEATURE_HAS_EFP_DOUBLE	0x00200000
 #define PPC_FEATURE_NO_TB		0x00100000
+#define PPC_FEATURE_POWER4		0x00080000
+#define PPC_FEATURE_POWER5		0x00040000
+#define PPC_FEATURE_POWER5_PLUS		0x00020000
+#define PPC_FEATURE_CELL		0x00010000
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h
new file mode 100644
index 0000000..82cd4a9
--- /dev/null
+++ b/include/asm-powerpc/current.h
@@ -0,0 +1,27 @@
+#ifndef _ASM_POWERPC_CURRENT_H
+#define _ASM_POWERPC_CURRENT_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.
+ */
+
+struct task_struct;
+
+#ifdef __powerpc64__
+#include <asm/paca.h>
+
+#define current		(get_paca()->__current)
+
+#else
+
+/*
+ * We keep `current' in r2 for speed.
+ */
+register struct task_struct *current asm ("r2");
+
+#endif
+
+#endif /* _ASM_POWERPC_CURRENT_H */
diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h
new file mode 100644
index 0000000..d168a30
--- /dev/null
+++ b/include/asm-powerpc/eeh_event.h
@@ -0,0 +1,52 @@
+/*
+ *	eeh_event.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
+ *
+ * Copyright (c) 2005 Linas Vepstas <linas@linas.org>
+ */
+
+#ifndef ASM_PPC64_EEH_EVENT_H
+#define ASM_PPC64_EEH_EVENT_H
+
+/** EEH event -- structure holding pci controller data that describes
+ *  a change in the isolation status of a PCI slot.  A pointer
+ *  to this struct is passed as the data pointer in a notify callback.
+ */
+struct eeh_event {
+	struct list_head     list;
+	struct device_node 	*dn;   /* struct device node */
+	struct pci_dev       *dev;  /* affected device */
+	int                  state;
+	int time_unavail;    /* milliseconds until device might be available */
+};
+
+/**
+ * eeh_send_failure_event - generate a PCI error event
+ * @dev pci device
+ *
+ * This routine builds a PCI error event which will be delivered
+ * to all listeners on the peh_notifier_chain.
+ *
+ * This routine can be called within an interrupt context;
+ * the actual event will be delivered in a normal context
+ * (from a workqueue).
+ */
+int eeh_send_failure_event (struct device_node *dn,
+                            struct pci_dev *dev,
+                            int reset_state,
+                            int time_unavail);
+
+#endif /* ASM_PPC64_EEH_EVENT_H */
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index feac345..3dcd65e 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -269,14 +269,12 @@
 extern int icache_bsize;
 extern int ucache_bsize;
 
-#ifdef __powerpc64__
+/* vDSO has arch_setup_additional_pages */
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 struct linux_binprm;
-#define ARCH_HAS_SETUP_ADDITIONAL_PAGES	/* vDSO has arch_setup_additional_pages */
-extern int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack);
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+				       int executable_stack);
 #define VDSO_AUX_ENT(a,b) NEW_AUX_ENT(a,b);
-#else
-#define VDSO_AUX_ENT(a,b)
-#endif /* __powerpc64__ */
 
 /*
  * The requirements here are:
diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h
index 806c142..12fabbcb0 100644
--- a/include/asm-powerpc/firmware.h
+++ b/include/asm-powerpc/firmware.h
@@ -43,6 +43,7 @@
 #define FW_FEATURE_ISERIES	(1UL<<21)
 
 enum {
+#ifdef CONFIG_PPC64
 	FW_FEATURE_PSERIES_POSSIBLE = FW_FEATURE_PFT | FW_FEATURE_TCE |
 		FW_FEATURE_SPRG0 | FW_FEATURE_DABR | FW_FEATURE_COPY |
 		FW_FEATURE_ASR | FW_FEATURE_DEBUG | FW_FEATURE_TERM |
@@ -70,6 +71,11 @@
 		FW_FEATURE_ISERIES_ALWAYS &
 #endif
 		FW_FEATURE_POSSIBLE,
+
+#else /* CONFIG_PPC64 */
+	FW_FEATURE_POSSIBLE = 0,
+	FW_FEATURE_ALWAYS = 0,
+#endif
 };
 
 /* This is used to identify firmware features which are available
diff --git a/include/asm-powerpc/futex.h b/include/asm-powerpc/futex.h
index 37c94e5..f0319d5 100644
--- a/include/asm-powerpc/futex.h
+++ b/include/asm-powerpc/futex.h
@@ -7,13 +7,14 @@
 #include <asm/errno.h>
 #include <asm/synch.h>
 #include <asm/uaccess.h>
-#include <asm/ppc_asm.h>
+#include <asm/asm-compat.h>
 
 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
   __asm__ __volatile ( \
 	SYNC_ON_SMP \
 "1:	lwarx	%0,0,%2\n" \
 	insn \
+	PPC405_ERR77(0, %2) \
 "2:	stwcx.	%1,0,%2\n" \
 	"bne-	1b\n" \
 	"li	%1,0\n" \
@@ -23,7 +24,7 @@
 	".previous\n" \
 	".section __ex_table,\"a\"\n" \
 	".align 3\n" \
-	DATAL " 1b,4b,2b,4b\n" \
+	PPC_LONG "1b,4b,2b,4b\n" \
 	".previous" \
 	: "=&r" (oldval), "=&r" (ret) \
 	: "b" (uaddr), "i" (-EFAULT), "1" (oparg) \
diff --git a/include/asm-ppc64/hvcall.h b/include/asm-powerpc/hvcall.h
similarity index 97%
rename from include/asm-ppc64/hvcall.h
rename to include/asm-powerpc/hvcall.h
index ab7c3cf..d36da61 100644
--- a/include/asm-ppc64/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -1,5 +1,5 @@
-#ifndef _PPC64_HVCALL_H
-#define _PPC64_HVCALL_H
+#ifndef _ASM_POWERPC_HVCALL_H
+#define _ASM_POWERPC_HVCALL_H
 
 #define HVSC			.long 0x44000022
 
@@ -138,7 +138,7 @@
  */
 long plpar_hcall_norets(unsigned long opcode, ...);
 
-/* 
+/*
  * Special hcall interface for ibmveth support.
  * Takes 8 input parms. Returns a rc and stores the
  * R4 return value in *out1.
@@ -153,11 +153,11 @@
 			   unsigned long arg7,
 			   unsigned long arg8,
 			   unsigned long *out1);
- 
+
 /* plpar_hcall_4out()
  *
- * same as plpar_hcall except with 4 output arguments.  
- * 
+ * same as plpar_hcall except with 4 output arguments.
+ *
  */
 long plpar_hcall_4out(unsigned long opcode,
 		      unsigned long arg1,
@@ -170,4 +170,4 @@
 		      unsigned long *out4);
 
 #endif /* __ASSEMBLY__ */
-#endif /* _PPC64_HVCALL_H */
+#endif /* _ASM_POWERPC_HVCALL_H */
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h
index c37b31b..26b89d8 100644
--- a/include/asm-powerpc/hw_irq.h
+++ b/include/asm-powerpc/hw_irq.h
@@ -12,7 +12,6 @@
 #include <asm/processor.h>
 
 extern void timer_interrupt(struct pt_regs *);
-extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
 
 #ifdef CONFIG_PPC_ISERIES
 
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index b3935ea..8eb7e85 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -389,6 +389,7 @@
 #define	SIU_INT_TIMER4		((uint)0x0f + CPM_IRQ_OFFSET)
 #define	SIU_INT_TMCNT		((uint)0x10 + CPM_IRQ_OFFSET)
 #define	SIU_INT_PIT		((uint)0x11 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PCI		((uint)0x12 + CPM_IRQ_OFFSET)
 #define	SIU_INT_IRQ1		((uint)0x13 + CPM_IRQ_OFFSET)
 #define	SIU_INT_IRQ2		((uint)0x14 + CPM_IRQ_OFFSET)
 #define	SIU_INT_IRQ3		((uint)0x15 + CPM_IRQ_OFFSET)
@@ -429,7 +430,6 @@
 #define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
 /* pedantic: these are long because they are used with set_bit --RR */
 extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
-extern unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
 extern atomic_t ppc_n_lost_interrupts;
 
 #define virt_irq_create_mapping(x)	(x)
@@ -488,8 +488,8 @@
 
 extern void irq_ctx_init(void);
 extern void call_do_softirq(struct thread_info *tp);
-extern int call_handle_IRQ_event(int irq, struct pt_regs *regs,
-			struct irqaction *action, struct thread_info *tp);
+extern int call___do_IRQ(int irq, struct pt_regs *regs,
+		struct thread_info *tp);
 
 #define __ARCH_HAS_DO_SOFTIRQ
 
diff --git a/include/asm-ppc64/lppaca.h b/include/asm-powerpc/lppaca.h
similarity index 97%
rename from include/asm-ppc64/lppaca.h
rename to include/asm-powerpc/lppaca.h
index 9e2a6c0..c1bedab 100644
--- a/include/asm-ppc64/lppaca.h
+++ b/include/asm-powerpc/lppaca.h
@@ -16,8 +16,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
-#ifndef _ASM_LPPACA_H
-#define _ASM_LPPACA_H
+#ifndef _ASM_POWERPC_LPPACA_H
+#define _ASM_POWERPC_LPPACA_H
 
 //=============================================================================
 //
@@ -28,8 +28,7 @@
 //----------------------------------------------------------------------------
 #include <asm/types.h>
 
-struct lppaca
-{
+struct lppaca {
 //=============================================================================
 // CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
 // NOTE: The xDynXyz fields are fields that will be dynamically changed by
@@ -129,4 +128,4 @@
 	u8	pmc_save_area[256];	// PMC interrupt Area           x00-xFF
 };
 
-#endif /* _ASM_LPPACA_H */
+#endif /* _ASM_POWERPC_LPPACA_H */
diff --git a/include/asm-ppc64/paca.h b/include/asm-powerpc/paca.h
similarity index 95%
rename from include/asm-ppc64/paca.h
rename to include/asm-powerpc/paca.h
index bccacd6..92c765c 100644
--- a/include/asm-ppc64/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -1,11 +1,8 @@
-#ifndef _PPC64_PACA_H
-#define _PPC64_PACA_H
-
 /*
- * include/asm-ppc64/paca.h
+ * include/asm-powerpc/paca.h
  *
- * This control block defines the PACA which defines the processor 
- * specific data for each logical processor on the system.  
+ * This control block defines the PACA which defines the processor
+ * specific data for each logical processor on the system.
  * There are some pointers defined that are utilized by PLIC.
  *
  * C 2001 PPC 64 Team, IBM Corp
@@ -14,7 +11,9 @@
  * 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.
- */    
+ */
+#ifndef _ASM_POWERPC_PACA_H
+#define _ASM_POWERPC_PACA_H
 
 #include	<linux/config.h>
 #include	<asm/types.h>
@@ -118,4 +117,4 @@
 
 extern struct paca_struct paca[];
 
-#endif /* _PPC64_PACA_H */
+#endif /* _ASM_POWERPC_PACA_H */
diff --git a/include/asm-powerpc/pmc.h b/include/asm-powerpc/pmc.h
index 2f3c3fc..5f41f3a 100644
--- a/include/asm-powerpc/pmc.h
+++ b/include/asm-powerpc/pmc.h
@@ -22,6 +22,7 @@
 #include <asm/ptrace.h>
 
 typedef void (*perf_irq_t)(struct pt_regs *);
+extern perf_irq_t perf_irq;
 
 int reserve_pmc_hardware(perf_irq_t new_perf_irq);
 void release_pmc_hardware(void);
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index 13aacff..9896fad 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -26,6 +26,10 @@
 
 extern struct pci_dev *ppc64_isabridge_dev;	/* may be NULL if no ISA bus */
 
+/** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */
+#define BUID_HI(buid) ((buid) >> 32)
+#define BUID_LO(buid) ((buid) & 0xffffffff)
+
 /* PCI device_node operations */
 struct device_node;
 typedef void *(*traverse_func)(struct device_node *me, void *data);
@@ -36,10 +40,6 @@
 void pci_devs_phb_init_dynamic(struct pci_controller *phb);
 void __devinit scan_phb(struct pci_controller *hose);
 
-/* PCI address cache management routines */
-void pci_addr_cache_insert_device(struct pci_dev *dev);
-void pci_addr_cache_remove_device(struct pci_dev *dev);
-
 /* From rtas_pci.h */
 void init_pci_config_tokens (void);
 unsigned long get_phb_buid (struct device_node *);
@@ -52,4 +52,48 @@
 extern unsigned long pci_assign_all_buses;
 extern int pci_read_irq_line(struct pci_dev *pci_dev);
 
+/* ---- EEH internal-use-only related routines ---- */
+#ifdef CONFIG_EEH
+/**
+ * rtas_set_slot_reset -- unfreeze a frozen slot
+ *
+ * Clear the EEH-frozen condition on a slot.  This routine
+ * does this by asserting the PCI #RST line for 1/8th of
+ * a second; this routine will sleep while the adapter is
+ * being reset.
+ */
+void rtas_set_slot_reset (struct pci_dn *);
+
+/** 
+ * eeh_restore_bars - Restore device configuration info.
+ *
+ * A reset of a PCI device will clear out its config space.
+ * This routines will restore the config space for this
+ * device, and is children, to values previously obtained
+ * from the firmware.
+ */
+void eeh_restore_bars(struct pci_dn *);
+
+/**
+ * rtas_configure_bridge -- firmware initialization of pci bridge
+ *
+ * Ask the firmware to configure all PCI bridges devices
+ * located behind the indicated node. Required after a
+ * pci device reset. Does essentially the same hing as
+ * eeh_restore_bars, but for brdges, and lets firmware 
+ * do the work.
+ */
+void rtas_configure_bridge(struct pci_dn *);
+
+int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
+
+/**
+ * mark and clear slots: find "partition endpoint" PE and set or 
+ * clear the flags for each subnode of the PE.
+ */
+void eeh_mark_slot (struct device_node *dn, int mode_flag);
+void eeh_clear_slot (struct device_node *dn, int mode_flag);
+
+#endif
+
 #endif /* _ASM_POWERPC_PPC_PCI_H */
diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h
index c534ca4..c27baa0 100644
--- a/include/asm-powerpc/ppc_asm.h
+++ b/include/asm-powerpc/ppc_asm.h
@@ -6,8 +6,13 @@
 
 #include <linux/stringify.h>
 #include <linux/config.h>
+#include <asm/asm-compat.h>
 
-#ifdef __ASSEMBLY__
+#ifndef __ASSEMBLY__
+#error __FILE__ should only be used in assembler files
+#else
+
+#define SZL			(BITS_PER_LONG/8)
 
 /*
  * Macros for storing registers into and loading registers from
@@ -184,12 +189,6 @@
 	oris    reg,reg,(label)@h;                      \
 	ori     reg,reg,(label)@l;
 
-/* operations for longs and pointers */
-#define LDL	ld
-#define STL	std
-#define CMPI	cmpdi
-#define SZL	8
-
 /* offsets for stack frame layout */
 #define LRSAVE	16
 
@@ -203,12 +202,6 @@
 
 #define OFF(name)	name@l
 
-/* operations for longs and pointers */
-#define LDL	lwz
-#define STL	stw
-#define CMPI	cmpwi
-#define SZL	4
-
 /* offsets for stack frame layout */
 #define LRSAVE	4
 
@@ -266,15 +259,6 @@
 #endif
 
 
-#ifdef CONFIG_IBM405_ERR77
-#define PPC405_ERR77(ra,rb)	dcbt	ra, rb;
-#define	PPC405_ERR77_SYNC	sync;
-#else
-#define PPC405_ERR77(ra,rb)
-#define PPC405_ERR77_SYNC
-#endif
-
-
 #ifdef CONFIG_IBM440EP_ERR42
 #define PPC440EP_ERR42 isync
 #else
@@ -502,17 +486,6 @@
 #define N_SLINE	68
 #define N_SO	100
 
-#define ASM_CONST(x) x
-#else
-  #define __ASM_CONST(x) x##UL
-  #define ASM_CONST(x) __ASM_CONST(x)
-
-#ifdef CONFIG_PPC64
-#define DATAL	".llong"
-#else
-#define DATAL	".long"
-#endif
-
 #endif /*  __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_PPC_ASM_H */
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index 1dc4bf7..d12382d 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -17,65 +17,71 @@
 #include <linux/compiler.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
-#ifdef CONFIG_PPC64
-#include <asm/systemcfg.h>
-#endif
 
-#ifdef CONFIG_PPC32
-/* 32-bit platform types */
-/* We only need to define a new _MACH_xxx for machines which are part of
- * a configuration which supports more than one type of different machine.
- * This is currently limited to CONFIG_PPC_MULTIPLATFORM and CHRP/PReP/PMac.
- * -- Tom
+/* We do _not_ want to define new machine types at all, those must die
+ * in favor of using the device-tree
+ * -- BenH.
  */
-#define _MACH_prep	0x00000001
-#define _MACH_Pmac	0x00000002	/* pmac or pmac clone (non-chrp) */
-#define _MACH_chrp	0x00000004	/* chrp machine */
 
-/* see residual.h for these */
+/* Platforms codes (to be obsoleted) */
+#define PLATFORM_PSERIES	0x0100
+#define PLATFORM_PSERIES_LPAR	0x0101
+#define PLATFORM_ISERIES_LPAR	0x0201
+#define PLATFORM_LPAR		0x0001
+#define PLATFORM_POWERMAC	0x0400
+#define PLATFORM_MAPLE		0x0500
+#define PLATFORM_PREP		0x0600
+#define PLATFORM_CHRP		0x0700
+#define PLATFORM_CELL		0x1000
+
+/* Compat platform codes for 32 bits */
+#define _MACH_prep	PLATFORM_PREP
+#define _MACH_Pmac	PLATFORM_POWERMAC
+#define _MACH_chrp	PLATFORM_CHRP
+
+/* PREP sub-platform types see residual.h for these */
 #define _PREP_Motorola	0x01	/* motorola prep */
 #define _PREP_Firm	0x02	/* firmworks prep */
 #define _PREP_IBM	0x00	/* ibm prep */
 #define _PREP_Bull	0x03	/* bull prep */
 
-/* these are arbitrary */
+/* CHRP sub-platform types. These are arbitrary */
 #define _CHRP_Motorola	0x04	/* motorola chrp, the cobra */
 #define _CHRP_IBM	0x05	/* IBM chrp, the longtrail and longtrail 2 */
 #define _CHRP_Pegasos	0x06	/* Genesi/bplan's Pegasos and Pegasos2 */
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
+#define platform_is_pseries()	(_machine == PLATFORM_PSERIES || \
+				 _machine == PLATFORM_PSERIES_LPAR)
+#define platform_is_lpar()	(!!(_machine & PLATFORM_LPAR))
+
+#if defined(CONFIG_PPC_MULTIPLATFORM)
 extern int _machine;
 
+#ifdef CONFIG_PPC32
+
 /* what kind of prep workstation we are */
 extern int _prep_type;
 extern int _chrp_type;
 
 /*
  * This is used to identify the board type from a given PReP board
- * vendor. Board revision is also made available.
+ * vendor. Board revision is also made available. This will be moved
+ * elsewhere soon
  */
 extern unsigned char ucSystemType;
 extern unsigned char ucBoardRev;
 extern unsigned char ucBoardRevMaj, ucBoardRevMin;
+
+#endif /* CONFIG_PPC32 */
+
+#elif defined(CONFIG_PPC_ISERIES)
+/*
+ * iSeries is soon to become MULTIPLATFORM hopefully ...
+ */
+#define _machine PLATFORM_ISERIES_LPAR
 #else
 #define _machine 0
 #endif /* CONFIG_PPC_MULTIPLATFORM */
-#endif /* CONFIG_PPC32 */
-
-#ifdef CONFIG_PPC64
-/* Platforms supported by PPC64 */
-#define PLATFORM_PSERIES      0x0100
-#define PLATFORM_PSERIES_LPAR 0x0101
-#define PLATFORM_ISERIES_LPAR 0x0201
-#define PLATFORM_LPAR         0x0001
-#define PLATFORM_POWERMAC     0x0400
-#define PLATFORM_MAPLE        0x0500
-#define PLATFORM_CELL         0x1000
-
-/* Compatibility with drivers coming from PPC32 world */
-#define _machine	(systemcfg->platform)
-#define _MACH_Pmac	PLATFORM_POWERMAC
-#endif
 
 /*
  * Default implementation of macro that returns current
@@ -171,8 +177,8 @@
 #ifdef CONFIG_PPC64
 	unsigned long	start_tb;	/* Start purr when proc switched in */
 	unsigned long	accum_tb;	/* Total accumilated purr for process */
-	unsigned long	vdso_base;	/* base of the vDSO library */
 #endif
+	unsigned long	vdso_base;	/* base of the vDSO library */
 	unsigned long	dabr;		/* Data address breakpoint register */
 #ifdef CONFIG_ALTIVEC
 	/* Complete AltiVec register set */
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index 489cf4c..eb392d0 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -16,7 +16,11 @@
 /* Pickup Book E specific registers. */
 #if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
 #include <asm/reg_booke.h>
-#endif
+#endif /* CONFIG_BOOKE || CONFIG_40x */
+
+#ifdef CONFIG_8xx
+#include <asm/reg_8xx.h>
+#endif /* CONFIG_8xx */
 
 #define MSR_SF_LG	63              /* Enable 64 bit mode */
 #define MSR_ISF_LG	61              /* Interrupt 64b mode valid on 630 */
@@ -359,6 +363,7 @@
 #define SPRN_RPA	0x3D6	/* Required Physical Address Register */
 #define SPRN_SDA	0x3BF	/* Sampled Data Address Register */
 #define SPRN_SDR1	0x019	/* MMU Hash Base Register */
+#define SPRN_ASR	0x118   /* Address Space Register */
 #define SPRN_SIA	0x3BB	/* Sampled Instruction Address Register */
 #define SPRN_SPRG0	0x110	/* Special Purpose Register General 0 */
 #define SPRN_SPRG1	0x111	/* Special Purpose Register General 1 */
diff --git a/include/asm-powerpc/reg_8xx.h b/include/asm-powerpc/reg_8xx.h
new file mode 100644
index 0000000..e8ea346
--- /dev/null
+++ b/include/asm-powerpc/reg_8xx.h
@@ -0,0 +1,42 @@
+/*
+ * Contains register definitions common to PowerPC 8xx CPUs.  Notice
+ */
+#ifndef _ASM_POWERPC_REG_8xx_H
+#define _ASM_POWERPC_REG_8xx_H
+
+/* Cache control on the MPC8xx is provided through some additional
+ * special purpose registers.
+ */
+#define SPRN_IC_CST	560	/* Instruction cache control/status */
+#define SPRN_IC_ADR	561	/* Address needed for some commands */
+#define SPRN_IC_DAT	562	/* Read-only data register */
+#define SPRN_DC_CST	568	/* Data cache control/status */
+#define SPRN_DC_ADR	569	/* Address needed for some commands */
+#define SPRN_DC_DAT	570	/* Read-only data register */
+
+/* Commands.  Only the first few are available to the instruction cache.
+*/
+#define	IDC_ENABLE	0x02000000	/* Cache enable */
+#define IDC_DISABLE	0x04000000	/* Cache disable */
+#define IDC_LDLCK	0x06000000	/* Load and lock */
+#define IDC_UNLINE	0x08000000	/* Unlock line */
+#define IDC_UNALL	0x0a000000	/* Unlock all */
+#define IDC_INVALL	0x0c000000	/* Invalidate all */
+
+#define DC_FLINE	0x0e000000	/* Flush data cache line */
+#define DC_SFWT		0x01000000	/* Set forced writethrough mode */
+#define DC_CFWT		0x03000000	/* Clear forced writethrough mode */
+#define DC_SLES		0x05000000	/* Set little endian swap mode */
+#define DC_CLES		0x07000000	/* Clear little endian swap mode */
+
+/* Status.
+*/
+#define IDC_ENABLED	0x80000000	/* Cache is enabled */
+#define IDC_CERR1	0x00200000	/* Cache error 1 */
+#define IDC_CERR2	0x00100000	/* Cache error 2 */
+#define IDC_CERR3	0x00080000	/* Cache error 3 */
+
+#define DC_DFWT		0x40000000	/* Data cache is forced write through */
+#define DC_LES		0x20000000	/* Caches are little endian mode */
+
+#endif /* _ASM_POWERPC_REG_8xx_H */
diff --git a/include/asm-ppc/signal.h b/include/asm-powerpc/signal.h
similarity index 82%
rename from include/asm-ppc/signal.h
rename to include/asm-powerpc/signal.h
index caf6ede..694c8d2 100644
--- a/include/asm-ppc/signal.h
+++ b/include/asm-powerpc/signal.h
@@ -1,18 +1,11 @@
-#ifndef _ASMPPC_SIGNAL_H
-#define _ASMPPC_SIGNAL_H
+#ifndef _ASM_POWERPC_SIGNAL_H
+#define _ASM_POWERPC_SIGNAL_H
 
-#ifdef __KERNEL__
 #include <linux/types.h>
-#endif /* __KERNEL__ */
-
-/* Avoid too many header ordering problems.  */
-struct siginfo;
-
-/* Most things should be clean enough to redefine this at will, if care
-   is taken to make libc match.  */
+#include <linux/config.h>
 
 #define _NSIG		64
-#define _NSIG_BPW	32
+#define _NSIG_BPW	BITS_PER_LONG
 #define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
 
 typedef unsigned long old_sigset_t;		/* at least 32 bits */
@@ -77,19 +70,19 @@
  * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
  * Unix names RESETHAND and NODEFER respectively.
  */
-#define SA_NOCLDSTOP	0x00000001
-#define SA_NOCLDWAIT	0x00000002
-#define SA_SIGINFO	0x00000004
-#define SA_ONSTACK	0x08000000
-#define SA_RESTART	0x10000000
-#define SA_NODEFER	0x40000000
-#define SA_RESETHAND	0x80000000
+#define SA_NOCLDSTOP	0x00000001U
+#define SA_NOCLDWAIT	0x00000002U
+#define SA_SIGINFO	0x00000004U
+#define SA_ONSTACK	0x08000000U
+#define SA_RESTART	0x10000000U
+#define SA_NODEFER	0x40000000U
+#define SA_RESETHAND	0x80000000U
 
 #define SA_NOMASK	SA_NODEFER
 #define SA_ONESHOT	SA_RESETHAND
-#define SA_INTERRUPT	0x20000000 /* dummy -- ignored */
+#define SA_INTERRUPT	0x20000000u /* dummy -- ignored */
 
-#define SA_RESTORER	0x04000000
+#define SA_RESTORER	0x04000000U
 
 /*
  * sigaltstack controls
@@ -127,10 +120,13 @@
 } stack_t;
 
 #ifdef __KERNEL__
-#include <asm/sigcontext.h>
+struct pt_regs;
+extern int do_signal(sigset_t *oldset, struct pt_regs *regs);
+extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
 #define ptrace_signal_deliver(regs, cookie) do { } while (0)
 #endif /* __KERNEL__ */
 
+#ifndef __powerpc64__
 /*
  * These are parameters to dbg_sigreturn syscall.  They enable or
  * disable certain debugging things that can be done from signal
@@ -149,5 +145,6 @@
 
 /* Enable or disable branch tracing.  The value sets the state. */
 #define SIG_DBG_BRANCH_TRACING		2
+#endif /* ! __powerpc64__ */
 
-#endif
+#endif /* _ASM_POWERPC_SIGNAL_H */
diff --git a/include/asm-powerpc/sparsemem.h b/include/asm-powerpc/sparsemem.h
index 1c95ab9..ba1b34f 100644
--- a/include/asm-powerpc/sparsemem.h
+++ b/include/asm-powerpc/sparsemem.h
@@ -8,8 +8,12 @@
  * MAX_PHYSMEM_BITS		2^N: how much memory we can have in that space
  */
 #define SECTION_SIZE_BITS       24
-#define MAX_PHYSADDR_BITS       38
-#define MAX_PHYSMEM_BITS        36
+#define MAX_PHYSADDR_BITS       44
+#define MAX_PHYSMEM_BITS        44
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+extern void create_section_mapping(unsigned long start, unsigned long end);
+#endif /* CONFIG_MEMORY_HOTPLUG */
 
 #endif /* CONFIG_SPARSEMEM */
 
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index 3536a5c..5341b75 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -8,7 +8,6 @@
 #include <linux/kernel.h>
 
 #include <asm/hw_irq.h>
-#include <asm/ppc_asm.h>
 #include <asm/atomic.h>
 
 /*
@@ -180,6 +179,7 @@
 extern unsigned int rtas_data;
 extern int mem_init_done;	/* set on boot once kmalloc can be called */
 extern unsigned long memory_limit;
+extern unsigned long klimit;
 
 extern int powersave_nap;	/* set if nap mode can be used in idle loop */
 
diff --git a/include/asm-ppc64/tce.h b/include/asm-powerpc/tce.h
similarity index 95%
rename from include/asm-ppc64/tce.h
rename to include/asm-powerpc/tce.h
index d40b6b4..d099d52 100644
--- a/include/asm-ppc64/tce.h
+++ b/include/asm-powerpc/tce.h
@@ -18,8 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#ifndef _ASM_TCE_H
-#define _ASM_TCE_H
+#ifndef _ASM_POWERPC_TCE_H
+#define _ASM_POWERPC_TCE_H
 
 /*
  * Tces come in two formats, one for the virtual bus and a different
@@ -61,4 +61,4 @@
 };
 
 
-#endif
+#endif /* _ASM_POWERPC_TCE_H */
diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h
index 2512e38..015d287 100644
--- a/include/asm-powerpc/topology.h
+++ b/include/asm-powerpc/topology.h
@@ -9,15 +9,7 @@
 
 static inline int cpu_to_node(int cpu)
 {
-	int node;
-
-	node = numa_cpu_lookup_table[cpu];
-
-#ifdef DEBUG_NUMA
-	BUG_ON(node == -1);
-#endif
-
-	return node;
+	return numa_cpu_lookup_table[cpu];
 }
 
 #define parent_node(node)	(node)
@@ -37,8 +29,6 @@
 #define pcibus_to_node(node)    (-1)
 #define pcibus_to_cpumask(bus)	(cpu_online_map)
 
-#define nr_cpus_node(node)	(nr_cpus_in_node[node])
-
 /* sched_domains SD_NODE_INIT for PPC64 machines */
 #define SD_NODE_INIT (struct sched_domain) {		\
 	.span			= CPU_MASK_NONE,	\
diff --git a/include/asm-powerpc/uaccess.h b/include/asm-powerpc/uaccess.h
index 33af730..3872e92 100644
--- a/include/asm-powerpc/uaccess.h
+++ b/include/asm-powerpc/uaccess.h
@@ -120,14 +120,6 @@
 
 extern long __put_user_bad(void);
 
-#ifdef __powerpc64__
-#define __EX_TABLE_ALIGN	"3"
-#define __EX_TABLE_TYPE		"llong"
-#else
-#define __EX_TABLE_ALIGN	"2"
-#define __EX_TABLE_TYPE		"long"
-#endif
-
 /*
  * We don't tell gcc that we are accessing memory, but this is OK
  * because we do not write to any memory gcc knows about, so there
@@ -142,11 +134,12 @@
 		"	b 2b\n"					\
 		".previous\n"					\
 		".section __ex_table,\"a\"\n"			\
-		"	.align " __EX_TABLE_ALIGN "\n"		\
-		"	."__EX_TABLE_TYPE" 1b,3b\n"		\
+		"	.balign %5\n"				\
+			PPC_LONG "1b,3b\n"			\
 		".previous"					\
 		: "=r" (err)					\
-		: "r" (x), "b" (addr), "i" (-EFAULT), "0" (err))
+		: "r" (x), "b" (addr), "i" (-EFAULT), "0" (err),\
+		  "i"(sizeof(unsigned long)))
 
 #ifdef __powerpc64__
 #define __put_user_asm2(x, ptr, retval)				\
@@ -162,12 +155,13 @@
 		"	b 3b\n"					\
 		".previous\n"					\
 		".section __ex_table,\"a\"\n"			\
-		"	.align " __EX_TABLE_ALIGN "\n"		\
-		"	." __EX_TABLE_TYPE " 1b,4b\n"		\
-		"	." __EX_TABLE_TYPE " 2b,4b\n"		\
+		"	.balign %5\n"				\
+			PPC_LONG "1b,4b\n"			\
+			PPC_LONG "2b,4b\n"			\
 		".previous"					\
 		: "=r" (err)					\
-		: "r" (x), "b" (addr), "i" (-EFAULT), "0" (err))
+		: "r" (x), "b" (addr), "i" (-EFAULT), "0" (err),\
+		  "i"(sizeof(unsigned long)))
 #endif /* __powerpc64__ */
 
 #define __put_user_size(x, ptr, size, retval)			\
@@ -213,11 +207,12 @@
 		"	b 2b\n"				\
 		".previous\n"				\
 		".section __ex_table,\"a\"\n"		\
-		"	.align "__EX_TABLE_ALIGN "\n"	\
-		"	." __EX_TABLE_TYPE " 1b,3b\n"	\
+		"	.balign %5\n"			\
+			PPC_LONG "1b,3b\n"		\
 		".previous"				\
 		: "=r" (err), "=r" (x)			\
-		: "b" (addr), "i" (-EFAULT), "0" (err))
+		: "b" (addr), "i" (-EFAULT), "0" (err),	\
+		  "i"(sizeof(unsigned long)))
 
 #ifdef __powerpc64__
 #define __get_user_asm2(x, addr, err)			\
@@ -235,12 +230,13 @@
 		"	b 3b\n"				\
 		".previous\n"				\
 		".section __ex_table,\"a\"\n"		\
-		"	.align " __EX_TABLE_ALIGN "\n"	\
-		"	." __EX_TABLE_TYPE " 1b,4b\n"	\
-		"	." __EX_TABLE_TYPE " 2b,4b\n"	\
+		"	.balign %5\n"			\
+			PPC_LONG "1b,4b\n"		\
+			PPC_LONG "2b,4b\n"		\
 		".previous"				\
 		: "=r" (err), "=&r" (x)			\
-		: "b" (addr), "i" (-EFAULT), "0" (err))
+		: "b" (addr), "i" (-EFAULT), "0" (err),	\
+		  "i"(sizeof(unsigned long)))
 #endif /* __powerpc64__ */
 
 #define __get_user_size(x, ptr, size, retval)			\
diff --git a/include/asm-ppc64/udbg.h b/include/asm-powerpc/udbg.h
similarity index 90%
rename from include/asm-ppc64/udbg.h
rename to include/asm-powerpc/udbg.h
index e3b9279..a383383 100644
--- a/include/asm-ppc64/udbg.h
+++ b/include/asm-powerpc/udbg.h
@@ -1,9 +1,3 @@
-#ifndef __UDBG_HDR
-#define __UDBG_HDR
-
-#include <linux/compiler.h>
-#include <linux/init.h>
-
 /*
  * c 2001 PPC 64 Team, IBM Corp
  *
@@ -13,6 +7,12 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#ifndef _ASM_POWERPC_UDBG_H
+#define _ASM_POWERPC_UDBG_H
+
+#include <linux/compiler.h>
+#include <linux/init.h>
+
 extern void (*udbg_putc)(unsigned char c);
 extern unsigned char (*udbg_getc)(void);
 extern int (*udbg_getc_poll)(void);
@@ -28,4 +28,4 @@
 
 struct device_node;
 extern void udbg_init_scc(struct device_node *np);
-#endif
+#endif /* _ASM_POWERPC_UDBG_H */
diff --git a/include/asm-ppc64/vdso.h b/include/asm-powerpc/vdso.h
similarity index 100%
rename from include/asm-ppc64/vdso.h
rename to include/asm-powerpc/vdso.h
diff --git a/include/asm-powerpc/vdso_datapage.h b/include/asm-powerpc/vdso_datapage.h
new file mode 100644
index 0000000..fc323b5
--- /dev/null
+++ b/include/asm-powerpc/vdso_datapage.h
@@ -0,0 +1,108 @@
+#ifndef _VDSO_DATAPAGE_H
+#define _VDSO_DATAPAGE_H
+
+/*
+ * Copyright (C) 2002 Peter Bergner <bergner@vnet.ibm.com>, IBM
+ * Copyright (C) 2005 Benjamin Herrenschmidy <benh@kernel.crashing.org>,
+ * 		      IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+/*
+ * Note about this structure:
+ *
+ * This structure was historically called systemcfg and exposed to
+ * userland via /proc/ppc64/systemcfg. Unfortunately, this became an
+ * ABI issue as some proprietary software started relying on being able
+ * to mmap() it, thus we have to keep the base layout at least for a
+ * few kernel versions.
+ *
+ * However, since ppc32 doesn't suffer from this backward handicap,
+ * a simpler version of the data structure is used there with only the
+ * fields actually used by the vDSO.
+ *
+ */
+
+/*
+ * If the major version changes we are incompatible.
+ * Minor version changes are a hint.
+ */
+#define SYSTEMCFG_MAJOR 1
+#define SYSTEMCFG_MINOR 1
+
+#ifndef __ASSEMBLY__
+
+#include <linux/unistd.h>
+
+#define SYSCALL_MAP_SIZE      ((__NR_syscalls + 31) / 32)
+
+/*
+ * So here is the ppc64 backward compatible version
+ */
+
+#ifdef CONFIG_PPC64
+
+struct vdso_data {
+	__u8  eye_catcher[16];		/* Eyecatcher: SYSTEMCFG:PPC64	0x00 */
+	struct {			/* Systemcfg version numbers	     */
+		__u32 major;		/* Major number			0x10 */
+		__u32 minor;		/* Minor number			0x14 */
+	} version;
+
+	__u32 platform;			/* Platform flags		0x18 */
+	__u32 processor;		/* Processor type		0x1C */
+	__u64 processorCount;		/* # of physical processors	0x20 */
+	__u64 physicalMemorySize;	/* Size of real memory(B)	0x28 */
+	__u64 tb_orig_stamp;		/* Timebase at boot		0x30 */
+	__u64 tb_ticks_per_sec;		/* Timebase tics / sec		0x38 */
+	__u64 tb_to_xs;			/* Inverse of TB to 2^20	0x40 */
+	__u64 stamp_xsec;		/*				0x48 */
+	__u64 tb_update_count;		/* Timebase atomicity ctr	0x50 */
+	__u32 tz_minuteswest;		/* Minutes west of Greenwich	0x58 */
+	__u32 tz_dsttime;		/* Type of dst correction	0x5C */
+	__u32 dcache_size;		/* L1 d-cache size		0x60 */
+	__u32 dcache_line_size;		/* L1 d-cache line size		0x64 */
+	__u32 icache_size;		/* L1 i-cache size		0x68 */
+	__u32 icache_line_size;		/* L1 i-cache line size		0x6C */
+
+	/* those additional ones don't have to be located anywhere
+	 * special as they were not part of the original systemcfg
+	 */
+	__s64 wtom_clock_sec;			/* Wall to monotonic clock */
+	__s32 wtom_clock_nsec;
+   	__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls  */
+   	__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
+};
+
+#else /* CONFIG_PPC64 */
+
+/*
+ * And here is the simpler 32 bits version
+ */
+struct vdso_data {
+	__u64 tb_orig_stamp;		/* Timebase at boot		0x30 */
+	__u64 tb_ticks_per_sec;		/* Timebase tics / sec		0x38 */
+	__u64 tb_to_xs;			/* Inverse of TB to 2^20	0x40 */
+	__u64 stamp_xsec;		/*				0x48 */
+	__u32 tb_update_count;		/* Timebase atomicity ctr	0x50 */
+	__u32 tz_minuteswest;		/* Minutes west of Greenwich	0x58 */
+	__u32 tz_dsttime;		/* Type of dst correction	0x5C */
+	__s32 wtom_clock_sec;			/* Wall to monotonic clock */
+	__s32 wtom_clock_nsec;
+   	__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
+};
+
+#endif /* CONFIG_PPC64 */
+
+#ifdef __KERNEL__
+extern struct vdso_data *vdso_data;
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _SYSTEMCFG_H */
diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h
index ace2072..43f7129 100644
--- a/include/asm-powerpc/xmon.h
+++ b/include/asm-powerpc/xmon.h
@@ -7,7 +7,6 @@
 extern int xmon(struct pt_regs *excp);
 extern void xmon_printf(const char *fmt, ...);
 extern void xmon_init(int);
-extern void xmon_map_scc(void);
 
 #endif
 #endif
diff --git a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h
deleted file mode 100644
index 7a157d0..0000000
--- a/include/asm-ppc/cache.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * include/asm-ppc/cache.h
- */
-#ifdef __KERNEL__
-#ifndef __ARCH_PPC_CACHE_H
-#define __ARCH_PPC_CACHE_H
-
-#include <linux/config.h>
-
-/* bytes per L1 cache line */
-#if defined(CONFIG_8xx) || defined(CONFIG_403GCX)
-#define L1_CACHE_SHIFT	4
-#define MAX_COPY_PREFETCH	1
-#elif defined(CONFIG_PPC64BRIDGE)
-#define L1_CACHE_SHIFT	7
-#define MAX_COPY_PREFETCH	1
-#else
-#define L1_CACHE_SHIFT	5
-#define MAX_COPY_PREFETCH	4
-#endif
-
-#define	L1_CACHE_BYTES	(1 << L1_CACHE_SHIFT)
-
-#define	SMP_CACHE_BYTES L1_CACHE_BYTES
-#define L1_CACHE_SHIFT_MAX 7	/* largest L1 which this arch supports */
-
-#define	L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
-#define	L1_CACHE_PAGES		8
-
-#ifndef __ASSEMBLY__
-extern void clean_dcache_range(unsigned long start, unsigned long stop);
-extern void flush_dcache_range(unsigned long start, unsigned long stop);
-extern void invalidate_dcache_range(unsigned long start, unsigned long stop);
-extern void flush_dcache_all(void);
-#endif /* __ASSEMBLY__ */
-
-/* prep registers for L2 */
-#define CACHECRBA       0x80000823      /* Cache configuration register address */
-#define L2CACHE_MASK	0x03	/* Mask for 2 L2 Cache bits */
-#define L2CACHE_512KB	0x00	/* 512KB */
-#define L2CACHE_256KB	0x01	/* 256KB */
-#define L2CACHE_1MB	0x02	/* 1MB */
-#define L2CACHE_NONE	0x03	/* NONE */
-#define L2CACHE_PARITY  0x08    /* Mask for L2 Cache Parity Protected bit */
-
-#ifdef CONFIG_8xx
-/* Cache control on the MPC8xx is provided through some additional
- * special purpose registers.
- */
-#define SPRN_IC_CST	560	/* Instruction cache control/status */
-#define SPRN_IC_ADR	561	/* Address needed for some commands */
-#define SPRN_IC_DAT	562	/* Read-only data register */
-#define SPRN_DC_CST	568	/* Data cache control/status */
-#define SPRN_DC_ADR	569	/* Address needed for some commands */
-#define SPRN_DC_DAT	570	/* Read-only data register */
-
-/* Commands.  Only the first few are available to the instruction cache.
-*/
-#define	IDC_ENABLE	0x02000000	/* Cache enable */
-#define IDC_DISABLE	0x04000000	/* Cache disable */
-#define IDC_LDLCK	0x06000000	/* Load and lock */
-#define IDC_UNLINE	0x08000000	/* Unlock line */
-#define IDC_UNALL	0x0a000000	/* Unlock all */
-#define IDC_INVALL	0x0c000000	/* Invalidate all */
-
-#define DC_FLINE	0x0e000000	/* Flush data cache line */
-#define DC_SFWT		0x01000000	/* Set forced writethrough mode */
-#define DC_CFWT		0x03000000	/* Clear forced writethrough mode */
-#define DC_SLES		0x05000000	/* Set little endian swap mode */
-#define DC_CLES		0x07000000	/* Clear little endian swap mode */
-
-/* Status.
-*/
-#define IDC_ENABLED	0x80000000	/* Cache is enabled */
-#define IDC_CERR1	0x00200000	/* Cache error 1 */
-#define IDC_CERR2	0x00100000	/* Cache error 2 */
-#define IDC_CERR3	0x00080000	/* Cache error 3 */
-
-#define DC_DFWT		0x40000000	/* Data cache is forced write through */
-#define DC_LES		0x20000000	/* Caches are little endian mode */
-#endif /* CONFIG_8xx */
-
-#endif
-#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/cacheflush.h b/include/asm-ppc/cacheflush.h
deleted file mode 100644
index 6a243ef..0000000
--- a/include/asm-ppc/cacheflush.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * include/asm-ppc/cacheflush.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.
- */
-#ifdef __KERNEL__
-#ifndef _PPC_CACHEFLUSH_H
-#define _PPC_CACHEFLUSH_H
-
-#include <linux/mm.h>
-
-/*
- * No cache flushing is required when address mappings are
- * changed, because the caches on PowerPCs are physically
- * addressed.  -- paulus
- * Also, when SMP we use the coherency (M) bit of the
- * BATs and PTEs.  -- Cort
- */
-#define flush_cache_all()		do { } while (0)
-#define flush_cache_mm(mm)		do { } while (0)
-#define flush_cache_range(vma, a, b)	do { } while (0)
-#define flush_cache_page(vma, p, pfn)	do { } while (0)
-#define flush_icache_page(vma, page)	do { } while (0)
-#define flush_cache_vmap(start, end)	do { } while (0)
-#define flush_cache_vunmap(start, end)	do { } while (0)
-
-extern void flush_dcache_page(struct page *page);
-#define flush_dcache_mmap_lock(mapping)		do { } while (0)
-#define flush_dcache_mmap_unlock(mapping)	do { } while (0)
-
-extern void flush_icache_range(unsigned long, unsigned long);
-extern void flush_icache_user_range(struct vm_area_struct *vma,
-		struct page *page, unsigned long addr, int len);
-
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-do { memcpy(dst, src, len); \
-     flush_icache_user_range(vma, page, vaddr, len); \
-} while (0)
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-	memcpy(dst, src, len)
-
-extern void __flush_dcache_icache(void *page_va);
-extern void __flush_dcache_icache_phys(unsigned long physaddr);
-extern void flush_dcache_icache_page(struct page *page);
-#endif /* _PPC_CACHEFLUSH_H */
-#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/current.h b/include/asm-ppc/current.h
deleted file mode 100644
index 8d41501..0000000
--- a/include/asm-ppc/current.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifdef __KERNEL__
-#ifndef _PPC_CURRENT_H
-#define _PPC_CURRENT_H
-
-/*
- * We keep `current' in r2 for speed.
- */
-register struct task_struct *current asm ("r2");
-
-#endif /* !(_PPC_CURRENT_H) */
-#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mpc83xx.h b/include/asm-ppc/mpc83xx.h
index bb1b057..ce21220 100644
--- a/include/asm-ppc/mpc83xx.h
+++ b/include/asm-ppc/mpc83xx.h
@@ -107,6 +107,7 @@
 	MPC83xx_SEC2,
 	MPC83xx_USB2_DR,
 	MPC83xx_USB2_MPH,
+	MPC83xx_MDIO,
 };
 
 #endif /* CONFIG_83xx */
diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h
index fc44f7c..538e0c8 100644
--- a/include/asm-ppc/page.h
+++ b/include/asm-ppc/page.h
@@ -1,9 +1,12 @@
 #ifndef _PPC_PAGE_H
 #define _PPC_PAGE_H
 
+#include <linux/config.h>
+#include <asm/asm-compat.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
-#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#define PAGE_SIZE	(ASM_CONST(1) << PAGE_SHIFT)
 
 /*
  * Subtle: this is an int (not an unsigned long) and so it
@@ -169,5 +172,8 @@
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
+/* We do define AT_SYSINFO_EHDR but don't use the gate mecanism */
+#define __HAVE_ARCH_GATE_AREA		1
+
 #endif /* __KERNEL__ */
 #endif /* _PPC_PAGE_H */
diff --git a/include/asm-ppc64/cache.h b/include/asm-ppc64/cache.h
deleted file mode 100644
index 92140a7..0000000
--- a/include/asm-ppc64/cache.h
+++ /dev/null
@@ -1,36 +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.
- */
-#ifndef __ARCH_PPC64_CACHE_H
-#define __ARCH_PPC64_CACHE_H
-
-#include <asm/types.h>
-
-/* bytes per L1 cache line */
-#define L1_CACHE_SHIFT	7
-#define L1_CACHE_BYTES	(1 << L1_CACHE_SHIFT)
-
-#define SMP_CACHE_BYTES L1_CACHE_BYTES
-#define L1_CACHE_SHIFT_MAX 7	/* largest L1 which this arch supports */
-
-#ifndef __ASSEMBLY__
-
-struct ppc64_caches {
-	u32	dsize;			/* L1 d-cache size */
-	u32	dline_size;		/* L1 d-cache line size	*/
-	u32	log_dline_size;
-	u32	dlines_per_page;
-	u32	isize;			/* L1 i-cache size */
-	u32	iline_size;		/* L1 i-cache line size	*/
-	u32	log_iline_size;
-	u32	ilines_per_page;
-};
-
-extern struct ppc64_caches ppc64_caches;
-
-#endif
-
-#endif
diff --git a/include/asm-ppc64/cacheflush.h b/include/asm-ppc64/cacheflush.h
deleted file mode 100644
index ffbc08b..0000000
--- a/include/asm-ppc64/cacheflush.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef _PPC64_CACHEFLUSH_H
-#define _PPC64_CACHEFLUSH_H
-
-#include <linux/mm.h>
-#include <asm/cputable.h>
-
-/*
- * No cache flushing is required when address mappings are
- * changed, because the caches on PowerPCs are physically
- * addressed.
- */
-#define flush_cache_all()			do { } while (0)
-#define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(vma, start, end)	do { } while (0)
-#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
-#define flush_icache_page(vma, page)		do { } while (0)
-#define flush_cache_vmap(start, end)		do { } while (0)
-#define flush_cache_vunmap(start, end)		do { } while (0)
-
-extern void flush_dcache_page(struct page *page);
-#define flush_dcache_mmap_lock(mapping)		do { } while (0)
-#define flush_dcache_mmap_unlock(mapping)	do { } while (0)
-
-extern void __flush_icache_range(unsigned long, unsigned long);
-extern void flush_icache_user_range(struct vm_area_struct *vma,
-				    struct page *page, unsigned long addr,
-				    int len);
-
-extern void flush_dcache_range(unsigned long start, unsigned long stop);
-extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
-extern void flush_inval_dcache_range(unsigned long start, unsigned long stop);
-
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-do { memcpy(dst, src, len); \
-     flush_icache_user_range(vma, page, vaddr, len); \
-} while (0)
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-	memcpy(dst, src, len)
-
-extern void __flush_dcache_icache(void *page_va);
-
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-	if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
-		__flush_icache_range(start, stop);
-}
-
-#endif /* _PPC64_CACHEFLUSH_H */
diff --git a/include/asm-ppc64/current.h b/include/asm-ppc64/current.h
deleted file mode 100644
index 52ddc60..0000000
--- a/include/asm-ppc64/current.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _PPC64_CURRENT_H
-#define _PPC64_CURRENT_H
-
-#include <asm/paca.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.
- */
-
-#define get_current()   (get_paca()->__current)
-#define current         get_current()
-
-#endif /* !(_PPC64_CURRENT_H) */
diff --git a/include/asm-ppc64/eeh.h b/include/asm-ppc64/eeh.h
index 40c8eb5..89f26ab 100644
--- a/include/asm-ppc64/eeh.h
+++ b/include/asm-ppc64/eeh.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * eeh.h
  * Copyright (C) 2001  Dave Engebretsen & Todd Inglett IBM Corporation.
  *
@@ -6,12 +6,12 @@
  * 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
@@ -27,8 +27,6 @@
 
 struct pci_dev;
 struct device_node;
-struct device_node;
-struct notifier_block;
 
 #ifdef CONFIG_EEH
 
@@ -37,6 +35,10 @@
 #define EEH_MODE_NOCHECK	(1<<1)
 #define EEH_MODE_ISOLATED	(1<<2)
 
+/* Max number of EEH freezes allowed before we consider the device
+ * to be permanently disabled. */
+#define EEH_MAX_ALLOWED_FREEZES 5
+
 void __init eeh_init(void);
 unsigned long eeh_check_failure(const volatile void __iomem *token,
 				unsigned long val);
@@ -59,36 +61,14 @@
  * eeh_remove_device - undo EEH setup for the indicated pci device
  * @dev: pci device to be removed
  *
- * This routine should be when a device is removed from a running
- * system (e.g. by hotplug or dlpar).
+ * This routine should be called when a device is removed from
+ * a running system (e.g. by hotplug or dlpar).  It unregisters
+ * the PCI device from the EEH subsystem.  I/O errors affecting
+ * this device will no longer be detected after this call; thus,
+ * i/o errors affecting this slot may leave this device unusable.
  */
 void eeh_remove_device(struct pci_dev *);
 
-#define EEH_DISABLE		0
-#define EEH_ENABLE		1
-#define EEH_RELEASE_LOADSTORE	2
-#define EEH_RELEASE_DMA		3
-
-/**
- * Notifier event flags.
- */
-#define EEH_NOTIFY_FREEZE  1
-
-/** EEH event -- structure holding pci slot data that describes
- *  a change in the isolation status of a PCI slot.  A pointer
- *  to this struct is passed as the data pointer in a notify callback.
- */
-struct eeh_event {
-	struct list_head     list;
-	struct pci_dev       *dev;
-	struct device_node   *dn;
-	int                  reset_state;
-};
-
-/** Register to find out about EEH events. */
-int eeh_register_notifier(struct notifier_block *nb);
-int eeh_unregister_notifier(struct notifier_block *nb);
-
 /**
  * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
  *
@@ -129,7 +109,7 @@
 #define EEH_IO_ERROR_VALUE(size) (-1UL)
 #endif /* CONFIG_EEH */
 
-/* 
+/*
  * MMIO read/write operations with EEH support.
  */
 static inline u8 eeh_readb(const volatile void __iomem *addr)
diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h
index 4c18a5c..1a7e0af 100644
--- a/include/asm-ppc64/mmu.h
+++ b/include/asm-ppc64/mmu.h
@@ -14,7 +14,7 @@
 #define _PPC64_MMU_H_
 
 #include <linux/config.h>
-#include <asm/ppc_asm.h> /* for ASM_CONST */
+#include <asm/asm-compat.h>
 #include <asm/page.h>
 
 /*
@@ -224,9 +224,12 @@
 			     unsigned long pstart, unsigned long mode,
 			     int psize);
 
+extern void htab_initialize(void);
+extern void htab_initialize_secondary(void);
 extern void hpte_init_native(void);
 extern void hpte_init_lpar(void);
 extern void hpte_init_iSeries(void);
+extern void mm_init_ppc64(void);
 
 extern long pSeries_lpar_hpte_insert(unsigned long hpte_group,
 				     unsigned long va, unsigned long prpn,
@@ -245,6 +248,7 @@
 
 extern void stabs_alloc(void);
 extern void slb_initialize(void);
+extern void stab_initialize(unsigned long stab);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h
index 80a708e..54958d6 100644
--- a/include/asm-ppc64/mmzone.h
+++ b/include/asm-ppc64/mmzone.h
@@ -8,15 +8,14 @@
 #define _ASM_MMZONE_H_
 
 #include <linux/config.h>
-#include <asm/smp.h>
 
-/* generic non-linear memory support:
+/*
+ * generic non-linear memory support:
  *
  * 1) we will not split memory into more chunks than will fit into the
  *    flags field of the struct page
  */
 
-
 #ifdef CONFIG_NEED_MULTIPLE_NODES
 
 extern struct pglist_data *node_data[];
@@ -30,36 +29,11 @@
  */
 
 extern int numa_cpu_lookup_table[];
-extern char *numa_memory_lookup_table;
 extern cpumask_t numa_cpumask_lookup_table[];
-extern int nr_cpus_in_node[];
-
-/* 16MB regions */
-#define MEMORY_INCREMENT_SHIFT 24
-#define MEMORY_INCREMENT (1UL << MEMORY_INCREMENT_SHIFT)
-
-/* NUMA debugging, will not work on a DLPAR machine */
-#undef DEBUG_NUMA
-
-static inline int pa_to_nid(unsigned long pa)
-{
-	int nid;
-
-	nid = numa_memory_lookup_table[pa >> MEMORY_INCREMENT_SHIFT];
-
-#ifdef DEBUG_NUMA
-	/* the physical address passed in is not in the map for the system */
-	if (nid == -1) {
-		printk("bad address: %lx\n", pa);
-		BUG();
-	}
+#ifdef CONFIG_MEMORY_HOTPLUG
+extern unsigned long max_pfn;
 #endif
 
-	return nid;
-}
-
-#define node_localnr(pfn, nid)	((pfn) - NODE_DATA(nid)->node_start_pfn)
-
 /*
  * Following are macros that each numa implmentation must define.
  */
@@ -67,39 +41,10 @@
 #define node_start_pfn(nid)	(NODE_DATA(nid)->node_start_pfn)
 #define node_end_pfn(nid)	(NODE_DATA(nid)->node_end_pfn)
 
-#ifdef CONFIG_DISCONTIGMEM
-
-/*
- * Given a kernel address, find the home node of the underlying memory.
- */
-#define kvaddr_to_nid(kaddr)	pa_to_nid(__pa(kaddr))
-
-#define pfn_to_nid(pfn)		pa_to_nid((unsigned long)(pfn) << PAGE_SHIFT)
-
-/* Written this way to avoid evaluating arguments twice */
-#define discontigmem_pfn_to_page(pfn) \
-({ \
-	unsigned long __tmp = pfn; \
-	(NODE_DATA(pfn_to_nid(__tmp))->node_mem_map + \
-	 node_localnr(__tmp, pfn_to_nid(__tmp))); \
-})
-
-#define discontigmem_page_to_pfn(p) \
-({ \
-	struct page *__tmp = p; \
-	(((__tmp) - page_zone(__tmp)->zone_mem_map) + \
-	 page_zone(__tmp)->zone_start_pfn); \
-})
-
-/* XXX fix for discontiguous physical memory */
-#define discontigmem_pfn_valid(pfn)		((pfn) < num_physpages)
-
-#endif /* CONFIG_DISCONTIGMEM */
-
 #endif /* CONFIG_NEED_MULTIPLE_NODES */
 
 #ifdef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
-#define early_pfn_to_nid(pfn)  pa_to_nid(((unsigned long)pfn) << PAGE_SHIFT)
+extern int __init early_pfn_to_nid(unsigned long pfn);
 #endif
 
 #endif /* _ASM_MMZONE_H_ */
diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
index 82ce187..3efc328 100644
--- a/include/asm-ppc64/page.h
+++ b/include/asm-ppc64/page.h
@@ -11,7 +11,7 @@
  */
 
 #include <linux/config.h>
-#include <asm/ppc_asm.h> /* for ASM_CONST */
+#include <asm/asm-compat.h>
 
 /*
  * We support either 4k or 64k software page size. When using 64k pages
@@ -279,11 +279,6 @@
 
 #define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
 
-#ifdef CONFIG_DISCONTIGMEM
-#define page_to_pfn(page)	discontigmem_page_to_pfn(page)
-#define pfn_to_page(pfn)	discontigmem_pfn_to_page(pfn)
-#define pfn_valid(pfn)		discontigmem_pfn_valid(pfn)
-#endif
 #ifdef CONFIG_FLATMEM
 #define pfn_to_page(pfn)	(mem_map + (pfn))
 #define page_to_pfn(page)	((unsigned long)((page) - mem_map))
diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h
index 60cf8c8..efbdaec 100644
--- a/include/asm-ppc64/pci-bridge.h
+++ b/include/asm-ppc64/pci-bridge.h
@@ -63,7 +63,6 @@
 	int	devfn;			/* for pci devices */
 	int	eeh_mode;		/* See eeh.h for possible EEH_MODEs */
 	int	eeh_config_addr;
-	int	eeh_capable;		/* from firmware */
 	int 	eeh_check_count;	/* # times driver ignored error */
 	int 	eeh_freeze_count;	/* # times this device froze up. */
 	int	eeh_is_bridge;		/* device is pci-to-pci bridge */
diff --git a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h
index 98da0e4..dcf3622 100644
--- a/include/asm-ppc64/pgalloc.h
+++ b/include/asm-ppc64/pgalloc.h
@@ -10,8 +10,8 @@
 
 #ifdef CONFIG_PPC_64K_PAGES
 #define PTE_CACHE_NUM	0
-#define PMD_CACHE_NUM	0
-#define PGD_CACHE_NUM	1
+#define PMD_CACHE_NUM	1
+#define PGD_CACHE_NUM	2
 #else
 #define PTE_CACHE_NUM	0
 #define PMD_CACHE_NUM	1
diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h
index 76bb026..ddfe186 100644
--- a/include/asm-ppc64/prom.h
+++ b/include/asm-ppc64/prom.h
@@ -204,6 +204,8 @@
 extern unsigned long prom_init(unsigned long, unsigned long, unsigned long,
 	unsigned long, unsigned long);
 extern void finish_device_tree(void);
+extern void unflatten_device_tree(void);
+extern void early_init_devtree(void *);
 extern int device_is_compatible(struct device_node *device, const char *);
 extern int machine_is_compatible(const char *compat);
 extern unsigned char *get_property(struct device_node *node, const char *name,
diff --git a/include/asm-ppc64/signal.h b/include/asm-ppc64/signal.h
deleted file mode 100644
index 432df7dd..0000000
--- a/include/asm-ppc64/signal.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef _ASMPPC64_SIGNAL_H
-#define _ASMPPC64_SIGNAL_H
-
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <asm/siginfo.h>
-
-/* Avoid too many header ordering problems.  */
-struct siginfo;
-
-#define _NSIG		64
-#define _NSIG_BPW	64
-#define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
-
-typedef unsigned long old_sigset_t;		/* at least 32 bits */
-
-typedef struct {
-	unsigned long sig[_NSIG_WORDS];
-} sigset_t;
-
-#define SIGHUP		 1
-#define SIGINT		 2
-#define SIGQUIT		 3
-#define SIGILL		 4
-#define SIGTRAP		 5
-#define SIGABRT		 6
-#define SIGIOT		 6
-#define SIGBUS		 7
-#define SIGFPE		 8
-#define SIGKILL		 9
-#define SIGUSR1		10
-#define SIGSEGV		11
-#define SIGUSR2		12
-#define SIGPIPE		13
-#define SIGALRM		14
-#define SIGTERM		15
-#define SIGSTKFLT	16
-#define SIGCHLD		17
-#define SIGCONT		18
-#define SIGSTOP		19
-#define SIGTSTP		20
-#define SIGTTIN		21
-#define SIGTTOU		22
-#define SIGURG		23
-#define SIGXCPU		24
-#define SIGXFSZ		25
-#define SIGVTALRM	26
-#define SIGPROF		27
-#define SIGWINCH	28
-#define SIGIO		29
-#define SIGPOLL		SIGIO
-/*
-#define SIGLOST		29
-*/
-#define SIGPWR		30
-#define SIGSYS		31
-#define	SIGUNUSED	31
-
-/* These should not be considered constants from userland.  */
-#define SIGRTMIN	32
-#define SIGRTMAX	_NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK is not currently supported, but will allow sigaltstack(2).
- * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP	0x00000001u
-#define SA_NOCLDWAIT	0x00000002u
-#define SA_SIGINFO	0x00000004u
-#define SA_ONSTACK	0x08000000u
-#define SA_RESTART	0x10000000u
-#define SA_NODEFER	0x40000000u
-#define SA_RESETHAND	0x80000000u
-
-#define SA_NOMASK	SA_NODEFER
-#define SA_ONESHOT	SA_RESETHAND
-#define SA_INTERRUPT	0x20000000u /* dummy -- ignored */
-
-#define SA_RESTORER	0x04000000u
-
-/* 
- * sigaltstack controls
- */
-#define SS_ONSTACK	1
-#define SS_DISABLE	2
-
-#define MINSIGSTKSZ	2048
-#define SIGSTKSZ	8192
-
-#include <asm-generic/signal.h>
-
-struct old_sigaction {
-	__sighandler_t sa_handler;
-	old_sigset_t sa_mask;
-	unsigned long sa_flags;
-	__sigrestore_t sa_restorer;
-};
-
-struct sigaction {
-	__sighandler_t sa_handler;
-	unsigned long sa_flags;
-	__sigrestore_t sa_restorer;
-	sigset_t sa_mask;		/* mask last for extensibility */
-};
-
-struct k_sigaction {
-	struct sigaction sa;
-};
-
-typedef struct sigaltstack {
-	void __user *ss_sp;
-	int ss_flags;
-	size_t ss_size;
-} stack_t;
-
-struct pt_regs;
-struct timespec;
-extern int do_signal(sigset_t *oldset, struct pt_regs *regs);
-extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
-#endif /* _ASMPPC64_SIGNAL_H */
diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h
index 0cdd66c..bf9a6ab 100644
--- a/include/asm-ppc64/system.h
+++ b/include/asm-ppc64/system.h
@@ -149,6 +149,8 @@
 extern struct task_struct * _switch(struct thread_struct *prev,
 				    struct thread_struct *next);
 
+extern unsigned long klimit;
+
 extern int powersave_nap;	/* set if nap mode can be used in idle loop */
 
 /*
diff --git a/include/asm-ppc64/systemcfg.h b/include/asm-ppc64/systemcfg.h
deleted file mode 100644
index 9b86b53..0000000
--- a/include/asm-ppc64/systemcfg.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef _SYSTEMCFG_H
-#define _SYSTEMCFG_H
-
-/* 
- * Copyright (C) 2002 Peter Bergner <bergner@vnet.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.
- */
-
-/* Change Activity:
- * 2002/09/30 : bergner  : Created
- * End Change Activity 
- */
-
-/*
- * If the major version changes we are incompatible.
- * Minor version changes are a hint.
- */
-#define SYSTEMCFG_MAJOR 1
-#define SYSTEMCFG_MINOR 1
-
-#ifndef __ASSEMBLY__
-
-#include <linux/unistd.h>
-
-#define SYSCALL_MAP_SIZE      ((__NR_syscalls + 31) / 32)
-
-struct systemcfg {
-	__u8  eye_catcher[16];		/* Eyecatcher: SYSTEMCFG:PPC64	0x00 */
-	struct {			/* Systemcfg version numbers	     */
-		__u32 major;		/* Major number			0x10 */
-		__u32 minor;		/* Minor number			0x14 */
-	} version;
-
-	__u32 platform;			/* Platform flags		0x18 */
-	__u32 processor;		/* Processor type		0x1C */
-	__u64 processorCount;		/* # of physical processors	0x20 */
-	__u64 physicalMemorySize;	/* Size of real memory(B)	0x28 */
-	__u64 tb_orig_stamp;		/* Timebase at boot		0x30 */
-	__u64 tb_ticks_per_sec;		/* Timebase tics / sec		0x38 */
-	__u64 tb_to_xs;			/* Inverse of TB to 2^20	0x40 */
-	__u64 stamp_xsec;		/*				0x48 */
-	__u64 tb_update_count;		/* Timebase atomicity ctr	0x50 */
-	__u32 tz_minuteswest;		/* Minutes west of Greenwich	0x58 */
-	__u32 tz_dsttime;		/* Type of dst correction	0x5C */
-	/* next four are no longer used except to be exported to /proc */
-	__u32 dcache_size;		/* L1 d-cache size		0x60 */
-	__u32 dcache_line_size;		/* L1 d-cache line size		0x64 */
-	__u32 icache_size;		/* L1 i-cache size		0x68 */
-	__u32 icache_line_size;		/* L1 i-cache line size		0x6C */
-   	__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of available syscalls 0x70 */
-   	__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of available syscalls */
-};
-
-#ifdef __KERNEL__
-extern struct systemcfg *systemcfg;
-#endif
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _SYSTEMCFG_H */
diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h
index 7127030..23450ed 100644
--- a/include/asm-s390/debug.h
+++ b/include/asm-s390/debug.h
@@ -129,7 +129,7 @@
 
 void debug_stop_all(void);
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_event(debug_info_t* id, int level, void* data, int length)
 {
 	if ((!id) || (level > id->level) || (id->pages_per_area == 0))
@@ -137,7 +137,7 @@
         return debug_event_common(id,level,data,length);
 }
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_int_event(debug_info_t* id, int level, unsigned int tag)
 {
         unsigned int t=tag;
@@ -146,7 +146,7 @@
         return debug_event_common(id,level,&t,sizeof(unsigned int));
 }
 
-extern inline debug_entry_t *
+static inline debug_entry_t *
 debug_long_event (debug_info_t* id, int level, unsigned long tag)
 {
         unsigned long t=tag;
@@ -155,7 +155,7 @@
         return debug_event_common(id,level,&t,sizeof(unsigned long));
 }
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_text_event(debug_info_t* id, int level, const char* txt)
 {
 	if ((!id) || (level > id->level) || (id->pages_per_area == 0))
@@ -168,7 +168,7 @@
 	__attribute__ ((format(printf, 3, 4)));
 
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_exception(debug_info_t* id, int level, void* data, int length)
 {
 	if ((!id) || (level > id->level) || (id->pages_per_area == 0))
@@ -176,7 +176,7 @@
         return debug_exception_common(id,level,data,length);
 }
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_int_exception(debug_info_t* id, int level, unsigned int tag)
 {
         unsigned int t=tag;
@@ -185,7 +185,7 @@
         return debug_exception_common(id,level,&t,sizeof(unsigned int));
 }
 
-extern inline debug_entry_t * 
+static inline debug_entry_t *
 debug_long_exception (debug_info_t* id, int level, unsigned long tag)
 {
         unsigned long t=tag;
@@ -194,7 +194,7 @@
         return debug_exception_common(id,level,&t,sizeof(unsigned long));
 }
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_text_exception(debug_info_t* id, int level, const char* txt)
 {
 	if ((!id) || (level > id->level) || (id->pages_per_area == 0))
diff --git a/include/asm-s390/ebcdic.h b/include/asm-s390/ebcdic.h
index 20e81e8..4cbc336 100644
--- a/include/asm-s390/ebcdic.h
+++ b/include/asm-s390/ebcdic.h
@@ -21,7 +21,7 @@
 extern __u8 _ebc_tolower[]; /* EBCDIC -> lowercase */
 extern __u8 _ebc_toupper[]; /* EBCDIC -> uppercase */
 
-extern __inline__ void
+static inline void
 codepage_convert(const __u8 *codepage, volatile __u8 * addr, unsigned long nr)
 {
 	if (nr-- <= 0)
diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h
index 8188fdc..71f55eb 100644
--- a/include/asm-s390/io.h
+++ b/include/asm-s390/io.h
@@ -24,7 +24,7 @@
  * Change virtual addresses to physical addresses and vv.
  * These are pretty trivial
  */
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
 {
 	unsigned long real_address;
 	__asm__ (
@@ -42,7 +42,7 @@
         return real_address;
 }
 
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
 {
         return __io_virt(address);
 }
@@ -54,7 +54,7 @@
 
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
-extern inline void * ioremap (unsigned long offset, unsigned long size)
+static inline void * ioremap (unsigned long offset, unsigned long size)
 {
         return __ioremap(offset, size, 0);
 }
@@ -64,7 +64,7 @@
  * it's useful if some control registers are in such an area and write combining
  * or read caching is not desirable:
  */
-extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
+static inline void * ioremap_nocache (unsigned long offset, unsigned long size)
 {
         return __ioremap(offset, size, 0);
 }
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index c6f51c9..db0606c1 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -346,7 +346,7 @@
 #define S390_lowcore (*((struct _lowcore *) 0))
 extern struct _lowcore *lowcore_ptr[];
 
-extern __inline__ void set_prefix(__u32 address)
+static inline void set_prefix(__u32 address)
 {
         __asm__ __volatile__ ("spx %0" : : "m" (address) : "memory" );
 }
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
index 3a3bb3f..bcf24a8 100644
--- a/include/asm-s390/mmu_context.h
+++ b/include/asm-s390/mmu_context.h
@@ -44,7 +44,7 @@
 
 #define deactivate_mm(tsk,mm)	do { } while (0)
 
-extern inline void activate_mm(struct mm_struct *prev,
+static inline void activate_mm(struct mm_struct *prev,
                                struct mm_struct *next)
 {
         switch_mm(prev, next, current);
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 9be741b..859b5e9 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -319,7 +319,7 @@
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
-extern inline void set_pte(pte_t *pteptr, pte_t pteval)
+static inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
 	*pteptr = pteval;
 }
@@ -330,63 +330,63 @@
  */
 #ifndef __s390x__
 
-extern inline int pgd_present(pgd_t pgd) { return 1; }
-extern inline int pgd_none(pgd_t pgd)    { return 0; }
-extern inline int pgd_bad(pgd_t pgd)     { return 0; }
+static inline int pgd_present(pgd_t pgd) { return 1; }
+static inline int pgd_none(pgd_t pgd)    { return 0; }
+static inline int pgd_bad(pgd_t pgd)     { return 0; }
 
-extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; }
-extern inline int pmd_none(pmd_t pmd)    { return pmd_val(pmd) & _PAGE_TABLE_INV; }
-extern inline int pmd_bad(pmd_t pmd)
+static inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; }
+static inline int pmd_none(pmd_t pmd)    { return pmd_val(pmd) & _PAGE_TABLE_INV; }
+static inline int pmd_bad(pmd_t pmd)
 {
 	return (pmd_val(pmd) & (~PAGE_MASK & ~_PAGE_TABLE_INV)) != _PAGE_TABLE;
 }
 
 #else /* __s390x__ */
 
-extern inline int pgd_present(pgd_t pgd)
+static inline int pgd_present(pgd_t pgd)
 {
 	return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY;
 }
 
-extern inline int pgd_none(pgd_t pgd)
+static inline int pgd_none(pgd_t pgd)
 {
 	return pgd_val(pgd) & _PGD_ENTRY_INV;
 }
 
-extern inline int pgd_bad(pgd_t pgd)
+static inline int pgd_bad(pgd_t pgd)
 {
 	return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY;
 }
 
-extern inline int pmd_present(pmd_t pmd)
+static inline int pmd_present(pmd_t pmd)
 {
 	return (pmd_val(pmd) & ~PAGE_MASK) == _PMD_ENTRY;
 }
 
-extern inline int pmd_none(pmd_t pmd)
+static inline int pmd_none(pmd_t pmd)
 {
 	return pmd_val(pmd) & _PMD_ENTRY_INV;
 }
 
-extern inline int pmd_bad(pmd_t pmd)
+static inline int pmd_bad(pmd_t pmd)
 {
 	return (pmd_val(pmd) & (~PAGE_MASK & ~_PMD_ENTRY_INV)) != _PMD_ENTRY;
 }
 
 #endif /* __s390x__ */
 
-extern inline int pte_none(pte_t pte)
+static inline int pte_none(pte_t pte)
 {
 	return (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_EMPTY;
 }
 
-extern inline int pte_present(pte_t pte)
+static inline int pte_present(pte_t pte)
 {
 	return !(pte_val(pte) & _PAGE_INVALID) ||
 		(pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_NONE;
 }
 
-extern inline int pte_file(pte_t pte)
+static inline int pte_file(pte_t pte)
 {
 	return (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_FILE;
 }
@@ -397,12 +397,12 @@
  * query functions pte_write/pte_dirty/pte_young only work if
  * pte_present() is true. Undefined behaviour if not..
  */
-extern inline int pte_write(pte_t pte)
+static inline int pte_write(pte_t pte)
 {
 	return (pte_val(pte) & _PAGE_RO) == 0;
 }
 
-extern inline int pte_dirty(pte_t pte)
+static inline int pte_dirty(pte_t pte)
 {
 	/* A pte is neither clean nor dirty on s/390. The dirty bit
 	 * is in the storage key. See page_test_and_clear_dirty for
@@ -411,7 +411,7 @@
 	return 0;
 }
 
-extern inline int pte_young(pte_t pte)
+static inline int pte_young(pte_t pte)
 {
 	/* A pte is neither young nor old on s/390. The young bit
 	 * is in the storage key. See page_test_and_clear_young for
@@ -420,7 +420,7 @@
 	return 0;
 }
 
-extern inline int pte_read(pte_t pte)
+static inline int pte_read(pte_t pte)
 {
 	/* All pages are readable since we don't use the fetch
 	 * protection bit in the storage key.
@@ -434,9 +434,9 @@
 
 #ifndef __s390x__
 
-extern inline void pgd_clear(pgd_t * pgdp)      { }
+static inline void pgd_clear(pgd_t * pgdp)      { }
 
-extern inline void pmd_clear(pmd_t * pmdp)
+static inline void pmd_clear(pmd_t * pmdp)
 {
 	pmd_val(pmdp[0]) = _PAGE_TABLE_INV;
 	pmd_val(pmdp[1]) = _PAGE_TABLE_INV;
@@ -446,12 +446,12 @@
 
 #else /* __s390x__ */
 
-extern inline void pgd_clear(pgd_t * pgdp)
+static inline void pgd_clear(pgd_t * pgdp)
 {
 	pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY;
 }
 
-extern inline void pmd_clear(pmd_t * pmdp)
+static inline void pmd_clear(pmd_t * pmdp)
 {
 	pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
 	pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
@@ -459,7 +459,7 @@
 
 #endif /* __s390x__ */
 
-extern inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	pte_val(*ptep) = _PAGE_INVALID_EMPTY;
 }
@@ -468,14 +468,14 @@
  * The following pte modification functions only work if
  * pte_present() is true. Undefined behaviour if not..
  */
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
 	pte_val(pte) &= PAGE_MASK;
 	pte_val(pte) |= pgprot_val(newprot);
 	return pte;
 }
 
-extern inline pte_t pte_wrprotect(pte_t pte)
+static inline pte_t pte_wrprotect(pte_t pte)
 {
 	/* Do not clobber _PAGE_INVALID_NONE pages!  */
 	if (!(pte_val(pte) & _PAGE_INVALID))
@@ -483,13 +483,13 @@
 	return pte;
 }
 
-extern inline pte_t pte_mkwrite(pte_t pte) 
+static inline pte_t pte_mkwrite(pte_t pte)
 {
 	pte_val(pte) &= ~_PAGE_RO;
 	return pte;
 }
 
-extern inline pte_t pte_mkclean(pte_t pte)
+static inline pte_t pte_mkclean(pte_t pte)
 {
 	/* The only user of pte_mkclean is the fork() code.
 	   We must *not* clear the *physical* page dirty bit
@@ -498,7 +498,7 @@
 	return pte;
 }
 
-extern inline pte_t pte_mkdirty(pte_t pte)
+static inline pte_t pte_mkdirty(pte_t pte)
 {
 	/* We do not explicitly set the dirty bit because the
 	 * sske instruction is slow. It is faster to let the
@@ -507,7 +507,7 @@
 	return pte;
 }
 
-extern inline pte_t pte_mkold(pte_t pte)
+static inline pte_t pte_mkold(pte_t pte)
 {
 	/* S/390 doesn't keep its dirty/referenced bit in the pte.
 	 * There is no point in clearing the real referenced bit.
@@ -515,7 +515,7 @@
 	return pte;
 }
 
-extern inline pte_t pte_mkyoung(pte_t pte)
+static inline pte_t pte_mkyoung(pte_t pte)
 {
 	/* S/390 doesn't keep its dirty/referenced bit in the pte.
 	 * There is no point in setting the real referenced bit.
@@ -695,7 +695,7 @@
 #ifndef __s390x__
 
 /* Find an entry in the second-level page table.. */
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
         return (pmd_t *) dir;
 }
@@ -758,7 +758,7 @@
 #else
 #define __SWP_OFFSET_MASK (~0UL >> 11)
 #endif
-extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
+static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 {
 	pte_t pte;
 	offset &= __SWP_OFFSET_MASK;
diff --git a/include/asm-s390/sigp.h b/include/asm-s390/sigp.h
index 3979bc3..fc56458 100644
--- a/include/asm-s390/sigp.h
+++ b/include/asm-s390/sigp.h
@@ -67,7 +67,7 @@
 /*
  * Signal processor
  */
-extern __inline__ sigp_ccode
+static inline sigp_ccode
 signal_processor(__u16 cpu_addr, sigp_order_code order_code)
 {
 	sigp_ccode ccode;
@@ -86,7 +86,7 @@
 /*
  * Signal processor with parameter
  */
-extern __inline__ sigp_ccode
+static inline sigp_ccode
 signal_processor_p(__u32 parameter, __u16 cpu_addr,
 		   sigp_order_code order_code)
 {
@@ -107,7 +107,7 @@
 /*
  * Signal processor with parameter and return status
  */
-extern __inline__ sigp_ccode
+static inline sigp_ccode
 signal_processor_ps(__u32 *statusptr, __u32 parameter,
 		    __u16 cpu_addr, sigp_order_code order_code)
 {
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
index dd50e57..a2ae762 100644
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -52,7 +52,7 @@
 extern int smp_get_cpu(cpumask_t cpu_map);
 extern void smp_put_cpu(int cpu);
 
-extern __inline__ __u16 hard_smp_processor_id(void)
+static inline __u16 hard_smp_processor_id(void)
 {
         __u16 cpu_address;
  
diff --git a/include/asm-sh/ide.h b/include/asm-sh/ide.h
index f42cf39..711dad4 100644
--- a/include/asm-sh/ide.h
+++ b/include/asm-sh/ide.h
@@ -16,10 +16,6 @@
 
 #include <linux/config.h>
 
-#ifndef MAX_HWIFS
-#define MAX_HWIFS	CONFIG_IDE_MAX_HWIFS
-#endif
-
 #define ide_default_io_ctl(base)	(0)
 
 #include <asm-generic/ide_iops.h>
diff --git a/include/asm-sh64/ide.h b/include/asm-sh64/ide.h
index 6fd514da..852f50a 100644
--- a/include/asm-sh64/ide.h
+++ b/include/asm-sh64/ide.h
@@ -17,10 +17,6 @@
 
 #include <linux/config.h>
 
-#ifndef MAX_HWIFS
-#define MAX_HWIFS	CONFIG_IDE_MAX_HWIFS
-#endif
-
 /* Without this, the initialisation of PCI IDE cards end up calling
  * ide_init_hwif_ports, which won't work. */
 #ifdef CONFIG_BLK_DEV_IDEPCI
diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h
index 85c427e..356e0e8 100644
--- a/include/asm-x86_64/msi.h
+++ b/include/asm-x86_64/msi.h
@@ -11,8 +11,6 @@
 #include <asm/smp.h>
 
 #define LAST_DEVICE_VECTOR		232
-#define MSI_DEST_MODE			MSI_LOGICAL_MODE
-#define MSI_TARGET_CPU_SHIFT		12
-#define MSI_TARGET_CPU			logical_smp_processor_id()
+#define MSI_TARGET_CPU_SHIFT	12
 
 #endif /* ASM_MSI_H */
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
index c57ce40..b9fb217 100644
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -135,5 +135,11 @@
 }
 #endif
 
+#ifdef CONFIG_SMP
+#define cpu_physical_id(cpu)		x86_cpu_to_apicid[cpu]
+#else
+#define cpu_physical_id(cpu)		boot_cpu_id
+#endif
+
 #endif
 
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
index ecb0d39..2209ad3 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -10,6 +10,10 @@
 #define ULONG_IOCTL(cmd)  HANDLE_IOCTL((cmd),(ioctl_trans_handler_t)sys_ioctl)
 #endif
 
+
+COMPATIBLE_IOCTL(0x4B50)   /* KDGHWCLK - not in the kernel, but don't complain */
+COMPATIBLE_IOCTL(0x4B51)   /* KDSHWCLK - not in the kernel, but don't complain */
+
 /* Big T */
 COMPATIBLE_IOCTL(TCGETA)
 COMPATIBLE_IOCTL(TCSETA)
@@ -52,13 +56,6 @@
 COMPATIBLE_IOCTL(TIOCGPTN)
 COMPATIBLE_IOCTL(TIOCSPTLCK)
 COMPATIBLE_IOCTL(TIOCSERGETLSR)
-/* Big F */
-COMPATIBLE_IOCTL(FBIOBLANK)
-COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
-COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
-COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
-COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP)
-COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP)
 /* Little f */
 COMPATIBLE_IOCTL(FIOCLEX)
 COMPATIBLE_IOCTL(FIONCLEX)
@@ -81,6 +78,8 @@
 COMPATIBLE_IOCTL(HDIO_DRIVE_TASK)
 COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
 COMPATIBLE_IOCTL(HDIO_SET_NICE)
+COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
+COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
 /* 0x02 -- Floppy ioctls */
 COMPATIBLE_IOCTL(FDMSGON)
 COMPATIBLE_IOCTL(FDMSGOFF)
@@ -99,6 +98,7 @@
 COMPATIBLE_IOCTL(FDFMTTRK)
 COMPATIBLE_IOCTL(FDRAWCMD)
 /* 0x12 */
+COMPATIBLE_IOCTL(BLKRASET)
 COMPATIBLE_IOCTL(BLKROSET)
 COMPATIBLE_IOCTL(BLKROGET)
 COMPATIBLE_IOCTL(BLKRRPART)
@@ -262,6 +262,7 @@
 /* Little m */
 COMPATIBLE_IOCTL(MTIOCTOP)
 /* Socket level stuff */
+COMPATIBLE_IOCTL(FIOQSIZE)
 COMPATIBLE_IOCTL(FIOSETOWN)
 COMPATIBLE_IOCTL(SIOCSPGRP)
 COMPATIBLE_IOCTL(FIOGETOWN)
diff --git a/include/linux/connector.h b/include/linux/connector.h
index c5769c6..ad1a22c 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -32,6 +32,8 @@
  */
 #define CN_IDX_PROC			0x1
 #define CN_VAL_PROC			0x1
+#define CN_IDX_CIFS			0x2
+#define CN_VAL_CIFS                     0x1
 
 #define CN_NETLINK_USERS		1
 
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 1f7b2c0..43c4453 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -42,6 +42,7 @@
 /* Need to know about CPUs going up/down? */
 extern int register_cpu_notifier(struct notifier_block *nb);
 extern void unregister_cpu_notifier(struct notifier_block *nb);
+extern int current_in_cpu_hotplug(void);
 
 int cpu_up(unsigned int cpu);
 
@@ -54,6 +55,10 @@
 static inline void unregister_cpu_notifier(struct notifier_block *nb)
 {
 }
+static inline int current_in_cpu_hotplug(void)
+{
+	return 0;
+}
 
 #endif /* CONFIG_SMP */
 extern struct sysdev_class cpu_sysdev_class;
diff --git a/include/linux/eeprom.h b/include/linux/eeprom.h
deleted file mode 100644
index 38afd9d..0000000
--- a/include/linux/eeprom.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* credit winbond-840.c
- */
-#include <asm/io.h>
-struct eeprom_ops {
-	void	(*set_cs)(void *ee);
-	void	(*clear_cs)(void *ee);
-};
-
-#define EEPOL_EEDI	0x01
-#define EEPOL_EEDO	0x02
-#define EEPOL_EECLK	0x04
-#define EEPOL_EESEL	0x08
-
-struct eeprom {
-	void *dev;
-	struct eeprom_ops *ops;
-
-	void __iomem *	addr;
-
-	unsigned	ee_addr_bits;
-
-	unsigned	eesel;
-	unsigned	eeclk;
-	unsigned	eedo;
-	unsigned	eedi;
-	unsigned	polarity;
-	unsigned	ee_state;
-
-	spinlock_t	*lock;
-	u32		*cache;
-};
-
-
-u8   eeprom_readb(struct eeprom *ee, unsigned address);
-void eeprom_read(struct eeprom *ee, unsigned address, u8 *bytes,
-		unsigned count);
-void eeprom_writeb(struct eeprom *ee, unsigned address, u8 data);
-void eeprom_write(struct eeprom *ee, unsigned address, u8 *bytes,
-		unsigned count);
-
-/* The EEPROM commands include the alway-set leading bit. */
-enum EEPROM_Cmds {
-        EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
-};
-
-void setup_ee_mem_bitbanger(struct eeprom *ee, void __iomem *memaddr, int eesel_bit, int eeclk_bit, int eedo_bit, int eedi_bit, unsigned polarity)
-{
-	ee->addr = memaddr;
-	ee->eesel = 1 << eesel_bit;
-	ee->eeclk = 1 << eeclk_bit;
-	ee->eedo = 1 << eedo_bit;
-	ee->eedi = 1 << eedi_bit;
-
-	ee->polarity = polarity;
-
-	*ee->cache = readl(ee->addr);
-}
-
-/* foo. put this in a .c file */
-static inline void eeprom_update(struct eeprom *ee, u32 mask, int pol)
-{
-	unsigned long flags;
-	u32 data;
-
-	spin_lock_irqsave(ee->lock, flags);
-	data = *ee->cache;
-
-	data &= ~mask;
-	if (pol)
-		data |= mask;
-
-	*ee->cache = data;
-//printk("update: %08x\n", data);
-	writel(data, ee->addr);
-	spin_unlock_irqrestore(ee->lock, flags);
-}
-
-void eeprom_clk_lo(struct eeprom *ee)
-{
-	int pol = !!(ee->polarity & EEPOL_EECLK);
-
-	eeprom_update(ee, ee->eeclk, pol);
-	udelay(2);
-}
-
-void eeprom_clk_hi(struct eeprom *ee)
-{
-	int pol = !!(ee->polarity & EEPOL_EECLK);
-
-	eeprom_update(ee, ee->eeclk, !pol);
-	udelay(2);
-}
-
-void eeprom_send_addr(struct eeprom *ee, unsigned address)
-{
-	int pol = !!(ee->polarity & EEPOL_EEDI);
-	unsigned i;
-	address |= 6 << 6;
-
-        /* Shift the read command bits out. */
-        for (i=0; i<11; i++) {
-		eeprom_update(ee, ee->eedi, ((address >> 10) & 1) ^ pol);
-		address <<= 1;
-		eeprom_clk_hi(ee);
-		eeprom_clk_lo(ee);
-        }
-	eeprom_update(ee, ee->eedi, pol);
-}
-
-u16   eeprom_readw(struct eeprom *ee, unsigned address)
-{
-	unsigned i;
-	u16	res = 0;
-
-	eeprom_clk_lo(ee);
-	eeprom_update(ee, ee->eesel, 1 ^ !!(ee->polarity & EEPOL_EESEL));
-	eeprom_send_addr(ee, address);
-
-	for (i=0; i<16; i++) {
-		u32 data;
-		eeprom_clk_hi(ee);
-		res <<= 1;
-		data = readl(ee->addr);
-//printk("eeprom_readw: %08x\n", data);
-		res |= !!(data & ee->eedo) ^ !!(ee->polarity & EEPOL_EEDO);
-		eeprom_clk_lo(ee);
-	}
-	eeprom_update(ee, ee->eesel, 0 ^ !!(ee->polarity & EEPOL_EESEL));
-
-	return res;
-}
-
-
-void eeprom_writeb(struct eeprom *ee, unsigned address, u8 data)
-{
-}
diff --git a/include/linux/fb.h b/include/linux/fb.h
index e7ff98e..04a58f3 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -201,6 +201,14 @@
 #define FB_VMODE_SMOOTH_XPAN	512	/* smooth xpan possible (internally used) */
 #define FB_VMODE_CONUPDATE	512	/* don't update x/yoffset	*/
 
+/*
+ * Display rotation support
+ */
+#define FB_ROTATE_UR      0
+#define FB_ROTATE_CW      1
+#define FB_ROTATE_UD      2
+#define FB_ROTATE_CCW     3
+
 #define PICOS2KHZ(a) (1000000000UL/(a))
 #define KHZ2PICOS(a) (1000000000UL/(a))
 
@@ -489,9 +497,9 @@
 #define FB_EVENT_MODE_DELETE            0x04
 /*      A driver registered itself */
 #define FB_EVENT_FB_REGISTERED          0x05
-/*      get console to framebuffer mapping */
+/*      CONSOLE-SPECIFIC: get console to framebuffer mapping */
 #define FB_EVENT_GET_CONSOLE_MAP        0x06
-/*      set console to framebuffer mapping */
+/*      CONSOLE-SPECIFIC: set console to framebuffer mapping */
 #define FB_EVENT_SET_CONSOLE_MAP        0x07
 /*      A display blank is requested       */
 #define FB_EVENT_BLANK                  0x08
@@ -500,6 +508,12 @@
 /*	The resolution of the passed in fb_info about to change and
         all vc's should be changed         */
 #define FB_EVENT_MODE_CHANGE_ALL	0x0A
+/*      CONSOLE-SPECIFIC: set console rotation */
+#define FB_EVENT_SET_CON_ROTATE         0x0B
+/*      CONSOLE-SPECIFIC: get console rotation */
+#define FB_EVENT_GET_CON_ROTATE         0x0C
+/*      CONSOLE-SPECIFIC: rotate all consoles */
+#define FB_EVENT_SET_CON_ROTATE_ALL     0x0D
 
 struct fb_event {
 	struct fb_info *info;
@@ -817,8 +831,8 @@
 /* drivers/video/fbmem.c */
 extern int register_framebuffer(struct fb_info *fb_info);
 extern int unregister_framebuffer(struct fb_info *fb_info);
-extern int fb_prepare_logo(struct fb_info *fb_info);
-extern int fb_show_logo(struct fb_info *fb_info);
+extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
+extern int fb_show_logo(struct fb_info *fb_info, int rotate);
 extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);
 extern void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx,
 				u32 height, u32 shift_high, u32 shift_low, u32 mod);
@@ -828,6 +842,7 @@
 			      struct fb_fix_screeninfo *fix);
 extern int fb_get_options(char *name, char **option);
 extern int fb_new_modelist(struct fb_info *info);
+extern int fb_con_duit(struct fb_info *info, int event, void *data);
 
 extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 1b5f502..cc35b6a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -874,6 +874,7 @@
 /*
  * VFS helper functions..
  */
+extern int vfs_permission(struct nameidata *, int);
 extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
 extern int vfs_mkdir(struct inode *, struct dentry *, int);
 extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
@@ -889,6 +890,11 @@
 extern void dentry_unhash(struct dentry *dentry);
 
 /*
+ * VFS file helper functions.
+ */
+extern int file_permission(struct file *, int);
+
+/*
  * File types
  *
  * NOTE! These match bits 12..15 of stat.st_mode
diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
index bef23bb..783c476 100644
--- a/include/linux/fs_enet_pd.h
+++ b/include/linux/fs_enet_pd.h
@@ -16,7 +16,6 @@
 #ifndef FS_ENET_PD_H
 #define FS_ENET_PD_H
 
-#include <linux/version.h>
 #include <asm/types.h>
 
 #define FS_ENET_NAME	"fs_enet"
diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h
new file mode 100644
index 0000000..84f12a4
--- /dev/null
+++ b/include/linux/genetlink.h
@@ -0,0 +1,51 @@
+#ifndef __LINUX_GENERIC_NETLINK_H
+#define __LINUX_GENERIC_NETLINK_H
+
+#include <linux/netlink.h>
+
+#define GENL_NAMSIZ	16	/* length of family name */
+
+#define GENL_MIN_ID	NLMSG_MIN_TYPE
+#define GENL_MAX_ID	1023
+
+struct genlmsghdr {
+	__u8	cmd;
+	__u8	version;
+	__u16	reserved;
+};
+
+#define GENL_HDRLEN	NLMSG_ALIGN(sizeof(struct genlmsghdr))
+
+/*
+ * List of reserved static generic netlink identifiers:
+ */
+#define GENL_ID_GENERATE	0
+#define GENL_ID_CTRL		NLMSG_MIN_TYPE
+
+/**************************************************************************
+ * Controller
+ **************************************************************************/
+
+enum {
+	CTRL_CMD_UNSPEC,
+	CTRL_CMD_NEWFAMILY,
+	CTRL_CMD_DELFAMILY,
+	CTRL_CMD_GETFAMILY,
+	CTRL_CMD_NEWOPS,
+	CTRL_CMD_DELOPS,
+	CTRL_CMD_GETOPS,
+	__CTRL_CMD_MAX,
+};
+
+#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1)
+
+enum {
+	CTRL_ATTR_UNSPEC,
+	CTRL_ATTR_FAMILY_ID,
+	CTRL_ATTR_FAMILY_NAME,
+	__CTRL_ATTR_MAX,
+};
+
+#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
+
+#endif	/* __LINUX_GENERIC_NETLINK_H */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 1ce4b54..74abaec 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -27,10 +27,10 @@
  * ---- Driver types -----------------------------------------------------
  *       device id name + number        function description, i2c address(es)
  *
- *  Range 1000-1999 range is defined in sensors/sensors.h 
- *  Range 0x100 - 0x1ff is for V4L2 Common Components 
+ *  Range 1000-1999 range is defined in sensors/sensors.h
+ *  Range 0x100 - 0x1ff is for V4L2 Common Components
  *  Range 0xf000 - 0xffff is reserved for local experimentation, and should
- *        never be used in official drivers 
+ *        never be used in official drivers
  */
 
 #define I2C_DRIVERID_MSP3400	 1
@@ -99,7 +99,14 @@
 #define I2C_DRIVERID_MAX6900	63	/* MAX6900 real-time clock	*/
 #define I2C_DRIVERID_SAA7114H	64	/* video decoder		*/
 #define I2C_DRIVERID_DS1374	65	/* DS1374 real time clock	*/
-
+#define I2C_DRIVERID_TDA9874	66	/* TV sound decoder		*/
+#define I2C_DRIVERID_SAA6752HS	67	/* MPEG2 encoder		*/
+#define I2C_DRIVERID_TVEEPROM	68	/* TV EEPROM			*/
+#define I2C_DRIVERID_WM8775	69	/* wm8775 audio processor	*/
+#define I2C_DRIVERID_CS53L32A	70	/* cs53l32a audio processor	*/
+#define I2C_DRIVERID_CX25840	71	/* cx2584x video encoder	*/
+#define I2C_DRIVERID_SAA7127	72	/* saa7124 video encoder	*/
+#define I2C_DRIVERID_SAA711X	73	/* saa711x video encoders	*/
 
 #define I2C_DRIVERID_EXP0	0xF0	/* experimental use id's	*/
 #define I2C_DRIVERID_EXP1	0xF1
@@ -111,7 +118,7 @@
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
 #define I2C_DRIVERID_ALERT      903    /* SMBus Alert Responder Client  */
 
-/* IDs --   Use DRIVERIDs 1000-1999 for sensors. 
+/* IDs --   Use DRIVERIDs 1000-1999 for sensors.
    These were originally in sensors.h in the lm_sensors package */
 #define I2C_DRIVERID_LM78 1002
 #define I2C_DRIVERID_LM75 1003
@@ -190,6 +197,7 @@
 #define I2C_HW_B_NVIDIA		0x01001c /* nvidia framebuffer driver */
 #define I2C_HW_B_SAVAGE		0x01001d /* savage framebuffer driver */
 #define I2C_HW_B_RADEON		0x01001e /* radeon framebuffer driver */
+#define I2C_HW_B_EM28XX		0x01001f /* em28xx video capture cards */
 
 /* --- PCF 8584 based algorithms					*/
 #define I2C_HW_P_LP		0x020000 /* Parallel port interface */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 3461abc..ac8b25f 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -230,6 +230,7 @@
 	int		dma;			/* our dma entry */
 	ide_ack_intr_t	*ack_intr;		/* acknowledge interrupt */
 	hwif_chipset_t  chipset;
+	struct device	*dev;
 } hw_regs_t;
 
 /*
@@ -266,6 +267,10 @@
 
 #include <asm/ide.h>
 
+#ifndef MAX_HWIFS
+#define MAX_HWIFS	CONFIG_IDE_MAX_HWIFS
+#endif
+
 /* needed on alpha, x86/x86_64, ia64, mips, ppc32 and sh */
 #ifndef IDE_ARCH_OBSOLETE_DEFAULTS
 # define ide_default_io_base(index)	(0)
@@ -1324,7 +1329,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);
+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 void ide_pci_unregister_driver(struct pci_driver *driver);
 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);
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index d21c305..fe26d43 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -21,6 +21,8 @@
 #ifndef _LINUX_IF_ETHER_H
 #define _LINUX_IF_ETHER_H
 
+#include <linux/types.h>
+
 /*
  *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
  *	and FCS/CRC (frame check sequence). 
@@ -100,7 +102,7 @@
 struct ethhdr {
 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
 	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
-	unsigned short	h_proto;		/* packet type ID field	*/
+	__be16		h_proto;		/* packet type ID field	*/
 } __attribute__((packed));
 
 #ifdef __KERNEL__
diff --git a/include/linux/if_ppp.h b/include/linux/if_ppp.h
index 572aff7..768372f 100644
--- a/include/linux/if_ppp.h
+++ b/include/linux/if_ppp.h
@@ -21,7 +21,7 @@
  */
 
 /*
- *  ==FILEVERSION 20000724==
+ *  ==FILEVERSION 20050812==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the above date.
@@ -35,6 +35,8 @@
 #ifndef _IF_PPP_H_
 #define _IF_PPP_H_
 
+#include <linux/compiler.h>
+
 /*
  * Packet sizes
  */
@@ -70,7 +72,8 @@
 #define SC_LOG_RAWIN	0x00080000	/* log all chars received */
 #define SC_LOG_FLUSH	0x00100000	/* log all chars flushed */
 #define	SC_SYNC		0x00200000	/* synchronous serial mode */
-#define	SC_MASK		0x0f200fff	/* bits that user can change */
+#define	SC_MUST_COMP    0x00400000	/* no uncompressed packets may be sent or received */
+#define	SC_MASK		0x0f600fff	/* bits that user can change */
 
 /* state bits */
 #define SC_XMIT_BUSY	0x10000000	/* (used by isdn_ppp?) */
diff --git a/include/linux/if_wanpipe_common.h b/include/linux/if_wanpipe_common.h
index f25fec8..6e5461d 100644
--- a/include/linux/if_wanpipe_common.h
+++ b/include/linux/if_wanpipe_common.h
@@ -17,8 +17,6 @@
 #ifndef _WANPIPE_SOCK_DRIVER_COMMON_H
 #define _WANPIPE_SOCK_DRIVER_COMMON_H
 
-#include <linux/version.h>
-
 typedef struct {
 	struct net_device *slave;
 	atomic_t packet_sent;
diff --git a/include/linux/istallion.h b/include/linux/istallion.h
index 5f4ee64..1f99662 100644
--- a/include/linux/istallion.h
+++ b/include/linux/istallion.h
@@ -21,8 +21,6 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
-
 /*****************************************************************************/
 #ifndef	_ISTALLION_H
 #define	_ISTALLION_H
diff --git a/include/linux/libata.h b/include/linux/libata.h
index dcd17e7..ad59961 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -29,6 +29,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <linux/ata.h>
 #include <linux/workqueue.h>
@@ -214,7 +215,7 @@
 	struct list_head	node;
 	struct device 		*dev;
 	const struct ata_port_operations *port_ops;
-	Scsi_Host_Template	*sht;
+	struct scsi_host_template *sht;
 	struct ata_ioports	port[ATA_MAX_PORTS];
 	unsigned int		n_ports;
 	unsigned int		hard_port_no;
@@ -398,12 +399,13 @@
 };
 
 struct ata_port_info {
-	Scsi_Host_Template	*sht;
+	struct scsi_host_template	*sht;
 	unsigned long		host_flags;
 	unsigned long		pio_mask;
 	unsigned long		mwdma_mask;
 	unsigned long		udma_mask;
 	const struct ata_port_operations *port_ops;
+	void 			*private_data;
 };
 
 struct ata_timing {
@@ -433,7 +435,7 @@
 #endif /* CONFIG_PCI */
 extern int ata_device_add(const struct ata_probe_ent *ent);
 extern void ata_host_set_remove(struct ata_host_set *host_set);
-extern int ata_scsi_detect(Scsi_Host_Template *sht);
+extern int ata_scsi_detect(struct scsi_host_template *sht);
 extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
 extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
 extern int ata_scsi_error(struct Scsi_Host *host);
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
index 39f1430..3c9ea4b 100644
--- a/include/linux/mtd/cfi.h
+++ b/include/linux/mtd/cfi.h
@@ -8,7 +8,6 @@
 #define __MTD_CFI_H__
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index e95d046..b6f2fda 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -14,7 +14,6 @@
 #endif
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/uio.h>
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 1c975d0..455660e 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -74,7 +74,7 @@
 extern void release_open_intent(struct nameidata *);
 
 extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
-extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+extern struct dentry * lookup_hash(struct nameidata *);
 
 extern int follow_down(struct vfsmount **, struct dentry **);
 extern int follow_up(struct vfsmount **, struct dentry **);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c6efce4..936f8b7 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -927,6 +927,13 @@
 extern int		weight_p;
 extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
 extern int skb_checksum_help(struct sk_buff *skb, int inward);
+#ifdef CONFIG_BUG
+extern void netdev_rx_csum_fault(struct net_device *dev);
+#else
+static inline void netdev_rx_csum_fault(struct net_device *dev)
+{
+}
+#endif
 /* rx skb timestamps */
 extern void		net_enable_timestamp(void);
 extern void		net_disable_timestamp(void);
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
new file mode 100644
index 0000000..6d39b51
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -0,0 +1,159 @@
+#ifndef _NF_CONNTRACK_COMMON_H
+#define _NF_CONNTRACK_COMMON_H
+/* Connection state tracking for netfilter.  This is separated from,
+   but required by, the NAT layer; it can also be used by an iptables
+   extension. */
+enum ip_conntrack_info
+{
+	/* Part of an established connection (either direction). */
+	IP_CT_ESTABLISHED,
+
+	/* Like NEW, but related to an existing connection, or ICMP error
+	   (in either direction). */
+	IP_CT_RELATED,
+
+	/* Started a new connection to track (only
+           IP_CT_DIR_ORIGINAL); may be a retransmission. */
+	IP_CT_NEW,
+
+	/* >= this indicates reply direction */
+	IP_CT_IS_REPLY,
+
+	/* Number of distinct IP_CT types (no NEW in reply dirn). */
+	IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
+};
+
+/* Bitset representing status of connection. */
+enum ip_conntrack_status {
+	/* It's an expected connection: bit 0 set.  This bit never changed */
+	IPS_EXPECTED_BIT = 0,
+	IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
+
+	/* We've seen packets both ways: bit 1 set.  Can be set, not unset. */
+	IPS_SEEN_REPLY_BIT = 1,
+	IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
+
+	/* Conntrack should never be early-expired. */
+	IPS_ASSURED_BIT = 2,
+	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
+
+	/* Connection is confirmed: originating packet has left box */
+	IPS_CONFIRMED_BIT = 3,
+	IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
+
+	/* Connection needs src nat in orig dir.  This bit never changed. */
+	IPS_SRC_NAT_BIT = 4,
+	IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT),
+
+	/* Connection needs dst nat in orig dir.  This bit never changed. */
+	IPS_DST_NAT_BIT = 5,
+	IPS_DST_NAT = (1 << IPS_DST_NAT_BIT),
+
+	/* Both together. */
+	IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT),
+
+	/* Connection needs TCP sequence adjusted. */
+	IPS_SEQ_ADJUST_BIT = 6,
+	IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT),
+
+	/* NAT initialization bits. */
+	IPS_SRC_NAT_DONE_BIT = 7,
+	IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT),
+
+	IPS_DST_NAT_DONE_BIT = 8,
+	IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT),
+
+	/* Both together */
+	IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+	/* Connection is dying (removed from lists), can not be unset. */
+	IPS_DYING_BIT = 9,
+	IPS_DYING = (1 << IPS_DYING_BIT),
+};
+
+/* Connection tracking event bits */
+enum ip_conntrack_events
+{
+	/* New conntrack */
+	IPCT_NEW_BIT = 0,
+	IPCT_NEW = (1 << IPCT_NEW_BIT),
+
+	/* Expected connection */
+	IPCT_RELATED_BIT = 1,
+	IPCT_RELATED = (1 << IPCT_RELATED_BIT),
+
+	/* Destroyed conntrack */
+	IPCT_DESTROY_BIT = 2,
+	IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),
+
+	/* Timer has been refreshed */
+	IPCT_REFRESH_BIT = 3,
+	IPCT_REFRESH = (1 << IPCT_REFRESH_BIT),
+
+	/* Status has changed */
+	IPCT_STATUS_BIT = 4,
+	IPCT_STATUS = (1 << IPCT_STATUS_BIT),
+
+	/* Update of protocol info */
+	IPCT_PROTOINFO_BIT = 5,
+	IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT),
+
+	/* Volatile protocol info */
+	IPCT_PROTOINFO_VOLATILE_BIT = 6,
+	IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT),
+
+	/* New helper for conntrack */
+	IPCT_HELPER_BIT = 7,
+	IPCT_HELPER = (1 << IPCT_HELPER_BIT),
+
+	/* Update of helper info */
+	IPCT_HELPINFO_BIT = 8,
+	IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT),
+
+	/* Volatile helper info */
+	IPCT_HELPINFO_VOLATILE_BIT = 9,
+	IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT),
+
+	/* NAT info */
+	IPCT_NATINFO_BIT = 10,
+	IPCT_NATINFO = (1 << IPCT_NATINFO_BIT),
+
+	/* Counter highest bit has been set */
+	IPCT_COUNTER_FILLING_BIT = 11,
+	IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT),
+};
+
+enum ip_conntrack_expect_events {
+	IPEXP_NEW_BIT = 0,
+	IPEXP_NEW = (1 << IPEXP_NEW_BIT),
+};
+
+#ifdef __KERNEL__
+struct ip_conntrack_counter
+{
+	u_int32_t packets;
+	u_int32_t bytes;
+};
+
+struct ip_conntrack_stat
+{
+	unsigned int searched;
+	unsigned int found;
+	unsigned int new;
+	unsigned int invalid;
+	unsigned int ignore;
+	unsigned int delete;
+	unsigned int delete_list;
+	unsigned int insert;
+	unsigned int insert_failed;
+	unsigned int drop;
+	unsigned int early_drop;
+	unsigned int error;
+	unsigned int expect_new;
+	unsigned int expect_create;
+	unsigned int expect_delete;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _NF_CONNTRACK_COMMON_H */
diff --git a/include/linux/netfilter/nf_conntrack_ftp.h b/include/linux/netfilter/nf_conntrack_ftp.h
new file mode 100644
index 0000000..ad4a41c
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_ftp.h
@@ -0,0 +1,44 @@
+#ifndef _NF_CONNTRACK_FTP_H
+#define _NF_CONNTRACK_FTP_H
+/* FTP tracking. */
+
+/* This enum is exposed to userspace */
+enum ip_ct_ftp_type
+{
+	/* PORT command from client */
+	IP_CT_FTP_PORT,
+	/* PASV response from server */
+	IP_CT_FTP_PASV,
+	/* EPRT command from client */
+	IP_CT_FTP_EPRT,
+	/* EPSV response from server */
+	IP_CT_FTP_EPSV,
+};
+
+#ifdef __KERNEL__
+
+#define FTP_PORT	21
+
+#define NUM_SEQ_TO_REMEMBER 2
+/* This structure exists only once per master */
+struct ip_ct_ftp_master {
+	/* Valid seq positions for cmd matching after newline */
+	u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
+	/* 0 means seq_match_aft_nl not set */
+	int seq_aft_nl_num[IP_CT_DIR_MAX];
+};
+
+struct ip_conntrack_expect;
+
+/* For NAT to hook in when we find a packet which describes what other
+ * connection we should expect. */
+extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
+				       enum ip_conntrack_info ctinfo,
+				       enum ip_ct_ftp_type type,
+				       unsigned int matchoff,
+				       unsigned int matchlen,
+				       struct ip_conntrack_expect *exp,
+				       u32 *seq);
+#endif /* __KERNEL__ */
+
+#endif /* _NF_CONNTRACK_FTP_H */
diff --git a/include/linux/netfilter/nf_conntrack_sctp.h b/include/linux/netfilter/nf_conntrack_sctp.h
new file mode 100644
index 0000000..b8994d9
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_sctp.h
@@ -0,0 +1,27 @@
+#ifndef _NF_CONNTRACK_SCTP_H
+#define _NF_CONNTRACK_SCTP_H
+/* SCTP tracking. */
+
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+
+enum sctp_conntrack {
+	SCTP_CONNTRACK_NONE,
+	SCTP_CONNTRACK_CLOSED,
+	SCTP_CONNTRACK_COOKIE_WAIT,
+	SCTP_CONNTRACK_COOKIE_ECHOED,
+	SCTP_CONNTRACK_ESTABLISHED,
+	SCTP_CONNTRACK_SHUTDOWN_SENT,
+	SCTP_CONNTRACK_SHUTDOWN_RECD,
+	SCTP_CONNTRACK_SHUTDOWN_ACK_SENT,
+	SCTP_CONNTRACK_MAX
+};
+
+struct ip_ct_sctp
+{
+	enum sctp_conntrack state;
+
+	u_int32_t vtag[IP_CT_DIR_MAX];
+	u_int32_t ttag[IP_CT_DIR_MAX];
+};
+
+#endif /* _NF_CONNTRACK_SCTP_H */
diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h
new file mode 100644
index 0000000..b2feeff
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_tcp.h
@@ -0,0 +1,56 @@
+#ifndef _NF_CONNTRACK_TCP_H
+#define _NF_CONNTRACK_TCP_H
+/* TCP tracking. */
+
+/* This is exposed to userspace (ctnetlink) */
+enum tcp_conntrack {
+	TCP_CONNTRACK_NONE,
+	TCP_CONNTRACK_SYN_SENT,
+	TCP_CONNTRACK_SYN_RECV,
+	TCP_CONNTRACK_ESTABLISHED,
+	TCP_CONNTRACK_FIN_WAIT,
+	TCP_CONNTRACK_CLOSE_WAIT,
+	TCP_CONNTRACK_LAST_ACK,
+	TCP_CONNTRACK_TIME_WAIT,
+	TCP_CONNTRACK_CLOSE,
+	TCP_CONNTRACK_LISTEN,
+	TCP_CONNTRACK_MAX,
+	TCP_CONNTRACK_IGNORE
+};
+
+/* Window scaling is advertised by the sender */
+#define IP_CT_TCP_FLAG_WINDOW_SCALE		0x01
+
+/* SACK is permitted by the sender */
+#define IP_CT_TCP_FLAG_SACK_PERM		0x02
+
+/* This sender sent FIN first */
+#define IP_CT_TCP_FLAG_CLOSE_INIT		0x03
+
+#ifdef __KERNEL__
+
+struct ip_ct_tcp_state {
+	u_int32_t	td_end;		/* max of seq + len */
+	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 */
+};
+
+struct ip_ct_tcp
+{
+	struct ip_ct_tcp_state seen[2];	/* connection parameters per direction */
+	u_int8_t	state;		/* state of the connection (enum tcp_conntrack) */
+	/* For detecting stale connections */
+	u_int8_t	last_dir;	/* Direction of the last packet (enum ip_conntrack_dir) */
+	u_int8_t	retrans;	/* Number of retransmitted packets */
+	u_int8_t	last_index;	/* Index of the last packet */
+	u_int32_t	last_seq;	/* Last sequence number seen in dir */
+	u_int32_t	last_ack;	/* Last sequence number seen in opposite dir */
+	u_int32_t	last_end;	/* Last seq + len */
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _NF_CONNTRACK_TCP_H */
diff --git a/include/linux/netfilter/nf_conntrack_tuple_common.h b/include/linux/netfilter/nf_conntrack_tuple_common.h
new file mode 100644
index 0000000..8e145f0
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_tuple_common.h
@@ -0,0 +1,13 @@
+#ifndef _NF_CONNTRACK_TUPLE_COMMON_H
+#define _NF_CONNTRACK_TUPLE_COMMON_H
+
+enum ip_conntrack_dir
+{
+	IP_CT_DIR_ORIGINAL,
+	IP_CT_DIR_REPLY,
+	IP_CT_DIR_MAX
+};
+
+#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
+
+#endif /* _NF_CONNTRACK_TUPLE_COMMON_H */
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index f08e870..72975fa 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -146,7 +146,7 @@
 extern int nfnetlink_subsys_register(struct nfnetlink_subsystem *n);
 extern int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n);
 
-extern int nfattr_parse(struct nfattr *tb[], int maxattr, 
+extern void nfattr_parse(struct nfattr *tb[], int maxattr, 
 			struct nfattr *nfa, int len);
 
 #define nfattr_parse_nested(tb, max, nfa) \
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index d078bb9..b3432ab 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -1,132 +1,7 @@
 #ifndef _IP_CONNTRACK_H
 #define _IP_CONNTRACK_H
-/* Connection state tracking for netfilter.  This is separated from,
-   but required by, the NAT layer; it can also be used by an iptables
-   extension. */
-enum ip_conntrack_info
-{
-	/* Part of an established connection (either direction). */
-	IP_CT_ESTABLISHED,
 
-	/* Like NEW, but related to an existing connection, or ICMP error
-	   (in either direction). */
-	IP_CT_RELATED,
-
-	/* Started a new connection to track (only
-           IP_CT_DIR_ORIGINAL); may be a retransmission. */
-	IP_CT_NEW,
-
-	/* >= this indicates reply direction */
-	IP_CT_IS_REPLY,
-
-	/* Number of distinct IP_CT types (no NEW in reply dirn). */
-	IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
-};
-
-/* Bitset representing status of connection. */
-enum ip_conntrack_status {
-	/* It's an expected connection: bit 0 set.  This bit never changed */
-	IPS_EXPECTED_BIT = 0,
-	IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
-
-	/* We've seen packets both ways: bit 1 set.  Can be set, not unset. */
-	IPS_SEEN_REPLY_BIT = 1,
-	IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
-
-	/* Conntrack should never be early-expired. */
-	IPS_ASSURED_BIT = 2,
-	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
-
-	/* Connection is confirmed: originating packet has left box */
-	IPS_CONFIRMED_BIT = 3,
-	IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
-
-	/* Connection needs src nat in orig dir.  This bit never changed. */
-	IPS_SRC_NAT_BIT = 4,
-	IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT),
-
-	/* Connection needs dst nat in orig dir.  This bit never changed. */
-	IPS_DST_NAT_BIT = 5,
-	IPS_DST_NAT = (1 << IPS_DST_NAT_BIT),
-
-	/* Both together. */
-	IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT),
-
-	/* Connection needs TCP sequence adjusted. */
-	IPS_SEQ_ADJUST_BIT = 6,
-	IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT),
-
-	/* NAT initialization bits. */
-	IPS_SRC_NAT_DONE_BIT = 7,
-	IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT),
-
-	IPS_DST_NAT_DONE_BIT = 8,
-	IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT),
-
-	/* Both together */
-	IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
-
-	/* Connection is dying (removed from lists), can not be unset. */
-	IPS_DYING_BIT = 9,
-	IPS_DYING = (1 << IPS_DYING_BIT),
-};
-
-/* Connection tracking event bits */
-enum ip_conntrack_events
-{
-	/* New conntrack */
-	IPCT_NEW_BIT = 0,
-	IPCT_NEW = (1 << IPCT_NEW_BIT),
-
-	/* Expected connection */
-	IPCT_RELATED_BIT = 1,
-	IPCT_RELATED = (1 << IPCT_RELATED_BIT),
-
-	/* Destroyed conntrack */
-	IPCT_DESTROY_BIT = 2,
-	IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),
-
-	/* Timer has been refreshed */
-	IPCT_REFRESH_BIT = 3,
-	IPCT_REFRESH = (1 << IPCT_REFRESH_BIT),
-
-	/* Status has changed */
-	IPCT_STATUS_BIT = 4,
-	IPCT_STATUS = (1 << IPCT_STATUS_BIT),
-
-	/* Update of protocol info */
-	IPCT_PROTOINFO_BIT = 5,
-	IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT),
-
-	/* Volatile protocol info */
-	IPCT_PROTOINFO_VOLATILE_BIT = 6,
-	IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT),
-
-	/* New helper for conntrack */
-	IPCT_HELPER_BIT = 7,
-	IPCT_HELPER = (1 << IPCT_HELPER_BIT),
-
-	/* Update of helper info */
-	IPCT_HELPINFO_BIT = 8,
-	IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT),
-
-	/* Volatile helper info */
-	IPCT_HELPINFO_VOLATILE_BIT = 9,
-	IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT),
-
-	/* NAT info */
-	IPCT_NATINFO_BIT = 10,
-	IPCT_NATINFO = (1 << IPCT_NATINFO_BIT),
-
-	/* Counter highest bit has been set */
-	IPCT_COUNTER_FILLING_BIT = 11,
-	IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT),
-};
-
-enum ip_conntrack_expect_events {
-	IPEXP_NEW_BIT = 0,
-	IPEXP_NEW = (1 << IPEXP_NEW_BIT),
-};
+#include <linux/netfilter/nf_conntrack_common.h>
 
 #ifdef __KERNEL__
 #include <linux/config.h>
@@ -194,12 +69,6 @@
 #define IP_NF_ASSERT(x)
 #endif
 
-struct ip_conntrack_counter
-{
-	u_int32_t packets;
-	u_int32_t bytes;
-};
-
 struct ip_conntrack_helper;
 
 struct ip_conntrack
@@ -426,25 +295,6 @@
 
 extern unsigned int ip_conntrack_htable_size;
  
-struct ip_conntrack_stat
-{
-	unsigned int searched;
-	unsigned int found;
-	unsigned int new;
-	unsigned int invalid;
-	unsigned int ignore;
-	unsigned int delete;
-	unsigned int delete_list;
-	unsigned int insert;
-	unsigned int insert_failed;
-	unsigned int drop;
-	unsigned int early_drop;
-	unsigned int error;
-	unsigned int expect_new;
-	unsigned int expect_create;
-	unsigned int expect_delete;
-};
-
 #define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++)
 
 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
index 5f06429..6381193 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
@@ -1,43 +1,6 @@
 #ifndef _IP_CONNTRACK_FTP_H
 #define _IP_CONNTRACK_FTP_H
-/* FTP tracking. */
 
-#ifdef __KERNEL__
+#include <linux/netfilter/nf_conntrack_ftp.h>
 
-#define FTP_PORT	21
-
-#endif /* __KERNEL__ */
-
-enum ip_ct_ftp_type
-{
-	/* PORT command from client */
-	IP_CT_FTP_PORT,
-	/* PASV response from server */
-	IP_CT_FTP_PASV,
-	/* EPRT command from client */
-	IP_CT_FTP_EPRT,
-	/* EPSV response from server */
-	IP_CT_FTP_EPSV,
-};
-
-#define NUM_SEQ_TO_REMEMBER 2
-/* This structure exists only once per master */
-struct ip_ct_ftp_master {
-	/* Valid seq positions for cmd matching after newline */
-	u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
-	/* 0 means seq_match_aft_nl not set */
-	int seq_aft_nl_num[IP_CT_DIR_MAX];
-};
-
-struct ip_conntrack_expect;
-
-/* For NAT to hook in when we find a packet which describes what other
- * connection we should expect. */
-extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
-				       enum ip_conntrack_info ctinfo,
-				       enum ip_ct_ftp_type type,
-				       unsigned int matchoff,
-				       unsigned int matchlen,
-				       struct ip_conntrack_expect *exp,
-				       u32 *seq);
 #endif /* _IP_CONNTRACK_FTP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_icmp.h b/include/linux/netfilter_ipv4/ip_conntrack_icmp.h
index f1664ab..eed5ee3 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_icmp.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_icmp.h
@@ -1,11 +1,6 @@
 #ifndef _IP_CONNTRACK_ICMP_H
 #define _IP_CONNTRACK_ICMP_H
-/* ICMP tracking. */
-#include <asm/atomic.h>
 
-struct ip_ct_icmp
-{
-	/* Optimization: when number in == number out, forget immediately. */
-	atomic_t count;
-};
+#include <net/netfilter/ipv4/nf_conntrack_icmp.h>
+
 #endif /* _IP_CONNTRACK_ICMP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sctp.h b/include/linux/netfilter_ipv4/ip_conntrack_sctp.h
index 7a8d869..4099a04 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_sctp.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_sctp.h
@@ -1,25 +1,6 @@
 #ifndef _IP_CONNTRACK_SCTP_H
 #define _IP_CONNTRACK_SCTP_H
-/* SCTP tracking. */
 
-enum sctp_conntrack {
-	SCTP_CONNTRACK_NONE,
-	SCTP_CONNTRACK_CLOSED,
-	SCTP_CONNTRACK_COOKIE_WAIT,
-	SCTP_CONNTRACK_COOKIE_ECHOED,
-	SCTP_CONNTRACK_ESTABLISHED,
-	SCTP_CONNTRACK_SHUTDOWN_SENT,
-	SCTP_CONNTRACK_SHUTDOWN_RECD,
-	SCTP_CONNTRACK_SHUTDOWN_ACK_SENT,
-	SCTP_CONNTRACK_MAX
-};
-
-struct ip_ct_sctp
-{
-	enum sctp_conntrack state;
-
-	u_int32_t vtag[IP_CT_DIR_MAX];
-	u_int32_t ttag[IP_CT_DIR_MAX];
-};
+#include <linux/netfilter/nf_conntrack_sctp.h>
 
 #endif /* _IP_CONNTRACK_SCTP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
index 16da044..876b8fb 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
@@ -1,51 +1,6 @@
 #ifndef _IP_CONNTRACK_TCP_H
 #define _IP_CONNTRACK_TCP_H
-/* TCP tracking. */
 
-enum tcp_conntrack {
-	TCP_CONNTRACK_NONE,
-	TCP_CONNTRACK_SYN_SENT,
-	TCP_CONNTRACK_SYN_RECV,
-	TCP_CONNTRACK_ESTABLISHED,
-	TCP_CONNTRACK_FIN_WAIT,
-	TCP_CONNTRACK_CLOSE_WAIT,
-	TCP_CONNTRACK_LAST_ACK,
-	TCP_CONNTRACK_TIME_WAIT,
-	TCP_CONNTRACK_CLOSE,
-	TCP_CONNTRACK_LISTEN,
-	TCP_CONNTRACK_MAX,
-	TCP_CONNTRACK_IGNORE
-};
-
-/* Window scaling is advertised by the sender */
-#define IP_CT_TCP_FLAG_WINDOW_SCALE		0x01
-
-/* SACK is permitted by the sender */
-#define IP_CT_TCP_FLAG_SACK_PERM		0x02
-
-/* This sender sent FIN first */
-#define IP_CT_TCP_FLAG_CLOSE_INIT		0x03
-
-struct ip_ct_tcp_state {
-	u_int32_t	td_end;		/* max of seq + len */
-	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 */
-};
-
-struct ip_ct_tcp
-{
-	struct ip_ct_tcp_state seen[2];	/* connection parameters per direction */
-	u_int8_t	state;		/* state of the connection (enum tcp_conntrack) */
-	/* For detecting stale connections */
-	u_int8_t	last_dir;	/* Direction of the last packet (enum ip_conntrack_dir) */
-	u_int8_t	retrans;	/* Number of retransmitted packets */
-	u_int8_t	last_index;	/* Index of the last packet */
-	u_int32_t	last_seq;	/* Last sequence number seen in dir */
-	u_int32_t	last_ack;	/* Last sequence number seen in opposite dir */
-	u_int32_t	last_end;	/* Last seq + len */
-};
+#include <linux/netfilter/nf_conntrack_tcp.h>
 
 #endif /* _IP_CONNTRACK_TCP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
index 3232db1..2fdabdb 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
@@ -2,6 +2,7 @@
 #define _IP_CONNTRACK_TUPLE_H
 
 #include <linux/types.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
 
 /* A `tuple' is a structure containing the information to uniquely
   identify a connection.  ie. if two packets have the same tuple, they
@@ -88,13 +89,6 @@
 		(tuple)->dst.u.all = 0;				\
 	} while (0)
 
-enum ip_conntrack_dir
-{
-	IP_CT_DIR_ORIGINAL,
-	IP_CT_DIR_REPLY,
-	IP_CT_DIR_MAX
-};
-
 #ifdef __KERNEL__
 
 #define DUMP_TUPLE(tp)						\
@@ -103,8 +97,6 @@
        NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all),		\
        NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
 
-#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
-
 /* If we're the first tuple, it's the original dir. */
 #define DIRECTION(h) ((enum ip_conntrack_dir)(h)->tuple.dst.dir)
 
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
index edcc2c6..53b2983 100644
--- a/include/linux/netfilter_ipv6.h
+++ b/include/linux/netfilter_ipv6.h
@@ -59,6 +59,7 @@
 
 enum nf_ip6_hook_priorities {
 	NF_IP6_PRI_FIRST = INT_MIN,
+	NF_IP6_PRI_CONNTRACK_DEFRAG = -400,
 	NF_IP6_PRI_SELINUX_FIRST = -225,
 	NF_IP6_PRI_CONNTRACK = -200,
 	NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index ba25ca8..6a2ccf7 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -71,7 +71,8 @@
 
 #define NLMSG_ALIGNTO	4
 #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
-#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
 #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
 #define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
 #define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
@@ -86,6 +87,8 @@
 #define NLMSG_DONE		0x3	/* End of a dump	*/
 #define NLMSG_OVERRUN		0x4	/* Data lost		*/
 
+#define NLMSG_MIN_TYPE		0x10	/* < 0x10: reserved control messages */
+
 struct nlmsgerr
 {
 	int		error;
@@ -108,6 +111,25 @@
 	NETLINK_CONNECTED,
 };
 
+/*
+ *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * |        Header       | Pad |     Payload       | Pad |
+ * |   (struct nlattr)   | ing |                   | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ *  <-------------- nlattr->nla_len -------------->
+ */
+
+struct nlattr
+{
+	__u16           nla_len;
+	__u16           nla_type;
+};
+
+#define NLA_ALIGNTO		4
+#define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+#define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
+
 #ifdef __KERNEL__
 
 #include <linux/capability.h>
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 857126a..4877e35 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -47,14 +47,15 @@
 				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
 
 #ifdef CONFIG_ACPI
-extern acpi_status pci_osc_control_set(u32 flags);
+extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags);
 extern acpi_status pci_osc_support_set(u32 flags);
 #else
 #if !defined(acpi_status)
 typedef u32 		acpi_status;
 #define AE_ERROR      	(acpi_status) (0x0001)
 #endif    
-static inline acpi_status pci_osc_control_set(u32 flags) {return AE_ERROR;}
+static inline acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
+{return AE_ERROR;}
 static inline acpi_status pci_osc_support_set(u32 flags) {return AE_ERROR;} 
 #endif
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 3596ac9..de690ca 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -236,7 +236,6 @@
 struct pci_driver {
 	struct list_head node;
 	char *name;
-	struct module *owner;
 	const struct pci_device_id *id_table;	/* must be non-NULL for probe to be called */
 	int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);	/* New device inserted */
 	void (*remove) (struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
@@ -338,6 +337,7 @@
 struct pci_dev *pci_find_device_reverse (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);
 int pci_find_ext_capability (struct pci_dev *dev, int cap);
 struct pci_bus * pci_find_next_bus(const struct pci_bus *from);
 
@@ -432,8 +432,13 @@
 			   void *alignf_data);
 void pci_enable_bridges(struct pci_bus *bus);
 
-/* New-style probing supporting hot-pluggable devices */
-int pci_register_driver(struct pci_driver *);
+/* Proper probing supporting hot-pluggable devices */
+int __pci_register_driver(struct pci_driver *, struct module *);
+static inline int pci_register_driver(struct pci_driver *driver)
+{
+	return __pci_register_driver(driver, THIS_MODULE);
+}
+
 void pci_unregister_driver(struct pci_driver *);
 void pci_remove_behind_bridge(struct pci_dev *);
 struct pci_driver *pci_dev_driver(const struct pci_dev *);
@@ -547,9 +552,11 @@
 static inline void pci_disable_device(struct pci_dev *dev) { }
 static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
 static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;}
+static inline int __pci_register_driver(struct pci_driver *drv, struct module *owner) { return 0;}
 static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
 static inline void pci_unregister_driver(struct pci_driver *drv) { }
 static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; }
+static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; }
 static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; }
 static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; }
 
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 9a96f05..d00f8ba 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -387,6 +387,7 @@
 #define PCI_DEVICE_ID_NS_SC1100_SMI	0x0511
 #define PCI_DEVICE_ID_NS_SC1100_XBUS	0x0515
 #define PCI_DEVICE_ID_NS_87410		0xd001
+#define PCI_DEVICE_ID_NS_CS5535_IDE	0x002d
 
 #define PCI_VENDOR_ID_TSENG		0x100c
 #define PCI_DEVICE_ID_TSENG_W32P_2	0x3202
@@ -441,6 +442,7 @@
 #define PCI_DEVICE_ID_IBM_SNIPE		0x0180
 #define PCI_DEVICE_ID_IBM_CITRINE		0x028C
 #define PCI_DEVICE_ID_IBM_GEMSTONE		0xB166
+#define PCI_DEVICE_ID_IBM_OBSIDIAN		0x02BD
 #define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1	0x0031
 #define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2	0x0219
 #define PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX		0x021A
@@ -487,6 +489,8 @@
 #define PCI_DEVICE_ID_AMD_8151_0	0x7454
 #define PCI_DEVICE_ID_AMD_8131_APIC     0x7450
 
+#define PCI_DEVICE_ID_AMD_CS5536_IDE	0x209A
+
 #define PCI_VENDOR_ID_TRIDENT		0x1023
 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX	0x2000
 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX	0x2001
@@ -2144,6 +2148,7 @@
 #define PCI_DEVICE_ID_ADAPTEC2_7899B	0x00c1
 #define PCI_DEVICE_ID_ADAPTEC2_7899D	0x00c3
 #define PCI_DEVICE_ID_ADAPTEC2_7899P	0x00cf
+#define PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN   0x0500
 #define PCI_DEVICE_ID_ADAPTEC2_SCAMP	0x0503
 
 
diff --git a/include/linux/phonedev.h b/include/linux/phonedev.h
index d54049e..a0e31ad 100644
--- a/include/linux/phonedev.h
+++ b/include/linux/phonedev.h
@@ -2,7 +2,6 @@
 #define __LINUX_PHONEDEV_H
 
 #include <linux/types.h>
-#include <linux/version.h>
 
 #ifdef __KERNEL__
 
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 1a165b7..17e336f 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -43,4 +43,19 @@
 extern int platform_device_add(struct platform_device *pdev);
 extern void platform_device_put(struct platform_device *pdev);
 
+struct platform_driver {
+	int (*probe)(struct platform_device *);
+	int (*remove)(struct platform_device *);
+	void (*shutdown)(struct platform_device *);
+	int (*suspend)(struct platform_device *, pm_message_t state);
+	int (*resume)(struct platform_device *);
+	struct device_driver driver;
+};
+
+extern int platform_driver_register(struct platform_driver *);
+extern void platform_driver_unregister(struct platform_driver *);
+
+#define platform_get_drvdata(_dev)	dev_get_drvdata(&(_dev)->dev)
+#define platform_set_drvdata(_dev,data)	dev_set_drvdata(&(_dev)->dev, (data))
+
 #endif /* _PLATFORM_DEVICE_H_ */
diff --git a/include/linux/ppp-comp.h b/include/linux/ppp-comp.h
index 7227e65..e86a7a5 100644
--- a/include/linux/ppp-comp.h
+++ b/include/linux/ppp-comp.h
@@ -111,6 +111,8 @@
 
 	/* Used in locking compressor modules */
 	struct module *owner;
+	/* Extra skb space needed by the compressor algorithm */
+	unsigned int comp_extra;
 };
 
 /*
@@ -191,6 +193,13 @@
 #define DEFLATE_CHK_SEQUENCE	0
 
 /*
+ * Definitions for MPPE.
+ */
+
+#define CI_MPPE                18      /* config option for MPPE */
+#define CILEN_MPPE              6      /* length of config option */
+
+/*
  * Definitions for other, as yet unsupported, compression methods.
  */
 
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 65ceeaa..74488e4 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -66,6 +66,7 @@
 	write_proc_t *write_proc;
 	atomic_t count;		/* use count */
 	int deleted;		/* delete flag */
+	void *set;
 };
 
 struct kcore_list {
diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h
index 9de9919..8994378 100644
--- a/include/linux/raid/bitmap.h
+++ b/include/linux/raid/bitmap.h
@@ -6,7 +6,13 @@
 #ifndef BITMAP_H
 #define BITMAP_H 1
 
-#define BITMAP_MAJOR 3
+#define BITMAP_MAJOR_LO 3
+/* version 4 insists the bitmap is in little-endian order
+ * with version 3, it is host-endian which is non-portable
+ */
+#define BITMAP_MAJOR_HI 4
+#define	BITMAP_MAJOR_HOSTENDIAN 3
+
 #define BITMAP_MINOR 39
 
 /*
@@ -133,7 +139,8 @@
 /* use these for bitmap->flags and bitmap->sb->state bit-fields */
 enum bitmap_state {
 	BITMAP_ACTIVE = 0x001, /* the bitmap is in use */
-	BITMAP_STALE  = 0x002  /* the bitmap file is out of date or had -EIO */
+	BITMAP_STALE  = 0x002,  /* the bitmap file is out of date or had -EIO */
+	BITMAP_HOSTENDIAN = 0x8000,
 };
 
 /* the superblock at the front of the bitmap file -- little endian */
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
index ffa316c..13e7c4b 100644
--- a/include/linux/raid/md.h
+++ b/include/linux/raid/md.h
@@ -66,8 +66,10 @@
  *     and major_version/minor_version accordingly
  * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT
  *     in the super status byte
+ * >=3 means that bitmap superblock version 4 is supported, which uses
+ *     little-ending representation rather than host-endian
  */
-#define MD_PATCHLEVEL_VERSION           2
+#define MD_PATCHLEVEL_VERSION           3
 
 extern int register_md_personality (int p_num, mdk_personality_t *p);
 extern int unregister_md_personality (int p_num);
@@ -87,6 +89,7 @@
 
 extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
 			   sector_t sector, int size, struct page *page);
+extern void md_super_wait(mddev_t *mddev);
 extern int sync_page_io(struct block_device *bdev, sector_t sector, int size,
 			struct page *page, int rw);
 
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index ebce949..46629a2 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -105,6 +105,8 @@
 	int		sb_size;	/* bytes in the superblock */
 	int		preferred_minor;	/* autorun support */
 
+	struct kobject	kobj;
+
 	/* A device can be in one of three states based on two flags:
 	 * Not working:   faulty==1 in_sync==0
 	 * Fully working: faulty==0 in_sync==1
@@ -115,11 +117,12 @@
 	 * It can never have faulty==1, in_sync==1
 	 * This reduces the burden of testing multiple flags in many cases
 	 */
-	int faulty;			/* if faulty do not issue IO requests */
-	int in_sync;			/* device is a full member of the array */
 
-	unsigned long	flags;		/* Should include faulty and in_sync here. */
+	unsigned long	flags;
+#define	Faulty		1		/* device is known to have a fault */
+#define	In_sync		2		/* device is in_sync with rest of array */
 #define	WriteMostly	4		/* Avoid reading if at all possible */
+#define	BarriersNotsupp	5		/* BIO_RW_BARRIER is not supported */
 
 	int desc_nr;			/* descriptor index in the superblock */
 	int raid_disk;			/* role of device in array */
@@ -132,6 +135,9 @@
 					 * only maintained for arrays that
 					 * support hot removal
 					 */
+	atomic_t	read_errors;	/* number of consecutive read errors that
+					 * we have tried to ignore.
+					 */
 };
 
 typedef struct mdk_personality_s mdk_personality_t;
@@ -148,6 +154,8 @@
 
 	struct gendisk			*gendisk;
 
+	struct kobject			kobj;
+
 	/* Superblock information */
 	int				major_version,
 					minor_version,
@@ -171,6 +179,10 @@
 	sector_t			resync_mark_cnt;/* blocks written at resync_mark */
 
 	sector_t			resync_max_sectors; /* may be set by personality */
+
+	sector_t			resync_mismatches; /* count of sectors where
+							    * parity/replica mismatch found
+							    */
 	/* recovery/resync flags 
 	 * NEEDED:   we might need to start a resync/recover
 	 * RUNNING:  a thread is running, or about to be started
@@ -178,6 +190,8 @@
 	 * ERR:      and IO error was detected - abort the resync/recovery
 	 * INTR:     someone requested a (clean) early abort.
 	 * DONE:     thread is done and is waiting to be reaped
+	 * REQUEST:  user-space has requested a sync (used with SYNC)
+	 * CHECK:    user-space request for for check-only, no repair
 	 */
 #define	MD_RECOVERY_RUNNING	0
 #define	MD_RECOVERY_SYNC	1
@@ -185,6 +199,8 @@
 #define	MD_RECOVERY_INTR	3
 #define	MD_RECOVERY_DONE	4
 #define	MD_RECOVERY_NEEDED	5
+#define	MD_RECOVERY_REQUESTED	6
+#define	MD_RECOVERY_CHECK	7
 	unsigned long			recovery;
 
 	int				in_sync;	/* know to not need resync */
@@ -195,6 +211,13 @@
 	int				degraded;	/* whether md should consider
 							 * adding a spare
 							 */
+	int				barriers_work;	/* initialised to true, cleared as soon
+							 * as a barrier request to slave
+							 * fails.  Only supported
+							 */
+	struct bio			*biolist; 	/* bios that need to be retried
+							 * because BIO_RW_BARRIER is not supported
+							 */
 
 	atomic_t			recovery_active; /* blocks scheduled, but not written */
 	wait_queue_head_t		recovery_wait;
@@ -232,7 +255,7 @@
 
 static inline void rdev_dec_pending(mdk_rdev_t *rdev, mddev_t *mddev)
 {
-	int faulty = rdev->faulty;
+	int faulty = test_bit(Faulty, &rdev->flags);
 	if (atomic_dec_and_test(&rdev->nr_pending) && faulty)
 		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 }
@@ -270,6 +293,13 @@
 };
 
 
+struct md_sysfs_entry {
+	struct attribute attr;
+	ssize_t (*show)(mddev_t *, char *);
+	ssize_t (*store)(mddev_t *, const char *, size_t);
+};
+
+
 static inline char * mdname (mddev_t * mddev)
 {
 	return mddev->gendisk ? mddev->gendisk->disk_name : "mdX";
@@ -304,10 +334,8 @@
 	mddev_t			*mddev;
 	wait_queue_head_t	wqueue;
 	unsigned long           flags;
-	struct completion	*event;
 	struct task_struct	*tsk;
 	unsigned long		timeout;
-	const char		*name;
 } mdk_thread_t;
 
 #define THREAD_WAKEUP  0
diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h
index 60e19b6..292b98f 100644
--- a/include/linux/raid/raid1.h
+++ b/include/linux/raid/raid1.h
@@ -110,7 +110,9 @@
 #define	R1BIO_Uptodate	0
 #define	R1BIO_IsSync	1
 #define	R1BIO_Degraded	2
-#define	R1BIO_BehindIO   3
+#define	R1BIO_BehindIO	3
+#define	R1BIO_Barrier	4
+#define R1BIO_BarrierRetry 5
 /* For write-behind requests, we call bi_end_io when
  * the last non-write-behind device completes, providing
  * any write was successful.  Otherwise we call when
diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
index 176fc65..f025ba6 100644
--- a/include/linux/raid/raid5.h
+++ b/include/linux/raid/raid5.h
@@ -154,6 +154,8 @@
 #define	R5_Wantwrite	5
 #define	R5_Syncio	6	/* this io need to be accounted as resync io */
 #define	R5_Overlap	7	/* There is a pending overlapping request on this block */
+#define	R5_ReadError	8	/* seen a read error here recently */
+#define	R5_ReWrite	9	/* have tried to over-write the readerror */
 
 /*
  * Write method
diff --git a/include/linux/raid_class.h b/include/linux/raid_class.h
index a71123c..48831ea 100644
--- a/include/linux/raid_class.h
+++ b/include/linux/raid_class.h
@@ -1,4 +1,9 @@
 /*
+ * raid_class.h - a generic raid visualisation class
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com>
+ *
+ * This file is licensed under GPLv2
  */
 #include <linux/transport_class.h>
 
@@ -14,20 +19,35 @@
 };
 
 enum raid_state {
-	RAID_ACTIVE = 1,
-	RAID_DEGRADED,
-	RAID_RESYNCING,
-	RAID_OFFLINE,
+	RAID_STATE_UNKNOWN = 0,
+	RAID_STATE_ACTIVE,
+	RAID_STATE_DEGRADED,
+	RAID_STATE_RESYNCING,
+	RAID_STATE_OFFLINE,
+};
+
+enum raid_level {
+	RAID_LEVEL_UNKNOWN = 0,
+	RAID_LEVEL_LINEAR,
+	RAID_LEVEL_0,
+	RAID_LEVEL_1,
+	RAID_LEVEL_3,
+	RAID_LEVEL_4,
+	RAID_LEVEL_5,
+	RAID_LEVEL_6,
 };
 
 struct raid_data {
 	struct list_head component_list;
 	int component_count;
-	int level;
+	enum raid_level level;
 	enum raid_state state;
 	int resync;
 };
 
+/* resync complete goes from 0 to this */
+#define RAID_MAX_RESYNC		(10000)
+
 #define DEFINE_RAID_ATTRIBUTE(type, attr)				      \
 static inline void							      \
 raid_set_##attr(struct raid_template *r, struct device *dev, type value) {    \
@@ -48,7 +68,7 @@
 	return rd->attr;						      \
 }
 
-DEFINE_RAID_ATTRIBUTE(int, level)
+DEFINE_RAID_ATTRIBUTE(enum raid_level, level)
 DEFINE_RAID_ATTRIBUTE(int, resync)
 DEFINE_RAID_ATTRIBUTE(enum raid_state, state)
 	
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 03b68a7..2bbf968 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -909,6 +909,7 @@
 #define PF_SYNCWRITE	0x00200000	/* I am doing a sync write */
 #define PF_BORROWED_MM	0x00400000	/* I am a kthread doing use_mm */
 #define PF_RANDOMIZE	0x00800000	/* randomize virtual address space */
+#define PF_HOTPLUG_CPU	0x01000000	/* Currently performing CPU hotplug */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index fdfb8fe..0a8ea8b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -274,6 +274,9 @@
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
 	__u8			ipvs_property:1;
 #endif
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	struct sk_buff		*nfct_reasm;
+#endif
 #ifdef CONFIG_BRIDGE_NETFILTER
 	struct nf_bridge_info	*nf_bridge;
 #endif
@@ -1233,8 +1236,7 @@
 extern int	       skb_copy_datagram_iovec(const struct sk_buff *from,
 					       int offset, struct iovec *to,
 					       int size);
-extern int	       skb_copy_and_csum_datagram_iovec(const
-							struct sk_buff *skb,
+extern int	       skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
 							int hlen,
 							struct iovec *iov);
 extern void	       skb_free_datagram(struct sock *sk, struct sk_buff *skb);
@@ -1302,6 +1304,30 @@
 
 extern void __net_timestamp(struct sk_buff *skb);
 
+extern unsigned int __skb_checksum_complete(struct sk_buff *skb);
+
+/**
+ *	skb_checksum_complete - Calculate checksum of an entire packet
+ *	@skb: packet to process
+ *
+ *	This function calculates the checksum over the entire packet plus
+ *	the value of skb->csum.  The latter can be used to supply the
+ *	checksum of a pseudo header as used by TCP/UDP.  It returns the
+ *	checksum.
+ *
+ *	For protocols that contain complete checksums such as ICMP/TCP/UDP,
+ *	this function can be used to verify that checksum on received
+ *	packets.  In that case the function should return zero if the
+ *	checksum is correct.  In particular, this function will return zero
+ *	if skb->ip_summed is CHECKSUM_UNNECESSARY which indicates that the
+ *	hardware has already verified the correctness of the checksum.
+ */
+static inline unsigned int skb_checksum_complete(struct sk_buff *skb)
+{
+	return skb->ip_summed != CHECKSUM_UNNECESSARY &&
+		__skb_checksum_complete(skb);
+}
+
 #ifdef CONFIG_NETFILTER
 static inline void nf_conntrack_put(struct nf_conntrack *nfct)
 {
@@ -1313,10 +1339,26 @@
 	if (nfct)
 		atomic_inc(&nfct->use);
 }
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
+{
+	if (skb)
+		atomic_inc(&skb->users);
+}
+static inline void nf_conntrack_put_reasm(struct sk_buff *skb)
+{
+	if (skb)
+		kfree_skb(skb);
+}
+#endif
 static inline void nf_reset(struct sk_buff *skb)
 {
 	nf_conntrack_put(skb->nfct);
 	skb->nfct = NULL;
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	nf_conntrack_put_reasm(skb->nfct_reasm);
+	skb->nfct_reasm = NULL;
+#endif
 }
 
 #ifdef CONFIG_BRIDGE_NETFILTER
diff --git a/include/linux/stallion.h b/include/linux/stallion.h
index e89b77b..13a37f1 100644
--- a/include/linux/stallion.h
+++ b/include/linux/stallion.h
@@ -21,8 +21,6 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
-
 /*****************************************************************************/
 #ifndef	_STALLION_H
 #define	_STALLION_H
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index fc8e367..ab2791b 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -24,6 +24,7 @@
 #include <linux/compiler.h>
 
 struct file;
+struct completion;
 
 #define CTL_MAXNAME 10		/* how many path components do we allow in a
 				   call to sysctl?   In other words, what is
@@ -204,6 +205,7 @@
 	NET_ECONET=16,
 	NET_SCTP=17,
 	NET_LLC=18,
+	NET_NETFILTER=19,
 };
 
 /* /proc/sys/kernel/random */
@@ -269,6 +271,42 @@
 	NET_UNIX_MAX_DGRAM_QLEN=3,
 };
 
+/* /proc/sys/net/netfilter */
+enum
+{
+	NET_NF_CONNTRACK_MAX=1,
+	NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2,
+	NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3,
+	NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4,
+	NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5,
+	NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6,
+	NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7,
+	NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8,
+	NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9,
+	NET_NF_CONNTRACK_UDP_TIMEOUT=10,
+	NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11,
+	NET_NF_CONNTRACK_ICMP_TIMEOUT=12,
+	NET_NF_CONNTRACK_GENERIC_TIMEOUT=13,
+	NET_NF_CONNTRACK_BUCKETS=14,
+	NET_NF_CONNTRACK_LOG_INVALID=15,
+	NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS=16,
+	NET_NF_CONNTRACK_TCP_LOOSE=17,
+	NET_NF_CONNTRACK_TCP_BE_LIBERAL=18,
+	NET_NF_CONNTRACK_TCP_MAX_RETRANS=19,
+	NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED=20,
+	NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT=21,
+	NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED=22,
+	NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED=23,
+	NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT=24,
+	NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD=25,
+	NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT=26,
+	NET_NF_CONNTRACK_COUNT=27,
+	NET_NF_CONNTRACK_ICMPV6_TIMEOUT=28,
+	NET_NF_CONNTRACK_FRAG6_TIMEOUT=29,
+	NET_NF_CONNTRACK_FRAG6_LOW_THRESH=30,
+	NET_NF_CONNTRACK_FRAG6_HIGH_THRESH=31,
+};
+
 /* /proc/sys/net/ipv4 */
 enum
 {
@@ -352,6 +390,7 @@
 	NET_TCP_BIC_BETA=108,
 	NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR=109,
 	NET_TCP_CONG_CONTROL=110,
+	NET_TCP_ABC=111,
 };
 
 enum {
@@ -925,6 +964,8 @@
 {
 	ctl_table *ctl_table;
 	struct list_head ctl_entry;
+	int used;
+	struct completion *unregistering;
 };
 
 struct ctl_table_header * register_sysctl_table(ctl_table * table, 
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index ac4ca44..0e1da66 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -307,6 +307,21 @@
 	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];
+
+	/* from STCP, retrans queue hinting */
+	struct sk_buff* lost_skb_hint;
+
+	struct sk_buff *scoreboard_skb_hint;
+	struct sk_buff *retransmit_skb_hint;
+	struct sk_buff *forward_skb_hint;
+	struct sk_buff *fastpath_skb_hint;
+
+	int     fastpath_cnt_hint;
+	int     lost_cnt_hint;
+	int     retransmit_cnt_hint;
+	int     forward_cnt_hint;
+
 	__u16	advmss;		/* Advertised MSS			*/
 	__u16	prior_ssthresh; /* ssthresh saved at recovery start	*/
 	__u32	lost_out;	/* Lost packets			*/
@@ -326,6 +341,7 @@
 	__u32	snd_up;		/* Urgent pointer		*/
 
 	__u32	total_retrans;	/* Total retransmits for entire connection */
+	__u32	bytes_acked;	/* Appropriate Byte Counting - RFC3465 */
 
 	unsigned int		keepalive_time;	  /* time before keep alive takes place */
 	unsigned int		keepalive_intvl;  /* time interval between keep alive probes */
diff --git a/include/linux/videodev.h b/include/linux/videodev.h
index 1cc8c31..9114009 100644
--- a/include/linux/videodev.h
+++ b/include/linux/videodev.h
@@ -1,57 +1,16 @@
 #ifndef __LINUX_VIDEODEV_H
 #define __LINUX_VIDEODEV_H
 
-#include <linux/compiler.h>
 #include <linux/types.h>
 
-#define HAVE_V4L2 1
+#define HAVE_V4L1 1
+
 #include <linux/videodev2.h>
 
 #ifdef __KERNEL__
 
-#include <linux/poll.h>
 #include <linux/mm.h>
-#include <linux/device.h>
 
-struct video_device
-{
-	/* device info */
-	struct device *dev;
-	char name[32];
-	int type;       /* v4l1 */
-	int type2;      /* v4l2 */
-	int hardware;
-	int minor;
-
-	/* device ops + callbacks */
-	struct file_operations *fops;
-	void (*release)(struct video_device *vfd);
-
-
-	/* obsolete -- fops->owner is used instead */
-	struct module *owner;
-	/* dev->driver_data will be used instead some day.
-	 * Use the video_{get|set}_drvdata() helper functions,
-	 * so the switch over will be transparent for you.
-	 * Or use {pci|usb}_{get|set}_drvdata() directly. */
-	void *priv;
-
-	/* for videodev.c intenal usage -- please don't touch */
-	int users;                     /* video_exclusive_{open|close} ... */
-	struct semaphore lock;         /* ... helper function uses these   */
-	char devfs_name[64];           /* devfs */
-	struct class_device class_dev; /* sysfs */
-};
-
-#define VIDEO_MAJOR	81
-
-#define VFL_TYPE_GRABBER	0
-#define VFL_TYPE_VBI		1
-#define VFL_TYPE_RADIO		2
-#define VFL_TYPE_VTX		3
-
-extern int video_register_device(struct video_device *, int type, int nr);
-extern void video_unregister_device(struct video_device *);
 extern struct video_device* video_devdata(struct file*);
 
 #define to_video_device(cd) container_of(cd, struct video_device, class_dev)
@@ -68,11 +27,7 @@
 	class_device_remove_file(&vfd->class_dev, attr);
 }
 
-/* helper functions to alloc / release struct video_device, the
-   later can be used for video_device->release() */
-struct video_device *video_device_alloc(void);
-void video_device_release(struct video_device *vfd);
-
+#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
 /* helper functions to access driver private data. */
 static inline void *video_get_drvdata(struct video_device *dev)
 {
@@ -83,30 +38,12 @@
 {
 	dev->priv = data;
 }
+#endif
 
 extern int video_exclusive_open(struct inode *inode, struct file *file);
 extern int video_exclusive_release(struct inode *inode, struct file *file);
-extern int video_usercopy(struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg,
-			  int (*func)(struct inode *inode, struct file *file,
-				      unsigned int cmd, void *arg));
 #endif /* __KERNEL__ */
 
-#define VID_TYPE_CAPTURE	1	/* Can capture */
-#define VID_TYPE_TUNER		2	/* Can tune */
-#define VID_TYPE_TELETEXT	4	/* Does teletext */
-#define VID_TYPE_OVERLAY	8	/* Overlay onto frame buffer */
-#define VID_TYPE_CHROMAKEY	16	/* Overlay by chromakey */
-#define VID_TYPE_CLIPPING	32	/* Can clip */
-#define VID_TYPE_FRAMERAM	64	/* Uses the frame buffer memory */
-#define VID_TYPE_SCALES		128	/* Scalable */
-#define VID_TYPE_MONOCHROME	256	/* Monochrome only */
-#define VID_TYPE_SUBCAPTURE	512	/* Can capture subareas of the image */
-#define VID_TYPE_MPEG_DECODER	1024	/* Can decode MPEG streams */
-#define VID_TYPE_MPEG_ENCODER	2048	/* Can encode MPEG streams */
-#define VID_TYPE_MJPEG_DECODER	4096	/* Can decode MJPEG streams */
-#define VID_TYPE_MJPEG_ENCODER	8192	/* Can encode MJPEG streams */
-
 struct video_capability
 {
 	char name[32];
@@ -202,9 +139,9 @@
 #define VIDEO_SOUND_STEREO	2
 #define VIDEO_SOUND_LANG1	4
 #define VIDEO_SOUND_LANG2	8
-        __u16   mode;
-        __u16	balance;	/* Stereo balance */
-        __u16	step;		/* Step actual volume uses */
+	__u16   mode;
+	__u16	balance;	/* Stereo balance */
+	__u16	step;		/* Step actual volume uses */
 };
 
 struct video_clip
@@ -260,9 +197,6 @@
 	__u32	flags;
 };
 
-
-#define VIDEO_MAX_FRAME		32
-
 struct video_mbuf
 {
 	int	size;		/* Total memory to map */
@@ -270,10 +204,8 @@
 	int	offsets[VIDEO_MAX_FRAME];
 };
 
-
 #define 	VIDEO_NO_UNIT	(-1)
 
-
 struct video_unit
 {
 	int 	video;		/* Video minor */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 89a0557..a114fff 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -15,16 +15,99 @@
  */
 #ifdef __KERNEL__
 #include <linux/time.h> /* need struct timeval */
+#include <linux/poll.h>
+#include <linux/device.h>
 #endif
 #include <linux/compiler.h> /* need __user */
 
+
+#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.15 */
+#define HAVE_V4L2 1
+
+/*
+ * Common stuff for both V4L1 and V4L2
+ * Moved from videodev.h
+ */
+
+#define VIDEO_MAX_FRAME               32
+
+#define VID_TYPE_CAPTURE	1	/* Can capture */
+#define VID_TYPE_TUNER		2	/* Can tune */
+#define VID_TYPE_TELETEXT	4	/* Does teletext */
+#define VID_TYPE_OVERLAY	8	/* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY	16	/* Overlay by chromakey */
+#define VID_TYPE_CLIPPING	32	/* Can clip */
+#define VID_TYPE_FRAMERAM	64	/* Uses the frame buffer memory */
+#define VID_TYPE_SCALES		128	/* Scalable */
+#define VID_TYPE_MONOCHROME	256	/* Monochrome only */
+#define VID_TYPE_SUBCAPTURE	512	/* Can capture subareas of the image */
+#define VID_TYPE_MPEG_DECODER	1024	/* Can decode MPEG streams */
+#define VID_TYPE_MPEG_ENCODER	2048	/* Can encode MPEG streams */
+#define VID_TYPE_MJPEG_DECODER	4096	/* Can decode MJPEG streams */
+#define VID_TYPE_MJPEG_ENCODER	8192	/* Can encode MJPEG streams */
+
+#ifdef __KERNEL__
+
+#define VFL_TYPE_GRABBER	0
+#define VFL_TYPE_VBI		1
+#define VFL_TYPE_RADIO		2
+#define VFL_TYPE_VTX		3
+
+struct video_device
+{
+	/* device info */
+	struct device *dev;
+	char name[32];
+	int type;       /* v4l1 */
+	int type2;      /* v4l2 */
+	int hardware;
+	int minor;
+
+	/* device ops + callbacks */
+	struct file_operations *fops;
+	void (*release)(struct video_device *vfd);
+
+
+#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
+	/* obsolete -- fops->owner is used instead */
+	struct module *owner;
+	/* dev->driver_data will be used instead some day.
+	 * Use the video_{get|set}_drvdata() helper functions,
+	 * so the switch over will be transparent for you.
+	 * Or use {pci|usb}_{get|set}_drvdata() directly. */
+	void *priv;
+#endif
+
+	/* for videodev.c intenal usage -- please don't touch */
+	int users;                     /* video_exclusive_{open|close} ... */
+	struct semaphore lock;         /* ... helper function uses these   */
+	char devfs_name[64];           /* devfs */
+	struct class_device class_dev; /* sysfs */
+};
+
+#define VIDEO_MAJOR	81
+
+extern int video_register_device(struct video_device *, int type, int nr);
+extern void video_unregister_device(struct video_device *);
+extern int video_usercopy(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg,
+			  int (*func)(struct inode *inode, struct file *file,
+				      unsigned int cmd, void *arg));
+
+/* helper functions to alloc / release struct video_device, the
+   later can be used for video_device->release() */
+struct video_device *video_device_alloc(void);
+void video_device_release(struct video_device *vfd);
+
+#endif
+
 /*
  *	M I S C E L L A N E O U S
  */
 
 /*  Four-character-code (FOURCC) */
 #define v4l2_fourcc(a,b,c,d)\
-        (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
+	(((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
 
 /*
  *	E N U M S
@@ -154,20 +237,20 @@
 };
 
 /* Values for 'capabilities' field */
-#define V4L2_CAP_VIDEO_CAPTURE	        0x00000001  /* Is a video capture device */
-#define V4L2_CAP_VIDEO_OUTPUT	        0x00000002  /* Is a video output device */
-#define V4L2_CAP_VIDEO_OVERLAY	        0x00000004  /* Can do video overlay */
-#define V4L2_CAP_VBI_CAPTURE	        0x00000010  /* Is a raw VBI capture device */
-#define V4L2_CAP_VBI_OUTPUT	        0x00000020  /* Is a raw VBI output device */
+#define V4L2_CAP_VIDEO_CAPTURE		0x00000001  /* Is a video capture device */
+#define V4L2_CAP_VIDEO_OUTPUT		0x00000002  /* Is a video output device */
+#define V4L2_CAP_VIDEO_OVERLAY		0x00000004  /* Can do video overlay */
+#define V4L2_CAP_VBI_CAPTURE		0x00000010  /* Is a raw VBI capture device */
+#define V4L2_CAP_VBI_OUTPUT		0x00000020  /* Is a raw VBI output device */
 #if 1
 #define V4L2_CAP_SLICED_VBI_CAPTURE	0x00000040  /* Is a sliced VBI capture device */
 #define V4L2_CAP_SLICED_VBI_OUTPUT	0x00000080  /* Is a sliced VBI output device */
 #endif
-#define V4L2_CAP_RDS_CAPTURE	        0x00000100  /* RDS data capture */
+#define V4L2_CAP_RDS_CAPTURE		0x00000100  /* RDS data capture */
 
-#define V4L2_CAP_TUNER		        0x00010000  /* has a tuner */
-#define V4L2_CAP_AUDIO		        0x00020000  /* has audio support */
-#define V4L2_CAP_RADIO		        0x00040000  /* is a radio device */
+#define V4L2_CAP_TUNER			0x00010000  /* has a tuner */
+#define V4L2_CAP_AUDIO			0x00020000  /* has audio support */
+#define V4L2_CAP_RADIO			0x00040000  /* is a radio device */
 
 #define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
 #define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
@@ -179,13 +262,13 @@
 
 struct v4l2_pix_format
 {
-	__u32         	 	width;
-	__u32	         	height;
-	__u32	         	pixelformat;
+	__u32         		width;
+	__u32			height;
+	__u32			pixelformat;
 	enum v4l2_field  	field;
 	__u32            	bytesperline;	/* for padding, zero if unused */
-	__u32          	 	sizeimage;
-        enum v4l2_colorspace	colorspace;
+	__u32          		sizeimage;
+	enum v4l2_colorspace	colorspace;
 	__u32			priv;		/* private data, depends on pixelformat */
 };
 
@@ -238,12 +321,12 @@
  */
 struct v4l2_fmtdesc
 {
-	__u32	            index;             /* Format number      */
+	__u32		    index;             /* Format number      */
 	enum v4l2_buf_type  type;              /* buffer type        */
 	__u32               flags;
-	__u8	            description[32];   /* Description string */
-	__u32	            pixelformat;       /* Format fourcc      */
-	__u32	            reserved[4];
+	__u8		    description[32];   /* Description string */
+	__u32		    pixelformat;       /* Format fourcc      */
+	__u32		    reserved[4];
 };
 
 #define V4L2_FMT_FLAG_COMPRESSED 0x0001
@@ -393,7 +476,7 @@
 #define V4L2_JPEG_MARKER_DRI (1<<5)    /* Define Restart Interval */
 #define V4L2_JPEG_MARKER_COM (1<<6)    /* Comment segment */
 #define V4L2_JPEG_MARKER_APP (1<<7)    /* App segment, driver will
-                                        * allways use APP0 */
+					* allways use APP0 */
 };
 
 
@@ -402,10 +485,10 @@
  */
 struct v4l2_requestbuffers
 {
-	__u32	                count;
+	__u32			count;
 	enum v4l2_buf_type      type;
 	enum v4l2_memory        memory;
-	__u32	                reserved[2];
+	__u32			reserved[2];
 };
 
 struct v4l2_buffer
@@ -511,9 +594,9 @@
 
 struct v4l2_cropcap {
 	enum v4l2_buf_type      type;
-        struct v4l2_rect        bounds;
-        struct v4l2_rect        defrect;
-        struct v4l2_fract       pixelaspect;
+	struct v4l2_rect        bounds;
+	struct v4l2_rect        defrect;
+	struct v4l2_fract       pixelaspect;
 };
 
 struct v4l2_crop {
@@ -544,6 +627,7 @@
 
 #define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
 #define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
+#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
 
 #define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
 #define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
@@ -581,13 +665,14 @@
 
 #define V4L2_STD_525_60		(V4L2_STD_PAL_M		|\
 				 V4L2_STD_PAL_60	|\
-				 V4L2_STD_NTSC)
+				 V4L2_STD_NTSC		|\
+				 V4L2_STD_NTSC_443)
 #define V4L2_STD_625_50		(V4L2_STD_PAL		|\
 				 V4L2_STD_PAL_N		|\
 				 V4L2_STD_PAL_Nc	|\
 				 V4L2_STD_SECAM)
 #define V4L2_STD_ATSC           (V4L2_STD_ATSC_8_VSB    |\
-		                 V4L2_STD_ATSC_16_VSB)
+				 V4L2_STD_ATSC_16_VSB)
 
 #define V4L2_STD_UNKNOWN        0
 #define V4L2_STD_ALL            (V4L2_STD_525_60	|\
@@ -595,7 +680,7 @@
 
 struct v4l2_standard
 {
-	__u32	       	     index;
+	__u32		     index;
 	v4l2_std_id          id;
 	__u8		     name[24];
 	struct v4l2_fract    frameperiod; /* Frames, not fields */
@@ -610,9 +695,9 @@
 struct v4l2_input
 {
 	__u32	     index;		/*  Which input */
-	__u8	     name[32];	        /*  Label */
+	__u8	     name[32];		/*  Label */
 	__u32	     type;		/*  Type of input */
-	__u32	     audioset;	        /*  Associated audios (bitfield) */
+	__u32	     audioset;		/*  Associated audios (bitfield) */
 	__u32        tuner;             /*  Associated tuner */
 	v4l2_std_id  std;
 	__u32	     status;
@@ -647,9 +732,9 @@
 struct v4l2_output
 {
 	__u32	     index;		/*  Which output */
-	__u8	     name[32];	        /*  Label */
+	__u8	     name[32];		/*  Label */
 	__u32	     type;		/*  Type of output */
-	__u32	     audioset;	        /*  Associated audios (bitfield) */
+	__u32	     audioset;		/*  Associated audios (bitfield) */
 	__u32	     modulator;         /*  Associated modulator */
 	v4l2_std_id  std;
 	__u32	     reserved[4];
@@ -671,12 +756,12 @@
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
 struct v4l2_queryctrl
 {
-	__u32	             id;
+	__u32		     id;
 	enum v4l2_ctrl_type  type;
 	__u8		     name[32];	/* Whatever */
 	__s32		     minimum;	/* Note signedness */
 	__s32		     maximum;
-	__s32	             step;
+	__s32		     step;
 	__s32		     default_value;
 	__u32                flags;
 	__u32		     reserved[2];
@@ -779,10 +864,10 @@
 
 struct v4l2_frequency
 {
-	__u32	              tuner;
+	__u32		      tuner;
 	enum v4l2_tuner_type  type;
-        __u32	              frequency;
-	__u32	              reserved[8];
+	__u32		      frequency;
+	__u32		      reserved[8];
 };
 
 /*
@@ -802,6 +887,7 @@
 
 /*  Flags for the 'mode' field */
 #define V4L2_AUDMODE_AVL		0x00001
+#define V4L2_AUDMODE_32BITS		0x00002
 
 struct v4l2_audioout
 {
@@ -846,14 +932,14 @@
 
 struct v4l2_sliced_vbi_format
 {
-        __u16   service_set;
-        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
-           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
-                                 (equals frame lines 313-336 for 625 line video
-                                  standards, 263-286 for 525 line standards) */
-        __u16   service_lines[2][24];
-        __u32   io_size;
-        __u32   reserved[2];            /* must be zero */
+	__u16   service_set;
+	/* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+	   service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+				 (equals frame lines 313-336 for 625 line video
+				  standards, 263-286 for 525 line standards) */
+	__u16   service_lines[2][24];
+	__u32   io_size;
+	__u32   reserved[2];            /* must be zero */
 };
 
 #define V4L2_SLICED_TELETEXT_B          (0x0001)
@@ -866,22 +952,22 @@
 
 struct v4l2_sliced_vbi_cap
 {
-        __u16   service_set;
-        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
-           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
-                                 (equals frame lines 313-336 for 625 line video
-                                  standards, 263-286 for 525 line standards) */
-        __u16   service_lines[2][24];
-        __u32   reserved[4];    /* must be 0 */
+	__u16   service_set;
+	/* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+	   service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+				 (equals frame lines 313-336 for 625 line video
+				  standards, 263-286 for 525 line standards) */
+	__u16   service_lines[2][24];
+	__u32   reserved[4];    /* must be 0 */
 };
 
 struct v4l2_sliced_vbi_data
 {
-        __u32   id;
-        __u32   field;          /* 0: first field, 1: second field */
-        __u32   line;           /* 1-23 */
-        __u32   reserved;       /* must be 0 */
-        __u8    data[48];
+	__u32   id;
+	__u32   field;          /* 0: first field, 1: second field */
+	__u32   line;           /* 1-23 */
+	__u32   reserved;       /* must be 0 */
+	__u8    data[48];
 };
 #endif
 
@@ -896,9 +982,9 @@
 	enum v4l2_buf_type type;
 	union
 	{
-		struct v4l2_pix_format	        pix;     // V4L2_BUF_TYPE_VIDEO_CAPTURE
-		struct v4l2_window	        win;     // V4L2_BUF_TYPE_VIDEO_OVERLAY
-		struct v4l2_vbi_format	        vbi;     // V4L2_BUF_TYPE_VBI_CAPTURE
+		struct v4l2_pix_format		pix;     // V4L2_BUF_TYPE_VIDEO_CAPTURE
+		struct v4l2_window		win;     // V4L2_BUF_TYPE_VIDEO_OVERLAY
+		struct v4l2_vbi_format		vbi;     // V4L2_BUF_TYPE_VBI_CAPTURE
 #if 1
 		struct v4l2_sliced_vbi_format	sliced;  // V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
 #endif
@@ -981,6 +1067,7 @@
 #if 1
 #define VIDIOC_G_SLICED_VBI_CAP _IOR  ('V', 69, struct v4l2_sliced_vbi_cap)
 #endif
+#define VIDIOC_LOG_STATUS       _IO   ('V', 70)
 
 /* for compatibility, will go away some day */
 #define VIDIOC_OVERLAY_OLD     	_IOWR ('V', 14, int)
diff --git a/include/media/audiochip.h b/include/media/audiochip.h
index a7ceee9..b7d4b09 100644
--- a/include/media/audiochip.h
+++ b/include/media/audiochip.h
@@ -4,6 +4,23 @@
 #ifndef AUDIOCHIP_H
 #define AUDIOCHIP_H
 
+enum audiochip {
+	AUDIO_CHIP_NONE,
+	AUDIO_CHIP_UNKNOWN,
+	/* Provided by video chip */
+	AUDIO_CHIP_INTERNAL,
+	/* Provided by tvaudio.c */
+	AUDIO_CHIP_TDA8425,
+	AUDIO_CHIP_TEA6300,
+	AUDIO_CHIP_TEA6420,
+	AUDIO_CHIP_TDA9840,
+	AUDIO_CHIP_TDA985X,
+	AUDIO_CHIP_TDA9874,
+	AUDIO_CHIP_PIC16C54,
+	/* Provided by msp3400.c */
+	AUDIO_CHIP_MSP34XX
+};
+
 /* ---------------------------------------------------------------------- */
 
 /* v4l device was opened in Radio mode */
diff --git a/include/media/id.h b/include/media/id.h
deleted file mode 100644
index 6d02c94..0000000
--- a/include/media/id.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- */
-
-/* FIXME: this temporarely, until these are included in linux/i2c-id.h */
-
-/* drivers */
-#ifndef  I2C_DRIVERID_TVMIXER
-# define I2C_DRIVERID_TVMIXER I2C_DRIVERID_EXP0
-#endif
-#ifndef  I2C_DRIVERID_TVAUDIO
-# define I2C_DRIVERID_TVAUDIO I2C_DRIVERID_EXP1
-#endif
-
-/* chips */
-#ifndef  I2C_DRIVERID_DPL3518
-# define I2C_DRIVERID_DPL3518 I2C_DRIVERID_EXP2
-#endif
-#ifndef  I2C_DRIVERID_TDA9873
-# define I2C_DRIVERID_TDA9873 I2C_DRIVERID_EXP3
-#endif
-#ifndef  I2C_DRIVERID_TDA9875
-# define I2C_DRIVERID_TDA9875 I2C_DRIVERID_EXP0+4
-#endif
-#ifndef  I2C_DRIVERID_PIC16C54_PV951
-# define I2C_DRIVERID_PIC16C54_PV951 I2C_DRIVERID_EXP0+5
-#endif
-#ifndef  I2C_DRIVERID_TDA7432
-# define I2C_DRIVERID_TDA7432 I2C_DRIVERID_EXP0+6
-#endif
-#ifndef  I2C_DRIVERID_TDA9874
-# define I2C_DRIVERID_TDA9874 I2C_DRIVERID_EXP0+7
-#endif
-#ifndef  I2C_DRIVERID_SAA6752HS
-# define I2C_DRIVERID_SAA6752HS I2C_DRIVERID_EXP0+8
-#endif
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 01b5682..0f1ba95 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -20,8 +20,10 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/input.h>
+#ifndef _IR_COMMON
+#define _IR_COMMON
 
+#include <linux/input.h>
 
 #define IR_TYPE_RC5     1
 #define IR_TYPE_PD      2 /* Pulse distance encoded IR */
@@ -61,6 +63,8 @@
 int  ir_decode_biphase(u32 *samples, int count, int low, int high);
 int  ir_decode_pulsedistance(u32 *samples, int count, int low, int high);
 
+#endif
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
new file mode 100644
index 0000000..00fa57e
--- /dev/null
+++ b/include/media/ir-kbd-i2c.h
@@ -0,0 +1,22 @@
+#ifndef _IR_I2C
+#define _IR_I2C
+
+#include <media/ir-common.h>
+
+struct IR_i2c;
+
+struct IR_i2c {
+	IR_KEYTAB_TYPE         *ir_codes;
+	struct i2c_client      c;
+	struct input_dev       *input;
+	struct ir_input_state  ir;
+
+	/* Used to avoid fast repeating */
+	unsigned char          old;
+
+	struct work_struct     work;
+	struct timer_list      timer;
+	char                   phys[32];
+	int                    (*get_key)(struct IR_i2c*, u32*, u32*);
+};
+#endif
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
index f3aa24f..6469175 100644
--- a/include/media/saa7146_vv.h
+++ b/include/media/saa7146_vv.h
@@ -1,7 +1,7 @@
 #ifndef __SAA7146_VV__
 #define __SAA7146_VV__
 
-#include <linux/videodev2.h>
+#include <linux/videodev.h>
 
 #include <media/saa7146.h>
 #include <media/video-buf.h>
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 4ad08e2..9184e53 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -95,7 +95,7 @@
 #define TUNER_THOMSON_DTT7610		52
 #define TUNER_PHILIPS_FQ1286		53
 #define TUNER_PHILIPS_TDA8290		54
-#define TUNER_LG_PAL_TAPE		55	/* Hauppauge PVR-150 PAL */
+#define TUNER_TCL_2002MB		55	/* Hauppauge PVR-150 PAL */
 
 #define TUNER_PHILIPS_FQ1216AME_MK4	56	/* Hauppauge PVR-150 PAL */
 #define TUNER_PHILIPS_FQ1236A_MK4	57	/* Hauppauge PVR-500MCE NTSC */
@@ -110,6 +110,9 @@
 #define TUNER_LG_TDVS_H062F		64	/* DViCO FusionHDTV 5 */
 #define TUNER_YMEC_TVF66T5_B_DFF	65	/* Acorp Y878F */
 #define TUNER_LG_NTSC_TALN_MINI		66
+#define TUNER_PHILIPS_TD1316		67
+
+#define TUNER_PHILIPS_TUV1236D		68	/* ATI HDTV Wonder */
 
 #define NOTUNER 0
 #define PAL     1	/* PAL_BG */
@@ -145,6 +148,7 @@
 # define TDA9887_INTERCARRIER        (1<<4)
 # define TDA9887_PORT1_ACTIVE        (1<<5)
 # define TDA9887_PORT2_ACTIVE        (1<<6)
+# define TDA9887_INTERCARRIER_NTSC   (1<<7)
 /* config options */
 # define TDA9887_DEEMPHASIS_MASK     (3<<16)
 # define TDA9887_DEEMPHASIS_NONE     (1<<16)
@@ -188,8 +192,11 @@
 	unsigned int radio_if2;
 
 	/* used by tda8290 */
-	unsigned char i2c_easy_mode[2];
-	unsigned char i2c_set_freq[8];
+	unsigned char tda8290_easy_mode;
+	unsigned char tda827x_lpsel;
+	unsigned char tda827x_addr;
+	unsigned char tda827x_ver;
+	unsigned int sgIF;
 
 	/* function ptrs */
 	void (*tv_freq)(struct i2c_client *c, unsigned int freq);
@@ -204,20 +211,21 @@
 
 extern int microtune_init(struct i2c_client *c);
 extern int tda8290_init(struct i2c_client *c);
+extern int tda8290_probe(struct i2c_client *c);
 extern int tea5767_tuner_init(struct i2c_client *c);
 extern int default_tuner_init(struct i2c_client *c);
 extern int tea5767_autodetection(struct i2c_client *c);
 
 #define tuner_warn(fmt, arg...) do {\
 	printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->name, \
-                        t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+			t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
 #define tuner_info(fmt, arg...) do {\
 	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->name, \
-                        t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+			t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
 #define tuner_dbg(fmt, arg...) do {\
 	if (tuner_debug) \
-                printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->name, \
-                        t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+		printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->name, \
+			t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/media/video-buf.h b/include/media/video-buf.h
index ae8d7a0..8ecfd78 100644
--- a/include/media/video-buf.h
+++ b/include/media/video-buf.h
@@ -17,7 +17,7 @@
  * (at your option) any later version.
  */
 
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 
 #define UNSET (-1U)
 
@@ -177,7 +177,7 @@
 };
 
 struct videobuf_queue {
-        struct semaphore           lock;
+	struct semaphore           lock;
 	spinlock_t                 *irqlock;
 	struct pci_dev             *pci;
 
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index e42d728..911ceb5 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -57,8 +57,6 @@
 #define BT_DBG(fmt, arg...)  printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg)
 #define BT_ERR(fmt, arg...)  printk(KERN_ERR  "%s: " fmt "\n" , __FUNCTION__ , ## arg)
 
-extern struct proc_dir_entry *proc_bt;
-
 /* Connection and socket states */
 enum {
 	BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
@@ -177,4 +175,6 @@
 extern int bt_sysfs_init(void);
 extern void bt_sysfs_cleanup(void);
 
+extern struct class bt_class;
+
 #endif /* __BLUETOOTH_H */
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index fa2d12b..b06a2d2 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -184,10 +184,10 @@
 struct hci_rp_read_loc_version {
 	__u8     status;
 	__u8     hci_ver;
-	__u16    hci_rev;
+	__le16   hci_rev;
 	__u8     lmp_ver;
-	__u16    manufacturer;
-	__u16    lmp_subver;
+	__le16   manufacturer;
+	__le16   lmp_subver;
 } __attribute__ ((packed));
 
 #define OCF_READ_LOCAL_FEATURES	0x0003
@@ -199,10 +199,10 @@
 #define OCF_READ_BUFFER_SIZE	0x0005
 struct hci_rp_read_buffer_size {
 	__u8     status;
-	__u16    acl_mtu;
+	__le16   acl_mtu;
 	__u8     sco_mtu;
-	__u16    acl_max_pkt;
-	__u16    sco_max_pkt;
+	__le16   acl_max_pkt;
+	__le16   sco_max_pkt;
 } __attribute__ ((packed));
 
 #define OCF_READ_BD_ADDR	0x0009
@@ -267,21 +267,21 @@
 
 #define OCF_READ_VOICE_SETTING	0x0025
 struct hci_rp_read_voice_setting {
-	__u8	status;
-	__u16	voice_setting;
+	__u8     status;
+	__le16   voice_setting;
 } __attribute__ ((packed));
 
 #define OCF_WRITE_VOICE_SETTING	0x0026
 struct hci_cp_write_voice_setting {
-	__u16	voice_setting;
+	__le16   voice_setting;
 } __attribute__ ((packed));
 
 #define OCF_HOST_BUFFER_SIZE	0x0033
 struct hci_cp_host_buffer_size {
-	__u16    acl_mtu;
+	__le16   acl_mtu;
 	__u8     sco_mtu;
-	__u16    acl_max_pkt;
-	__u16    sco_max_pkt;
+	__le16   acl_max_pkt;
+	__le16   sco_max_pkt;
 } __attribute__ ((packed));
 
 /* Link Control */
@@ -289,10 +289,10 @@
 #define OCF_CREATE_CONN		0x0005
 struct hci_cp_create_conn {
 	bdaddr_t bdaddr;
-	__u16    pkt_type;
+	__le16   pkt_type;
 	__u8     pscan_rep_mode;
 	__u8     pscan_mode;
-	__u16    clock_offset;
+	__le16   clock_offset;
 	__u8     role_switch;
 } __attribute__ ((packed));
 
@@ -310,14 +310,14 @@
 
 #define OCF_DISCONNECT	0x0006
 struct hci_cp_disconnect {
-	__u16    handle;
+	__le16   handle;
 	__u8     reason;
 } __attribute__ ((packed));
 
 #define OCF_ADD_SCO	0x0007
 struct hci_cp_add_sco {
-	__u16    handle;
-	__u16    pkt_type;
+	__le16   handle;
+	__le16   pkt_type;
 } __attribute__ ((packed));
 
 #define OCF_INQUIRY		0x0001
@@ -354,56 +354,56 @@
 
 #define OCF_CHANGE_CONN_PTYPE	0x000F
 struct hci_cp_change_conn_ptype {
-	__u16    handle;
-	__u16    pkt_type;
+	__le16   handle;
+	__le16   pkt_type;
 } __attribute__ ((packed));
 
 #define OCF_AUTH_REQUESTED	0x0011
 struct hci_cp_auth_requested {
-	__u16    handle;
+	__le16   handle;
 } __attribute__ ((packed));
 
 #define OCF_SET_CONN_ENCRYPT	0x0013
 struct hci_cp_set_conn_encrypt {
-	__u16    handle;
+	__le16   handle;
 	__u8     encrypt;
 } __attribute__ ((packed));
 
 #define OCF_CHANGE_CONN_LINK_KEY 0x0015
 struct hci_cp_change_conn_link_key {
-	__u16    handle;
+	__le16   handle;
 } __attribute__ ((packed));
 
 #define OCF_READ_REMOTE_FEATURES 0x001B
 struct hci_cp_read_rmt_features {
-	__u16    handle;
+	__le16   handle;
 } __attribute__ ((packed));
 
 #define OCF_READ_REMOTE_VERSION 0x001D
 struct hci_cp_read_rmt_version {
-	__u16    handle;
+	__le16   handle;
 } __attribute__ ((packed));
 
 /* Link Policy */
 #define OGF_LINK_POLICY	 0x02   
 #define OCF_ROLE_DISCOVERY	0x0009
 struct hci_cp_role_discovery {
-	__u16    handle;
+	__le16   handle;
 } __attribute__ ((packed));
 struct hci_rp_role_discovery {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 	__u8     role;
 } __attribute__ ((packed));
 
 #define OCF_READ_LINK_POLICY	0x000C
 struct hci_cp_read_link_policy {
-	__u16    handle;
+	__le16   handle;
 } __attribute__ ((packed));
 struct hci_rp_read_link_policy {
 	__u8     status;
-	__u16    handle;
-	__u16    policy;
+	__le16   handle;
+	__le16   policy;
 } __attribute__ ((packed));
 
 #define OCF_SWITCH_ROLE	0x000B
@@ -414,12 +414,12 @@
 
 #define OCF_WRITE_LINK_POLICY	0x000D
 struct hci_cp_write_link_policy {
-	__u16    handle;
-	__u16    policy;
+	__le16   handle;
+	__le16   policy;
 } __attribute__ ((packed));
 struct hci_rp_write_link_policy {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 } __attribute__ ((packed));
 
 /* Status params */
@@ -441,7 +441,7 @@
 	__u8     pscan_period_mode;
 	__u8     pscan_mode;
 	__u8     dev_class[3];
-	__u16    clock_offset;
+	__le16   clock_offset;
 } __attribute__ ((packed));
 
 #define HCI_EV_INQUIRY_RESULT_WITH_RSSI	0x22
@@ -450,7 +450,7 @@
 	__u8     pscan_rep_mode;
 	__u8     pscan_period_mode;
 	__u8     dev_class[3];
-	__u16    clock_offset;
+	__le16   clock_offset;
 	__s8     rssi;
 } __attribute__ ((packed));
 struct inquiry_info_with_rssi_and_pscan_mode {
@@ -459,7 +459,7 @@
 	__u8     pscan_period_mode;
 	__u8     pscan_mode;
 	__u8     dev_class[3];
-	__u16    clock_offset;
+	__le16   clock_offset;
 	__s8     rssi;
 } __attribute__ ((packed));
 
@@ -469,7 +469,7 @@
 	__u8     pscan_rep_mode;
 	__u8     pscan_period_mode;
 	__u8     dev_class[3];
-	__u16    clock_offset;
+	__le16   clock_offset;
 	__s8     rssi;
 	__u8     data[240];
 } __attribute__ ((packed));
@@ -477,7 +477,7 @@
 #define HCI_EV_CONN_COMPLETE 	0x03
 struct hci_ev_conn_complete {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 	bdaddr_t bdaddr;
 	__u8     link_type;
 	__u8     encr_mode;
@@ -493,27 +493,27 @@
 #define HCI_EV_DISCONN_COMPLETE	0x05
 struct hci_ev_disconn_complete {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 	__u8     reason;
 } __attribute__ ((packed));
 
 #define HCI_EV_AUTH_COMPLETE	0x06
 struct hci_ev_auth_complete {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 } __attribute__ ((packed));
 
 #define HCI_EV_ENCRYPT_CHANGE	0x08
 struct hci_ev_encrypt_change {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 	__u8     encrypt;
 } __attribute__ ((packed));
 
 #define HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE	0x09
 struct hci_ev_change_conn_link_key_complete {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 } __attribute__ ((packed));
 
 #define HCI_EV_QOS_SETUP_COMPLETE	0x0D
@@ -526,21 +526,21 @@
 } __attribute__ ((packed));
 struct hci_ev_qos_setup_complete {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 	struct   hci_qos qos;
 } __attribute__ ((packed));
 
 #define HCI_EV_CMD_COMPLETE 	0x0E
 struct hci_ev_cmd_complete {
 	__u8     ncmd;
-	__u16    opcode;
+	__le16   opcode;
 } __attribute__ ((packed));
 
 #define HCI_EV_CMD_STATUS 	0x0F
 struct hci_ev_cmd_status {
 	__u8     status;
 	__u8     ncmd;
-	__u16    opcode;
+	__le16   opcode;
 } __attribute__ ((packed));
 
 #define HCI_EV_NUM_COMP_PKTS	0x13
@@ -559,9 +559,9 @@
 #define HCI_EV_MODE_CHANGE	0x14
 struct hci_ev_mode_change {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 	__u8     mode;
-	__u16    interval;
+	__le16   interval;
 } __attribute__ ((packed));
 
 #define HCI_EV_PIN_CODE_REQ	0x16
@@ -584,24 +584,24 @@
 #define HCI_EV_RMT_FEATURES	0x0B
 struct hci_ev_rmt_features {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 	__u8     features[8];
 } __attribute__ ((packed));
 
 #define HCI_EV_RMT_VERSION	0x0C
 struct hci_ev_rmt_version {
 	__u8     status;
-	__u16    handle;
+	__le16   handle;
 	__u8     lmp_ver;
-	__u16    manufacturer;
-	__u16    lmp_subver;
+	__le16   manufacturer;
+	__le16   lmp_subver;
 } __attribute__ ((packed));
 
 #define HCI_EV_CLOCK_OFFSET	0x01C
 struct hci_ev_clock_offset {
 	__u8     status;
-	__u16    handle;
-	__u16    clock_offset;
+	__le16   handle;
+	__le16   clock_offset;
 } __attribute__ ((packed));
 
 #define HCI_EV_PSCAN_REP_MODE	0x20
@@ -638,7 +638,7 @@
 #define HCI_SCO_HDR_SIZE     3
 
 struct hci_command_hdr {
-	__u16 	opcode;		/* OCF & OGF */
+	__le16 	opcode;		/* OCF & OGF */
 	__u8 	plen;
 } __attribute__ ((packed));
 
@@ -648,22 +648,22 @@
 } __attribute__ ((packed));
 
 struct hci_acl_hdr {
-	__u16 	handle;		/* Handle & Flags(PB, BC) */
-	__u16 	dlen;
+	__le16 	handle;		/* Handle & Flags(PB, BC) */
+	__le16 	dlen;
 } __attribute__ ((packed));
 
 struct hci_sco_hdr {
-	__u16 	handle;
+	__le16 	handle;
 	__u8 	dlen;
 } __attribute__ ((packed));
 
 /* Command opcode pack/unpack */
-#define hci_opcode_pack(ogf, ocf)	(__u16)((ocf & 0x03ff)|(ogf << 10))
+#define hci_opcode_pack(ogf, ocf)	(__u16) ((ocf & 0x03ff)|(ogf << 10))
 #define hci_opcode_ogf(op)		(op >> 10)
 #define hci_opcode_ocf(op)		(op & 0x03ff)
 
 /* ACL handle and flags pack/unpack */
-#define hci_handle_pack(h, f)	(__u16)((h & 0x0fff)|(f << 12))
+#define hci_handle_pack(h, f)	(__u16) ((h & 0x0fff)|(f << 12))
 #define hci_handle(h)		(h & 0x0fff)
 #define hci_flags(h)		(h >> 12)
 
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7f933f3..bb9f81d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -25,7 +25,6 @@
 #ifndef __HCI_CORE_H
 #define __HCI_CORE_H
 
-#include <linux/proc_fs.h>
 #include <net/bluetooth/hci.h>
 
 /* HCI upper protocols */
@@ -34,8 +33,6 @@
 
 #define HCI_INIT_TIMEOUT (HZ * 10)
 
-extern struct proc_dir_entry *proc_bt_hci;
-
 /* HCI Core structures */
 
 struct inquiry_data {
@@ -44,7 +41,7 @@
 	__u8		pscan_period_mode;
 	__u8		pscan_mode;
 	__u8		dev_class[3];
-	__u16		clock_offset;
+	__le16		clock_offset;
 	__s8		rssi;
 };
 
@@ -126,10 +123,6 @@
 
 	atomic_t 		promisc;
 
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry	*proc;
-#endif
-
 	struct class_device	class_dev;
 
 	struct module 		*owner;
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index e656be7..bbfac86 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -351,6 +351,4 @@
 int  rfcomm_init_ttys(void);
 void rfcomm_cleanup_ttys(void);
 
-extern struct proc_dir_entry *proc_bt_rfcomm;
-
 #endif /* __RFCOMM_H */
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
new file mode 100644
index 0000000..52d8b1a
--- /dev/null
+++ b/include/net/genetlink.h
@@ -0,0 +1,154 @@
+#ifndef __NET_GENERIC_NETLINK_H
+#define __NET_GENERIC_NETLINK_H
+
+#include <linux/genetlink.h>
+#include <net/netlink.h>
+
+/**
+ * struct genl_family - generic netlink family
+ * @id: protocol family idenfitier
+ * @hdrsize: length of user specific header in bytes
+ * @name: name of family
+ * @version: protocol version
+ * @maxattr: maximum number of attributes supported
+ * @attrbuf: buffer to store parsed attributes
+ * @ops_list: list of all assigned operations
+ * @family_list: family list
+ */
+struct genl_family
+{
+	unsigned int		id;
+	unsigned int		hdrsize;
+	char			name[GENL_NAMSIZ];
+	unsigned int		version;
+	unsigned int		maxattr;
+	struct module *		owner;
+	struct nlattr **	attrbuf;	/* private */
+	struct list_head	ops_list;	/* private */
+	struct list_head	family_list;	/* private */
+};
+
+#define GENL_ADMIN_PERM		0x01
+
+/**
+ * struct genl_info - receiving information
+ * @snd_seq: sending sequence number
+ * @snd_pid: netlink pid of sender
+ * @nlhdr: netlink message header
+ * @genlhdr: generic netlink message header
+ * @userhdr: user specific header
+ * @attrs: netlink attributes
+ */
+struct genl_info
+{
+	u32			snd_seq;
+	u32			snd_pid;
+	struct nlmsghdr *	nlhdr;
+	struct genlmsghdr *	genlhdr;
+	void *			userhdr;
+	struct nlattr **	attrs;
+};
+
+/**
+ * struct genl_ops - generic netlink operations
+ * @cmd: command identifier
+ * @flags: flags
+ * @policy: attribute validation policy
+ * @doit: standard command callback
+ * @dumpit: callback for dumpers
+ * @ops_list: operations list
+ */
+struct genl_ops
+{
+	unsigned int		cmd;
+	unsigned int		flags;
+	struct nla_policy	*policy;
+	int		       (*doit)(struct sk_buff *skb,
+				       struct genl_info *info);
+	int		       (*dumpit)(struct sk_buff *skb,
+					 struct netlink_callback *cb);
+	struct list_head	ops_list;
+};
+
+extern int genl_register_family(struct genl_family *family);
+extern int genl_unregister_family(struct genl_family *family);
+extern int genl_register_ops(struct genl_family *, struct genl_ops *ops);
+extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
+
+extern struct sock *genl_sock;
+
+/**
+ * genlmsg_put - Add generic netlink header to netlink message
+ * @skb: socket buffer holding the message
+ * @pid: netlink pid the message is addressed to
+ * @seq: sequence number (usually the one of the sender)
+ * @type: netlink message type
+ * @hdrlen: length of the user specific header
+ * @flags netlink message flags
+ * @cmd: generic netlink command
+ * @version: version
+ *
+ * Returns pointer to user specific header
+ */
+static inline void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq,
+				int type, int hdrlen, int flags,
+				u8 cmd, u8 version)
+{
+	struct nlmsghdr *nlh;
+	struct genlmsghdr *hdr;
+
+	nlh = nlmsg_put(skb, pid, seq, type, GENL_HDRLEN + hdrlen, flags);
+	if (nlh == NULL)
+		return NULL;
+
+	hdr = nlmsg_data(nlh);
+	hdr->cmd = cmd;
+	hdr->version = version;
+	hdr->reserved = 0;
+
+	return (char *) hdr + GENL_HDRLEN;
+}
+
+/**
+ * genlmsg_end - Finalize a generic netlink message
+ * @skb: socket buffer the message is stored in
+ * @hdr: user specific header
+ */
+static inline int genlmsg_end(struct sk_buff *skb, void *hdr)
+{
+	return nlmsg_end(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
+}
+
+/**
+ * genlmsg_cancel - Cancel construction of a generic netlink message
+ * @skb: socket buffer the message is stored in
+ * @hdr: generic netlink message header
+ */
+static inline int genlmsg_cancel(struct sk_buff *skb, void *hdr)
+{
+	return nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
+}
+
+/**
+ * genlmsg_multicast - multicast a netlink message
+ * @skb: netlink message as socket buffer
+ * @pid: own netlink pid to avoid sending to yourself
+ * @group: multicast group id
+ */
+static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid,
+				    unsigned int group)
+{
+	return nlmsg_multicast(genl_sock, skb, pid, group);
+}
+
+/**
+ * genlmsg_unicast - unicast a netlink message
+ * @skb: netlink message as socket buffer
+ * @pid: netlink pid of the destination socket
+ */
+static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
+{
+	return nlmsg_unicast(genl_sock, skb, pid);
+}
+
+#endif	/* __NET_GENERIC_NETLINK_H */
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index 5e38dca..b93fd8c 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -29,7 +29,7 @@
 #include <linux/kernel.h>	/* ARRAY_SIZE */
 #include <linux/wireless.h>
 
-#define IEEE80211_VERSION "git-1.1.6"
+#define IEEE80211_VERSION "git-1.1.7"
 
 #define IEEE80211_DATA_LEN		2304
 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
index 0a1c2d8..225fc751 100644
--- a/include/net/ieee80211_crypt.h
+++ b/include/net/ieee80211_crypt.h
@@ -31,6 +31,7 @@
 
 struct ieee80211_crypto_ops {
 	const char *name;
+	struct list_head list;
 
 	/* init new crypto context (e.g., allocate private data space,
 	 * select IV, etc.); returns NULL on failure or pointer to allocated
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 65ec866..6addb4d 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -252,12 +252,25 @@
 					   char *,
 					   unsigned int, unsigned int);
 
-
-extern int		ipv6_addr_type(const struct in6_addr *addr);
+extern int __ipv6_addr_type(const struct in6_addr *addr);
+static inline int ipv6_addr_type(const struct in6_addr *addr)
+{
+	return __ipv6_addr_type(addr) & 0xffff;
+}
 
 static inline int ipv6_addr_scope(const struct in6_addr *addr)
 {
-	return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
+	return __ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
+}
+
+static inline int __ipv6_addr_src_scope(int type)
+{
+	return (type == IPV6_ADDR_ANY ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16));
+}
+
+static inline int ipv6_addr_src_scope(const struct in6_addr *addr)
+{
+	return __ipv6_addr_src_scope(__ipv6_addr_type(addr));
 }
 
 static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
@@ -341,6 +354,54 @@
 }
 
 /*
+ * find the first different bit between two addresses
+ * length of address must be a multiple of 32bits
+ */
+static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen)
+{
+	const __u32 *a1 = token1, *a2 = token2;
+	int i;
+
+	addrlen >>= 2;
+
+	for (i = 0; i < addrlen; i++) {
+		__u32 xb = a1[i] ^ a2[i];
+		if (xb) {
+			int j = 31;
+
+			xb = ntohl(xb);
+			while ((xb & (1 << j)) == 0)
+				j--;
+
+			return (i * 32 + 31 - j);
+		}
+	}
+
+	/*
+	 *	we should *never* get to this point since that 
+	 *	would mean the addrs are equal
+	 *
+	 *	However, we do get to it 8) And exacly, when
+	 *	addresses are equal 8)
+	 *
+	 *	ip route add 1111::/128 via ...
+	 *	ip route add 1111::/64 via ...
+	 *	and we are here.
+	 *
+	 *	Ideally, this function should stop comparison
+	 *	at prefix length. It does not, but it is still OK,
+	 *	if returned value is greater than prefix length.
+	 *					--ANK (980803)
+	 */
+	return (addrlen << 5);
+}
+
+static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2)
+{
+	return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
+}
+
+/*
  *	Prototypes exported by ipv6
  */
 
diff --git a/include/net/netfilter/ipv4/nf_conntrack_icmp.h b/include/net/netfilter/ipv4/nf_conntrack_icmp.h
new file mode 100644
index 0000000..3dd22cf
--- /dev/null
+++ b/include/net/netfilter/ipv4/nf_conntrack_icmp.h
@@ -0,0 +1,11 @@
+#ifndef _NF_CONNTRACK_ICMP_H
+#define _NF_CONNTRACK_ICMP_H
+/* ICMP tracking. */
+#include <asm/atomic.h>
+
+struct ip_ct_icmp
+{
+	/* Optimization: when number in == number out, forget immediately. */
+	atomic_t count;
+};
+#endif /* _NF_CONNTRACK_ICMP_H */
diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
new file mode 100644
index 0000000..25b081a
--- /dev/null
+++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
@@ -0,0 +1,43 @@
+/*
+ * IPv4 support for nf_conntrack.
+ *
+ * 23 Mar 2004: Yasuyuki Kozakai @ USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- move L3 protocol dependent part from include/linux/netfilter_ipv4/
+ *	  ip_conntarck.h
+ */
+
+#ifndef _NF_CONNTRACK_IPV4_H
+#define _NF_CONNTRACK_IPV4_H
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+#include <linux/netfilter_ipv4/ip_nat.h>
+
+/* per conntrack: nat application helper private data */
+union ip_conntrack_nat_help {
+        /* insert nat helper private data here */
+};
+
+struct nf_conntrack_ipv4_nat {
+	struct ip_nat_info info;
+	union ip_conntrack_nat_help help;
+#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
+	defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
+	int masq_index;
+#endif
+};
+#endif /* CONFIG_IP_NF_NAT_NEEDED */
+
+struct nf_conntrack_ipv4 {
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+	struct nf_conntrack_ipv4_nat *nat;
+#endif
+};
+
+/* Returns new sk_buff, or NULL */
+struct sk_buff *
+nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
+
+/* call to create an explicit dependency on nf_conntrack_l3proto_ipv4. */
+extern void need_ip_conntrack(void);
+
+#endif /*_NF_CONNTRACK_IPV4_H*/
diff --git a/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h
new file mode 100644
index 0000000..86591af
--- /dev/null
+++ b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h
@@ -0,0 +1,27 @@
+/*
+ * ICMPv6 tracking.
+ *
+ * 21 Apl 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- separated from nf_conntrack_icmp.h
+ *
+ * Derived from include/linux/netfiter_ipv4/ip_conntrack_icmp.h
+ */
+
+#ifndef _NF_CONNTRACK_ICMPV6_H
+#define _NF_CONNTRACK_ICMPV6_H
+#include <asm/atomic.h>
+
+#ifndef ICMPV6_NI_QUERY
+#define ICMPV6_NI_QUERY 139
+#endif
+#ifndef ICMPV6_NI_REPLY
+#define ICMPV6_NI_REPLY 140
+#endif
+
+struct nf_ct_icmpv6
+{
+	/* Optimization: when number in == number out, forget immediately. */
+	atomic_t count;
+};
+
+#endif /* _NF_CONNTRACK_ICMPV6_H */
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
new file mode 100644
index 0000000..cc48256
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack.h
@@ -0,0 +1,354 @@
+/*
+ * Connection state tracking for netfilter.  This is separated from,
+ * but required by, the (future) NAT layer; it can also be used by an iptables
+ * extension.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- generalize L3 protocol dependent part.
+ *
+ * Derived from include/linux/netfiter_ipv4/ip_conntrack.h
+ */
+
+#ifndef _NF_CONNTRACK_H
+#define _NF_CONNTRACK_H
+
+#include <linux/netfilter/nf_conntrack_common.h>
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <asm/atomic.h>
+
+#include <linux/netfilter/nf_conntrack_tcp.h>
+#include <linux/netfilter/nf_conntrack_sctp.h>
+#include <net/netfilter/ipv4/nf_conntrack_icmp.h>
+#include <net/netfilter/ipv6/nf_conntrack_icmpv6.h>
+
+#include <net/netfilter/nf_conntrack_tuple.h>
+
+/* per conntrack: protocol private data */
+union nf_conntrack_proto {
+	/* insert conntrack proto private data here */
+	struct ip_ct_sctp sctp;
+	struct ip_ct_tcp tcp;
+	struct ip_ct_icmp icmp;
+	struct nf_ct_icmpv6 icmpv6;
+};
+
+union nf_conntrack_expect_proto {
+	/* insert expect proto private data here */
+};
+
+/* Add protocol helper include file here */
+#include <linux/netfilter/nf_conntrack_ftp.h>
+
+/* per conntrack: application helper private data */
+union nf_conntrack_help {
+	/* insert conntrack helper private data (master) here */
+	struct ip_ct_ftp_master ct_ftp_info;
+};
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#ifdef CONFIG_NETFILTER_DEBUG
+#define NF_CT_ASSERT(x)							\
+do {									\
+	if (!(x))							\
+		/* Wooah!  I'm tripping my conntrack in a frenzy of	\
+		   netplay... */					\
+		printk("NF_CT_ASSERT: %s:%i(%s)\n",			\
+		       __FILE__, __LINE__, __FUNCTION__);		\
+} while(0)
+#else
+#define NF_CT_ASSERT(x)
+#endif
+
+struct nf_conntrack_helper;
+
+#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
+struct nf_conn
+{
+	/* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
+           plus 1 for any connection(s) we are `master' for */
+	struct nf_conntrack ct_general;
+
+	/* XXX should I move this to the tail ? - Y.K */
+	/* These are my tuples; original and reply */
+	struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
+
+	/* Have we seen traffic both ways yet? (bitset) */
+	unsigned long status;
+
+	/* Timer function; drops refcnt when it goes off. */
+	struct timer_list timeout;
+
+#ifdef CONFIG_NF_CT_ACCT
+	/* Accounting Information (same cache line as other written members) */
+	struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
+#endif
+	/* If we were expected by an expectation, this will be it */
+	struct nf_conn *master;
+	
+	/* Current number of expected connections */
+	unsigned int expecting;
+
+	/* Helper. if any */
+	struct nf_conntrack_helper *helper;
+
+	/* features - nat, helper, ... used by allocating system */
+	u_int32_t features;
+
+	/* Storage reserved for other modules: */
+
+	union nf_conntrack_proto proto;
+
+#if defined(CONFIG_NF_CONNTRACK_MARK)
+	u_int32_t mark;
+#endif
+
+	/* These members are dynamically allocated. */
+
+	union nf_conntrack_help *help;
+
+	/* Layer 3 dependent members. (ex: NAT) */
+	union {
+		struct nf_conntrack_ipv4 *ipv4;
+	} l3proto;
+	void *data[0];
+};
+
+struct nf_conntrack_expect
+{
+	/* Internal linked list (global expectation list) */
+	struct list_head list;
+
+	/* We expect this tuple, with the following mask */
+	struct nf_conntrack_tuple tuple, mask;
+ 
+	/* Function to call after setup and insertion */
+	void (*expectfn)(struct nf_conn *new,
+			 struct nf_conntrack_expect *this);
+
+	/* The conntrack of the master connection */
+	struct nf_conn *master;
+
+	/* Timer function; deletes the expectation. */
+	struct timer_list timeout;
+
+	/* Usage count. */
+	atomic_t use;
+
+	/* Flags */
+	unsigned int flags;
+
+#ifdef CONFIG_NF_NAT_NEEDED
+	/* This is the original per-proto part, used to map the
+	 * expected connection the way the recipient expects. */
+	union nf_conntrack_manip_proto saved_proto;
+	/* Direction relative to the master connection. */
+	enum ip_conntrack_dir dir;
+#endif
+};
+
+#define NF_CT_EXPECT_PERMANENT 0x1
+
+static inline struct nf_conn *
+nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash)
+{
+	return container_of(hash, struct nf_conn,
+			    tuplehash[hash->tuple.dst.dir]);
+}
+
+/* get master conntrack via master expectation */
+#define master_ct(conntr) (conntr->master)
+
+/* Alter reply tuple (maybe alter helper). */
+extern void
+nf_conntrack_alter_reply(struct nf_conn *conntrack,
+			 const struct nf_conntrack_tuple *newreply);
+
+/* Is this tuple taken? (ignoring any belonging to the given
+   conntrack). */
+extern int
+nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
+			 const struct nf_conn *ignored_conntrack);
+
+/* Return conntrack_info and tuple hash for given skb. */
+static inline struct nf_conn *
+nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
+{
+	*ctinfo = skb->nfctinfo;
+	return (struct nf_conn *)skb->nfct;
+}
+
+/* decrement reference count on a conntrack */
+static inline void nf_ct_put(struct nf_conn *ct)
+{
+	NF_CT_ASSERT(ct);
+	nf_conntrack_put(&ct->ct_general);
+}
+
+/* call to create an explicit dependency on nf_conntrack. */
+extern void need_nf_conntrack(void);
+
+extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
+				const struct nf_conntrack_tuple *orig);
+
+extern void __nf_ct_refresh_acct(struct nf_conn *ct,
+				 enum ip_conntrack_info ctinfo,
+				 const struct sk_buff *skb,
+				 unsigned long extra_jiffies,
+				 int do_acct);
+
+/* Refresh conntrack for this many jiffies and do accounting */
+static inline void nf_ct_refresh_acct(struct nf_conn *ct,
+				      enum ip_conntrack_info ctinfo,
+				      const struct sk_buff *skb,
+				      unsigned long extra_jiffies)
+{
+	__nf_ct_refresh_acct(ct, ctinfo, skb, extra_jiffies, 1);
+}
+
+/* Refresh conntrack for this many jiffies */
+static inline void nf_ct_refresh(struct nf_conn *ct,
+				 const struct sk_buff *skb,
+				 unsigned long extra_jiffies)
+{
+	__nf_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0);
+}
+
+/* These are for NAT.  Icky. */
+/* Update TCP window tracking data when NAT mangles the packet */
+extern void nf_conntrack_tcp_update(struct sk_buff *skb,
+				    unsigned int dataoff,
+				    struct nf_conn *conntrack,
+				    int dir);
+
+/* Call me when a conntrack is destroyed. */
+extern void (*nf_conntrack_destroyed)(struct nf_conn *conntrack);
+
+/* Fake conntrack entry for untracked connections */
+extern struct nf_conn nf_conntrack_untracked;
+
+extern int nf_ct_no_defrag;
+
+/* Iterate over all conntracks: if iter returns true, it's deleted. */
+extern void
+nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data);
+extern void nf_conntrack_free(struct nf_conn *ct);
+extern struct nf_conn *
+nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+		   const struct nf_conntrack_tuple *repl);
+
+/* It's confirmed if it is, or has been in the hash table. */
+static inline int nf_ct_is_confirmed(struct nf_conn *ct)
+{
+	return test_bit(IPS_CONFIRMED_BIT, &ct->status);
+}
+
+static inline int nf_ct_is_dying(struct nf_conn *ct)
+{
+	return test_bit(IPS_DYING_BIT, &ct->status);
+}
+
+extern unsigned int nf_conntrack_htable_size;
+
+#define NF_CT_STAT_INC(count) (__get_cpu_var(nf_conntrack_stat).count++)
+
+#ifdef CONFIG_NF_CONNTRACK_EVENTS
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+
+struct nf_conntrack_ecache {
+	struct nf_conn *ct;
+	unsigned int events;
+};
+DECLARE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache);
+
+#define CONNTRACK_ECACHE(x)	(__get_cpu_var(nf_conntrack_ecache).x)
+
+extern struct notifier_block *nf_conntrack_chain;
+extern struct notifier_block *nf_conntrack_expect_chain;
+
+static inline int nf_conntrack_register_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_register(&nf_conntrack_chain, nb);
+}
+
+static inline int nf_conntrack_unregister_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&nf_conntrack_chain, nb);
+}
+
+static inline int
+nf_conntrack_expect_register_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_register(&nf_conntrack_expect_chain, nb);
+}
+
+static inline int
+nf_conntrack_expect_unregister_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&nf_conntrack_expect_chain, nb);
+}
+
+extern void nf_ct_deliver_cached_events(const struct nf_conn *ct);
+extern void __nf_ct_event_cache_init(struct nf_conn *ct);
+
+static inline void
+nf_conntrack_event_cache(enum ip_conntrack_events event,
+			 const struct sk_buff *skb)
+{
+	struct nf_conn *ct = (struct nf_conn *)skb->nfct;
+	struct nf_conntrack_ecache *ecache;
+
+	local_bh_disable();
+	ecache = &__get_cpu_var(nf_conntrack_ecache);
+	if (ct != ecache->ct)
+		__nf_ct_event_cache_init(ct);
+	ecache->events |= event;
+	local_bh_enable();
+}
+
+static inline void nf_conntrack_event(enum ip_conntrack_events event,
+				      struct nf_conn *ct)
+{
+	if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct))
+		notifier_call_chain(&nf_conntrack_chain, event, ct);
+}
+
+static inline void
+nf_conntrack_expect_event(enum ip_conntrack_expect_events event,
+			  struct nf_conntrack_expect *exp)
+{
+	notifier_call_chain(&nf_conntrack_expect_chain, event, exp);
+}
+#else /* CONFIG_NF_CONNTRACK_EVENTS */
+static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
+					    const struct sk_buff *skb) {}
+static inline void nf_conntrack_event(enum ip_conntrack_events event,
+				      struct nf_conn *ct) {}
+static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {}
+static inline void
+nf_conntrack_expect_event(enum ip_conntrack_expect_events event,
+			  struct nf_conntrack_expect *exp) {}
+#endif /* CONFIG_NF_CONNTRACK_EVENTS */
+
+/* no helper, no nat */
+#define	NF_CT_F_BASIC	0
+/* for helper */
+#define	NF_CT_F_HELP	1
+/* for nat. */
+#define	NF_CT_F_NAT	2
+#define NF_CT_F_NUM	4
+
+extern int
+nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size,
+			    int (*init_conntrack)(struct nf_conn *, u_int32_t));
+extern void
+nf_conntrack_unregister_cache(u_int32_t features);
+
+#endif /* __KERNEL__ */
+#endif /* _NF_CONNTRACK_H */
diff --git a/include/net/netfilter/nf_conntrack_compat.h b/include/net/netfilter/nf_conntrack_compat.h
new file mode 100644
index 0000000..3cac19f
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_compat.h
@@ -0,0 +1,108 @@
+#ifndef _NF_CONNTRACK_COMPAT_H
+#define _NF_CONNTRACK_COMPAT_H
+
+#ifdef __KERNEL__
+
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
+
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+
+#ifdef CONFIG_IP_NF_CONNTRACK_MARK
+static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb,
+					u_int32_t *ctinfo)
+{
+	struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo);
+
+	if (ct)
+		return &ct->mark;
+	else
+		return NULL;
+}
+#endif /* CONFIG_IP_NF_CONNTRACK_MARK */
+
+#ifdef CONFIG_IP_NF_CT_ACCT
+static inline struct ip_conntrack_counter *
+nf_ct_get_counters(const struct sk_buff *skb)
+{
+	enum ip_conntrack_info ctinfo;
+	struct ip_conntrack *ct = ip_conntrack_get(skb, &ctinfo);
+
+	if (ct)
+		return ct->counters;
+	else
+		return NULL;
+}
+#endif /* CONFIG_IP_NF_CT_ACCT */
+
+static inline int nf_ct_is_untracked(const struct sk_buff *skb)
+{
+	return (skb->nfct == &ip_conntrack_untracked.ct_general);
+}
+
+static inline void nf_ct_untrack(struct sk_buff *skb)
+{
+	skb->nfct = &ip_conntrack_untracked.ct_general;
+}
+
+static inline int nf_ct_get_ctinfo(const struct sk_buff *skb,
+				   enum ip_conntrack_info *ctinfo)
+{
+	struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo);
+	return (ct != NULL);
+}
+
+#else /* CONFIG_IP_NF_CONNTRACK */
+
+#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
+#include <net/netfilter/nf_conntrack.h>
+
+#ifdef CONFIG_NF_CONNTRACK_MARK
+
+static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb,
+					u_int32_t *ctinfo)
+{
+	struct nf_conn *ct = nf_ct_get(skb, ctinfo);
+
+	if (ct)
+		return &ct->mark;
+	else
+		return NULL;
+}
+#endif /* CONFIG_NF_CONNTRACK_MARK */
+
+#ifdef CONFIG_NF_CT_ACCT
+static inline struct ip_conntrack_counter *
+nf_ct_get_counters(const struct sk_buff *skb)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
+	if (ct)
+		return ct->counters;
+	else
+		return NULL;
+}
+#endif /* CONFIG_NF_CT_ACCT */
+
+static inline int nf_ct_is_untracked(const struct sk_buff *skb)
+{
+	return (skb->nfct == &nf_conntrack_untracked.ct_general);
+}
+
+static inline void nf_ct_untrack(struct sk_buff *skb)
+{
+	skb->nfct = &nf_conntrack_untracked.ct_general;
+}
+
+static inline int nf_ct_get_ctinfo(const struct sk_buff *skb,
+				   enum ip_conntrack_info *ctinfo)
+{
+	struct nf_conn *ct = nf_ct_get(skb, ctinfo);
+	return (ct != NULL);
+}
+
+#endif /* CONFIG_IP_NF_CONNTRACK */
+
+#endif /* __KERNEL__ */
+
+#endif /* _NF_CONNTRACK_COMPAT_H */
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
new file mode 100644
index 0000000..da25452
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -0,0 +1,76 @@
+/*
+ * This header is used to share core functionality between the
+ * standalone connection tracking module, and the compatibility layer's use
+ * of connection tracking.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- generalize L3 protocol dependent part.
+ *
+ * Derived from include/linux/netfiter_ipv4/ip_conntrack_core.h
+ */
+
+#ifndef _NF_CONNTRACK_CORE_H
+#define _NF_CONNTRACK_CORE_H
+
+#include <linux/netfilter.h>
+
+/* This header is used to share core functionality between the
+   standalone connection tracking module, and the compatibility layer's use
+   of connection tracking. */
+extern unsigned int nf_conntrack_in(int pf,
+				    unsigned int hooknum,
+				    struct sk_buff **pskb);
+
+extern int nf_conntrack_init(void);
+extern void nf_conntrack_cleanup(void);
+
+struct nf_conntrack_l3proto;
+extern struct nf_conntrack_l3proto *nf_ct_find_l3proto(u_int16_t pf);
+/* Like above, but you already have conntrack read lock. */
+extern struct nf_conntrack_l3proto *__nf_ct_find_l3proto(u_int16_t l3proto);
+
+struct nf_conntrack_protocol;
+
+extern int
+nf_ct_get_tuple(const struct sk_buff *skb,
+		unsigned int nhoff,
+		unsigned int dataoff,
+		u_int16_t l3num,
+		u_int8_t protonum,
+		struct nf_conntrack_tuple *tuple,
+		const struct nf_conntrack_l3proto *l3proto,
+		const struct nf_conntrack_protocol *protocol);
+
+extern int
+nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
+		   const struct nf_conntrack_tuple *orig,
+		   const struct nf_conntrack_l3proto *l3proto,
+		   const struct nf_conntrack_protocol *protocol);
+
+/* Find a connection corresponding to a tuple. */
+extern struct nf_conntrack_tuple_hash *
+nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple,
+		      const struct nf_conn *ignored_conntrack);
+
+extern int __nf_conntrack_confirm(struct sk_buff **pskb);
+
+/* Confirm a connection: returns NF_DROP if packet must be dropped. */
+static inline int nf_conntrack_confirm(struct sk_buff **pskb)
+{
+	struct nf_conn *ct = (struct nf_conn *)(*pskb)->nfct;
+	int ret = NF_ACCEPT;
+
+	if (ct) {
+		if (!nf_ct_is_confirmed(ct))
+			ret = __nf_conntrack_confirm(pskb);
+		nf_ct_deliver_cached_events(ct);
+	}
+	return ret;
+}
+
+extern void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb);
+
+extern struct list_head *nf_conntrack_hash;
+extern struct list_head nf_conntrack_expect_list;
+extern rwlock_t nf_conntrack_lock ;
+#endif /* _NF_CONNTRACK_CORE_H */
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
new file mode 100644
index 0000000..5a66b2a
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -0,0 +1,51 @@
+/*
+ * connection tracking helpers.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- generalize L3 protocol dependent part.
+ *
+ * Derived from include/linux/netfiter_ipv4/ip_conntrack_helper.h
+ */
+
+#ifndef _NF_CONNTRACK_HELPER_H
+#define _NF_CONNTRACK_HELPER_H
+#include <net/netfilter/nf_conntrack.h>
+
+struct module;
+
+struct nf_conntrack_helper
+{	
+	struct list_head list; 		/* Internal use. */
+
+	const char *name;		/* name of the module */
+	struct module *me;		/* pointer to self */
+	unsigned int max_expected;	/* Maximum number of concurrent 
+					 * expected connections */
+	unsigned int timeout;		/* timeout for expecteds */
+
+	/* Mask of things we will help (compared against server response) */
+	struct nf_conntrack_tuple tuple;
+	struct nf_conntrack_tuple mask;
+	
+	/* Function to call when data passes; return verdict, or -1 to
+           invalidate. */
+	int (*help)(struct sk_buff **pskb,
+		    unsigned int protoff,
+		    struct nf_conn *ct,
+		    enum ip_conntrack_info conntrackinfo);
+};
+
+extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
+extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
+
+/* Allocate space for an expectation: this is mandatory before calling
+   nf_conntrack_expect_related.  You will have to call put afterwards. */
+extern struct nf_conntrack_expect *
+nf_conntrack_expect_alloc(struct nf_conn *master);
+extern void nf_conntrack_expect_put(struct nf_conntrack_expect *exp);
+
+/* Add an expected connection: can have more than one per connection */
+extern int nf_conntrack_expect_related(struct nf_conntrack_expect *exp);
+extern void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp);
+
+#endif /*_NF_CONNTRACK_HELPER_H*/
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
new file mode 100644
index 0000000..01663e5
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C)2003,2004 USAGI/WIDE Project
+ *
+ * Header for use in defining a given L3 protocol for connection tracking.
+ *
+ * Author:
+ *	Yasuyuki Kozakai @USAGI	<yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Derived from include/netfilter_ipv4/ip_conntrack_protocol.h
+ */
+
+#ifndef _NF_CONNTRACK_L3PROTO_H
+#define _NF_CONNTRACK_L3PROTO_H
+#include <linux/seq_file.h>
+#include <net/netfilter/nf_conntrack.h>
+
+struct nf_conntrack_l3proto
+{
+	/* Next pointer. */
+	struct list_head list;
+
+	/* L3 Protocol Family number. ex) PF_INET */
+	u_int16_t l3proto;
+
+	/* Protocol name */
+	const char *name;
+
+	/*
+	 * Try to fill in the third arg: nhoff is offset of l3 proto
+         * hdr.  Return true if possible.
+	 */
+	int (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int nhoff,
+			    struct nf_conntrack_tuple *tuple);
+
+	/*
+	 * Invert the per-proto part of the tuple: ie. turn xmit into reply.
+	 * Some packets can't be inverted: return 0 in that case.
+	 */
+	int (*invert_tuple)(struct nf_conntrack_tuple *inverse,
+			    const struct nf_conntrack_tuple *orig);
+
+	/* Print out the per-protocol part of the tuple. */
+	int (*print_tuple)(struct seq_file *s,
+			   const struct nf_conntrack_tuple *);
+
+	/* Print out the private part of the conntrack. */
+	int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
+
+	/* Returns verdict for packet, or -1 for invalid. */
+	int (*packet)(struct nf_conn *conntrack,
+		      const struct sk_buff *skb,
+		      enum ip_conntrack_info ctinfo);
+
+	/*
+	 * Called when a new connection for this protocol found;
+	 * returns TRUE if it's OK.  If so, packet() called next.
+	 */
+	int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb);
+
+	/* Called when a conntrack entry is destroyed */
+	void (*destroy)(struct nf_conn *conntrack);
+
+	/*
+	 * Called before tracking. 
+	 *	*dataoff: offset of protocol header (TCP, UDP,...) in *pskb
+	 *	*protonum: protocol number
+	 */
+	int (*prepare)(struct sk_buff **pskb, unsigned int hooknum,
+		       unsigned int *dataoff, u_int8_t *protonum);
+
+	u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple);
+
+	/* Module (if any) which this is connected to. */
+	struct module *me;
+};
+
+extern struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX];
+
+/* Protocol registration. */
+extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
+extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
+
+static inline struct nf_conntrack_l3proto *
+nf_ct_find_l3proto(u_int16_t l3proto)
+{
+	return nf_ct_l3protos[l3proto];
+}
+
+/* Existing built-in protocols */
+extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
+extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
+extern struct nf_conntrack_l3proto nf_conntrack_generic_l3proto;
+#endif /*_NF_CONNTRACK_L3PROTO_H*/
diff --git a/include/net/netfilter/nf_conntrack_protocol.h b/include/net/netfilter/nf_conntrack_protocol.h
new file mode 100644
index 0000000..b3afda3
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_protocol.h
@@ -0,0 +1,105 @@
+/*
+ * Header for use in defining a given protocol for connection tracking.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- generalized L3 protocol dependent part.
+ *
+ * Derived from include/linux/netfiter_ipv4/ip_conntrack_protcol.h
+ */
+
+#ifndef _NF_CONNTRACK_PROTOCOL_H
+#define _NF_CONNTRACK_PROTOCOL_H
+#include <net/netfilter/nf_conntrack.h>
+
+struct seq_file;
+
+struct nf_conntrack_protocol
+{
+	/* Next pointer. */
+	struct list_head list;
+
+	/* L3 Protocol number. */
+	u_int16_t l3proto;
+
+	/* Protocol number. */
+	u_int8_t proto;
+
+	/* Protocol name */
+	const char *name;
+
+	/* Try to fill in the third arg: dataoff is offset past network protocol
+           hdr.  Return true if possible. */
+	int (*pkt_to_tuple)(const struct sk_buff *skb,
+			    unsigned int dataoff,
+			    struct nf_conntrack_tuple *tuple);
+
+	/* Invert the per-proto part of the tuple: ie. turn xmit into reply.
+	 * Some packets can't be inverted: return 0 in that case.
+	 */
+	int (*invert_tuple)(struct nf_conntrack_tuple *inverse,
+			    const struct nf_conntrack_tuple *orig);
+
+	/* Print out the per-protocol part of the tuple. Return like seq_* */
+	int (*print_tuple)(struct seq_file *s,
+			   const struct nf_conntrack_tuple *);
+
+	/* Print out the private part of the conntrack. */
+	int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
+
+	/* Returns verdict for packet, or -1 for invalid. */
+	int (*packet)(struct nf_conn *conntrack,
+		      const struct sk_buff *skb,
+		      unsigned int dataoff,
+		      enum ip_conntrack_info ctinfo,
+		      int pf,
+		      unsigned int hooknum);
+
+	/* Called when a new connection for this protocol found;
+	 * returns TRUE if it's OK.  If so, packet() called next. */
+	int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb,
+		   unsigned int dataoff);
+
+	/* Called when a conntrack entry is destroyed */
+	void (*destroy)(struct nf_conn *conntrack);
+
+	int (*error)(struct sk_buff *skb, unsigned int dataoff,
+		     enum ip_conntrack_info *ctinfo,
+		     int pf, unsigned int hooknum);
+
+	/* Module (if any) which this is connected to. */
+	struct module *me;
+};
+
+/* Existing built-in protocols */
+extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp6;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6;
+extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
+
+#define MAX_NF_CT_PROTO 256
+extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX];
+
+extern struct nf_conntrack_protocol *
+nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol);
+
+/* Protocol registration. */
+extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto);
+extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto);
+
+/* Log invalid packets */
+extern unsigned int nf_ct_log_invalid;
+
+#ifdef CONFIG_SYSCTL
+#ifdef DEBUG_INVALID_PACKETS
+#define LOG_INVALID(proto) \
+	(nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW)
+#else
+#define LOG_INVALID(proto) \
+	((nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW) \
+	 && net_ratelimit())
+#endif
+#else
+#define LOG_INVALID(proto) 0
+#endif /* CONFIG_SYSCTL */
+
+#endif /*_NF_CONNTRACK_PROTOCOL_H*/
diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h
new file mode 100644
index 0000000..14ce790
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_tuple.h
@@ -0,0 +1,190 @@
+/*
+ * Definitions and Declarations for tuple.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- generalize L3 protocol dependent part.
+ *
+ * Derived from include/linux/netfiter_ipv4/ip_conntrack_tuple.h
+ */
+
+#ifndef _NF_CONNTRACK_TUPLE_H
+#define _NF_CONNTRACK_TUPLE_H
+
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+
+/* A `tuple' is a structure containing the information to uniquely
+  identify a connection.  ie. if two packets have the same tuple, they
+  are in the same connection; if not, they are not.
+
+  We divide the structure along "manipulatable" and
+  "non-manipulatable" lines, for the benefit of the NAT code.
+*/
+
+#define NF_CT_TUPLE_L3SIZE	4
+
+/* The l3 protocol-specific manipulable parts of the tuple: always in
+   network order! */
+union nf_conntrack_man_l3proto {
+	u_int32_t all[NF_CT_TUPLE_L3SIZE];
+	u_int32_t ip;
+	u_int32_t ip6[4];
+};
+
+/* The protocol-specific manipulable parts of the tuple: always in
+   network order! */
+union nf_conntrack_man_proto
+{
+	/* Add other protocols here. */
+	u_int16_t all;
+
+	struct {
+		u_int16_t port;
+	} tcp;
+	struct {
+		u_int16_t port;
+	} udp;
+	struct {
+		u_int16_t id;
+	} icmp;
+	struct {
+		u_int16_t port;
+	} sctp;
+};
+
+/* The manipulable part of the tuple. */
+struct nf_conntrack_man
+{
+	union nf_conntrack_man_l3proto u3;
+	union nf_conntrack_man_proto u;
+	/* Layer 3 protocol */
+	u_int16_t l3num;
+};
+
+/* This contains the information to distinguish a connection. */
+struct nf_conntrack_tuple
+{
+	struct nf_conntrack_man src;
+
+	/* These are the parts of the tuple which are fixed. */
+	struct {
+		union {
+			u_int32_t all[NF_CT_TUPLE_L3SIZE];
+			u_int32_t ip;
+			u_int32_t ip6[4];
+		} u3;
+		union {
+			/* Add other protocols here. */
+			u_int16_t all;
+
+			struct {
+				u_int16_t port;
+			} tcp;
+			struct {
+				u_int16_t port;
+			} udp;
+			struct {
+				u_int8_t type, code;
+			} icmp;
+			struct {
+				u_int16_t port;
+			} sctp;
+		} u;
+
+		/* The protocol. */
+		u_int8_t protonum;
+
+		/* The direction (for tuplehash) */
+		u_int8_t dir;
+	} dst;
+};
+
+/* This is optimized opposed to a memset of the whole structure.  Everything we
+ * really care about is the  source/destination unions */
+#define NF_CT_TUPLE_U_BLANK(tuple)                              	\
+        do {                                                    	\
+                (tuple)->src.u.all = 0;                         	\
+                (tuple)->dst.u.all = 0;                         	\
+		memset(&(tuple)->src.u3, 0, sizeof((tuple)->src.u3));	\
+		memset(&(tuple)->dst.u3, 0, sizeof((tuple)->dst.u3));	\
+        } while (0)
+
+#ifdef __KERNEL__
+
+#define NF_CT_DUMP_TUPLE(tp)						    \
+DEBUGP("tuple %p: %u %u %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu -> %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu\n",					    \
+	(tp), (tp)->src.l3num, (tp)->dst.protonum,			    \
+	NIP6(*(struct in6_addr *)(tp)->src.u3.all), ntohs((tp)->src.u.all), \
+	NIP6(*(struct in6_addr *)(tp)->dst.u3.all), ntohs((tp)->dst.u.all))
+
+/* If we're the first tuple, it's the original dir. */
+#define NF_CT_DIRECTION(h)						\
+	((enum ip_conntrack_dir)(h)->tuple.dst.dir)
+
+/* Connections have two entries in the hash table: one for each way */
+struct nf_conntrack_tuple_hash
+{
+	struct list_head list;
+
+	struct nf_conntrack_tuple tuple;
+};
+
+#endif /* __KERNEL__ */
+
+static inline int nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1,
+				        const struct nf_conntrack_tuple *t2)
+{ 
+	return (t1->src.u3.all[0] == t2->src.u3.all[0] &&
+		t1->src.u3.all[1] == t2->src.u3.all[1] &&
+		t1->src.u3.all[2] == t2->src.u3.all[2] &&
+		t1->src.u3.all[3] == t2->src.u3.all[3] &&
+		t1->src.u.all == t2->src.u.all &&
+		t1->src.l3num == t2->src.l3num &&
+		t1->dst.protonum == t2->dst.protonum);
+}
+
+static inline int nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1,
+				        const struct nf_conntrack_tuple *t2)
+{
+	return (t1->dst.u3.all[0] == t2->dst.u3.all[0] &&
+		t1->dst.u3.all[1] == t2->dst.u3.all[1] &&
+		t1->dst.u3.all[2] == t2->dst.u3.all[2] &&
+		t1->dst.u3.all[3] == t2->dst.u3.all[3] &&
+		t1->dst.u.all == t2->dst.u.all &&
+		t1->src.l3num == t2->src.l3num &&
+		t1->dst.protonum == t2->dst.protonum);
+}
+
+static inline int nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1,
+				    const struct nf_conntrack_tuple *t2)
+{
+	return nf_ct_tuple_src_equal(t1, t2) && nf_ct_tuple_dst_equal(t1, t2);
+}
+
+static inline int nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t,
+				       const struct nf_conntrack_tuple *tuple,
+				       const struct nf_conntrack_tuple *mask)
+{
+	int count = 0;
+
+        for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
+                if ((t->src.u3.all[count] ^ tuple->src.u3.all[count]) &
+                    mask->src.u3.all[count])
+                        return 0;
+        }
+
+        for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
+                if ((t->dst.u3.all[count] ^ tuple->dst.u3.all[count]) &
+                    mask->dst.u3.all[count])
+                        return 0;
+        }
+
+        if ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all ||
+            (t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all ||
+            (t->src.l3num ^ tuple->src.l3num) & mask->src.l3num ||
+            (t->dst.protonum ^ tuple->dst.protonum) & mask->dst.protonum)
+                return 0;
+
+        return 1;
+}
+
+#endif /* _NF_CONNTRACK_TUPLE_H */
diff --git a/include/net/netlink.h b/include/net/netlink.h
new file mode 100644
index 0000000..640c26a
--- /dev/null
+++ b/include/net/netlink.h
@@ -0,0 +1,883 @@
+#ifndef __NET_NETLINK_H
+#define __NET_NETLINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+/* ========================================================================
+ *         Netlink Messages and Attributes Interface (As Seen On TV)
+ * ------------------------------------------------------------------------
+ *                          Messages Interface
+ * ------------------------------------------------------------------------
+ *
+ * Message Format:
+ *    <--- nlmsg_total_size(payload)  --->
+ *    <-- nlmsg_msg_size(payload) ->
+ *   +----------+- - -+-------------+- - -+-------- - -
+ *   | nlmsghdr | Pad |   Payload   | Pad | nlmsghdr
+ *   +----------+- - -+-------------+- - -+-------- - -
+ *   nlmsg_data(nlh)---^                   ^
+ *   nlmsg_next(nlh)-----------------------+
+ *
+ * Payload Format:
+ *    <---------------------- nlmsg_len(nlh) --------------------->
+ *    <------ hdrlen ------>       <- nlmsg_attrlen(nlh, hdrlen) ->
+ *   +----------------------+- - -+--------------------------------+
+ *   |     Family Header    | Pad |           Attributes           |
+ *   +----------------------+- - -+--------------------------------+
+ *   nlmsg_attrdata(nlh, hdrlen)---^
+ *
+ * Data Structures:
+ *   struct nlmsghdr			netlink message header
+ *
+ * Message Construction:
+ *   nlmsg_new()			create a new netlink message
+ *   nlmsg_put()			add a netlink message to an skb
+ *   nlmsg_put_answer()			callback based nlmsg_put()
+ *   nlmsg_end()			finanlize netlink message
+ *   nlmsg_cancel()			cancel message construction
+ *   nlmsg_free()			free a netlink message
+ *
+ * Message Sending:
+ *   nlmsg_multicast()			multicast message to several groups
+ *   nlmsg_unicast()			unicast a message to a single socket
+ *
+ * Message Length Calculations:
+ *   nlmsg_msg_size(payload)		length of message w/o padding
+ *   nlmsg_total_size(payload)		length of message w/ padding
+ *   nlmsg_padlen(payload)		length of padding at tail
+ *
+ * Message Payload Access:
+ *   nlmsg_data(nlh)			head of message payload
+ *   nlmsg_len(nlh)			length of message payload
+ *   nlmsg_attrdata(nlh, hdrlen)	head of attributes data
+ *   nlmsg_attrlen(nlh, hdrlen)		length of attributes data
+ *
+ * Message Parsing:
+ *   nlmsg_ok(nlh, remaining)		does nlh fit into remaining bytes?
+ *   nlmsg_next(nlh, remaining)		get next netlink message
+ *   nlmsg_parse()			parse attributes of a message
+ *   nlmsg_find_attr()			find an attribute in a message
+ *   nlmsg_for_each_msg()		loop over all messages
+ *   nlmsg_validate()			validate netlink message incl. attrs
+ *   nlmsg_for_each_attr()		loop over all attributes
+ *
+ * ------------------------------------------------------------------------
+ *                          Attributes Interface
+ * ------------------------------------------------------------------------
+ *
+ * Attribute Format:
+ *    <------- nla_total_size(payload) ------->
+ *    <---- nla_attr_size(payload) ----->
+ *   +----------+- - -+- - - - - - - - - +- - -+-------- - -
+ *   |  Header  | Pad |     Payload      | Pad |  Header
+ *   +----------+- - -+- - - - - - - - - +- - -+-------- - -
+ *                     <- nla_len(nla) ->      ^
+ *   nla_data(nla)----^                        |
+ *   nla_next(nla)-----------------------------'
+ *
+ * Data Structures:
+ *   struct nlattr			netlink attribtue header
+ *
+ * Attribute Construction:
+ *   nla_reserve(skb, type, len)	reserve skb tailroom for an attribute
+ *   nla_put(skb, type, len, data)	add attribute to skb
+ *
+ * Attribute Construction for Basic Types:
+ *   nla_put_u8(skb, type, value)	add u8 attribute to skb
+ *   nla_put_u16(skb, type, value)	add u16 attribute to skb
+ *   nla_put_u32(skb, type, value)	add u32 attribute to skb
+ *   nla_put_u64(skb, type, value)	add u64 attribute to skb
+ *   nla_put_string(skb, type, str)	add string attribute to skb
+ *   nla_put_flag(skb, type)		add flag attribute to skb
+ *   nla_put_msecs(skb, type, jiffies)	add msecs attribute to skb
+ *
+ * Exceptions Based Attribute Construction:
+ *   NLA_PUT(skb, type, len, data)	add attribute to skb
+ *   NLA_PUT_U8(skb, type, value)	add u8 attribute to skb
+ *   NLA_PUT_U16(skb, type, value)	add u16 attribute to skb
+ *   NLA_PUT_U32(skb, type, value)	add u32 attribute to skb
+ *   NLA_PUT_U64(skb, type, value)	add u64 attribute to skb
+ *   NLA_PUT_STRING(skb, type, str)	add string attribute to skb
+ *   NLA_PUT_FLAG(skb, type)		add flag attribute to skb
+ *   NLA_PUT_MSECS(skb, type, jiffies)	add msecs attribute to skb
+ *
+ *   The meaning of these functions is equal to their lower case
+ *   variants but they jump to the label nla_put_failure in case
+ *   of a failure.
+ *
+ * Nested Attributes Construction:
+ *   nla_nest_start(skb, type)		start a nested attribute
+ *   nla_nest_end(skb, nla)		finalize a nested attribute
+ *   nla_nest_cancel(skb, nla)		cancel nested attribute construction
+ *
+ * Attribute Length Calculations:
+ *   nla_attr_size(payload)		length of attribute w/o padding
+ *   nla_total_size(payload)		length of attribute w/ padding
+ *   nla_padlen(payload)		length of padding
+ *
+ * Attribute Payload Access:
+ *   nla_data(nla)			head of attribute payload
+ *   nla_len(nla)			length of attribute payload
+ *
+ * Attribute Payload Access for Basic Types:
+ *   nla_get_u8(nla)			get payload for a u8 attribute
+ *   nla_get_u16(nla)			get payload for a u16 attribute
+ *   nla_get_u32(nla)			get payload for a u32 attribute
+ *   nla_get_u64(nla)			get payload for a u64 attribute
+ *   nla_get_flag(nla)			return 1 if flag is true
+ *   nla_get_msecs(nla)			get payload for a msecs attribute
+ *
+ * Attribute Misc:
+ *   nla_memcpy(dest, nla, count)	copy attribute into memory
+ *   nla_memcmp(nla, data, size)	compare attribute with memory area
+ *   nla_strlcpy(dst, nla, size)	copy attribute to a sized string
+ *   nla_strcmp(nla, str)		compare attribute with string
+ *
+ * Attribute Parsing:
+ *   nla_ok(nla, remaining)		does nla fit into remaining bytes?
+ *   nla_next(nla, remaining)		get next netlink attribute
+ *   nla_validate()			validate a stream of attributes
+ *   nla_find()				find attribute in stream of attributes
+ *   nla_parse()			parse and validate stream of attrs
+ *   nla_parse_nested()			parse nested attribuets
+ *   nla_for_each_attr()		loop over all attributes
+ *=========================================================================
+ */
+
+ /**
+  * Standard attribute types to specify validation policy
+  */
+enum {
+	NLA_UNSPEC,
+	NLA_U8,
+	NLA_U16,
+	NLA_U32,
+	NLA_U64,
+	NLA_STRING,
+	NLA_FLAG,
+	NLA_MSECS,
+	NLA_NESTED,
+	__NLA_TYPE_MAX,
+};
+
+#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
+
+/**
+ * struct nla_policy - attribute validation policy
+ * @type: Type of attribute or NLA_UNSPEC
+ * @minlen: Minimal length of payload required to be available
+ *
+ * Policies are defined as arrays of this struct, the array must be
+ * accessible by attribute type up to the highest identifier to be expected.
+ *
+ * Example:
+ * static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = {
+ * 	[ATTR_FOO] = { .type = NLA_U16 },
+ *	[ATTR_BAR] = { .type = NLA_STRING },
+ *	[ATTR_BAZ] = { .minlen = sizeof(struct mystruct) },
+ * };
+ */
+struct nla_policy {
+	u16		type;
+	u16		minlen;
+};
+
+extern void		netlink_run_queue(struct sock *sk, unsigned int *qlen,
+					  int (*cb)(struct sk_buff *,
+						    struct nlmsghdr *, int *));
+extern void		netlink_queue_skip(struct nlmsghdr *nlh,
+					   struct sk_buff *skb);
+
+extern int		nla_validate(struct nlattr *head, int len, int maxtype,
+				     struct nla_policy *policy);
+extern int		nla_parse(struct nlattr *tb[], int maxtype,
+				  struct nlattr *head, int len,
+				  struct nla_policy *policy);
+extern struct nlattr *	nla_find(struct nlattr *head, int len, int attrtype);
+extern size_t		nla_strlcpy(char *dst, const struct nlattr *nla,
+				    size_t dstsize);
+extern int		nla_memcpy(void *dest, struct nlattr *src, int count);
+extern int		nla_memcmp(const struct nlattr *nla, const void *data,
+				   size_t size);
+extern int		nla_strcmp(const struct nlattr *nla, const char *str);
+extern struct nlattr *	__nla_reserve(struct sk_buff *skb, int attrtype,
+				      int attrlen);
+extern struct nlattr *	nla_reserve(struct sk_buff *skb, int attrtype,
+				    int attrlen);
+extern void		__nla_put(struct sk_buff *skb, int attrtype,
+				  int attrlen, const void *data);
+extern int		nla_put(struct sk_buff *skb, int attrtype,
+				int attrlen, const void *data);
+
+/**************************************************************************
+ * Netlink Messages
+ **************************************************************************/
+
+/**
+ * nlmsg_msg_size - length of netlink message not including padding
+ * @payload: length of message payload
+ */
+static inline int nlmsg_msg_size(int payload)
+{
+	return NLMSG_HDRLEN + payload;
+}
+
+/**
+ * nlmsg_total_size - length of netlink message including padding
+ * @payload: length of message payload
+ */
+static inline int nlmsg_total_size(int payload)
+{
+	return NLMSG_ALIGN(nlmsg_msg_size(payload));
+}
+
+/**
+ * nlmsg_padlen - length of padding at the message's tail
+ * @payload: length of message payload
+ */
+static inline int nlmsg_padlen(int payload)
+{
+	return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
+}
+
+/**
+ * nlmsg_data - head of message payload
+ * @nlh: netlink messsage header
+ */
+static inline void *nlmsg_data(const struct nlmsghdr *nlh)
+{
+	return (unsigned char *) nlh + NLMSG_HDRLEN;
+}
+
+/**
+ * nlmsg_len - length of message payload
+ * @nlh: netlink message header
+ */
+static inline int nlmsg_len(const struct nlmsghdr *nlh)
+{
+	return nlh->nlmsg_len - NLMSG_HDRLEN;
+}
+
+/**
+ * nlmsg_attrdata - head of attributes data
+ * @nlh: netlink message header
+ * @hdrlen: length of family specific header
+ */
+static inline struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh,
+					    int hdrlen)
+{
+	unsigned char *data = nlmsg_data(nlh);
+	return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
+}
+
+/**
+ * nlmsg_attrlen - length of attributes data
+ * @nlh: netlink message header
+ * @hdrlen: length of family specific header
+ */
+static inline int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
+{
+	return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
+}
+
+/**
+ * nlmsg_ok - check if the netlink message fits into the remaining bytes
+ * @nlh: netlink message header
+ * @remaining: number of bytes remaining in message stream
+ */
+static inline int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
+{
+	return (remaining >= sizeof(struct nlmsghdr) &&
+		nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
+		nlh->nlmsg_len <= remaining);
+}
+
+/**
+ * nlmsg_next - next netlink message in message stream
+ * @nlh: netlink message header
+ * @remaining: number of bytes remaining in message stream
+ *
+ * Returns the next netlink message in the message stream and
+ * decrements remaining by the size of the current message.
+ */
+static inline struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
+{
+	int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
+
+	*remaining -= totlen;
+
+	return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
+}
+
+/**
+ * nlmsg_parse - parse attributes of a netlink message
+ * @nlh: netlink message header
+ * @hdrlen: length of family specific header
+ * @tb: destination array with maxtype+1 elements
+ * @maxtype: maximum attribute type to be expected
+ * @policy: validation policy
+ *
+ * See nla_parse()
+ */
+static inline int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen,
+			      struct nlattr *tb[], int maxtype,
+			      struct nla_policy *policy)
+{
+	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
+		return -EINVAL;
+
+	return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
+			 nlmsg_attrlen(nlh, hdrlen), policy);
+}
+
+/**
+ * nlmsg_find_attr - find a specific attribute in a netlink message
+ * @nlh: netlink message header
+ * @hdrlen: length of familiy specific header
+ * @attrtype: type of attribute to look for
+ *
+ * Returns the first attribute which matches the specified type.
+ */
+static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh,
+					     int hdrlen, int attrtype)
+{
+	return nla_find(nlmsg_attrdata(nlh, hdrlen),
+			nlmsg_attrlen(nlh, hdrlen), attrtype);
+}
+
+/**
+ * nlmsg_validate - validate a netlink message including attributes
+ * @nlh: netlinket message header
+ * @hdrlen: length of familiy specific header
+ * @maxtype: maximum attribute type to be expected
+ * @policy: validation policy
+ */
+static inline int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
+				 struct nla_policy *policy)
+{
+	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
+		return -EINVAL;
+
+	return nla_validate(nlmsg_attrdata(nlh, hdrlen),
+			    nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
+}
+
+/**
+ * nlmsg_for_each_attr - iterate over a stream of attributes
+ * @pos: loop counter, set to current attribute
+ * @nlh: netlink message header
+ * @hdrlen: length of familiy specific header
+ * @rem: initialized to len, holds bytes currently remaining in stream
+ */
+#define nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \
+	nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \
+			  nlmsg_attrlen(nlh, hdrlen), rem)
+
+#if 0
+/* FIXME: Enable once all users have been converted */
+
+/**
+ * __nlmsg_put - Add a new netlink message to an skb
+ * @skb: socket buffer to store message in
+ * @pid: netlink process id
+ * @seq: sequence number of message
+ * @type: message type
+ * @payload: length of message payload
+ * @flags: message flags
+ *
+ * The caller is responsible to ensure that the skb provides enough
+ * tailroom for both the netlink header and payload.
+ */
+static inline struct nlmsghdr *__nlmsg_put(struct sk_buff *skb, u32 pid,
+					   u32 seq, int type, int payload,
+					   int flags)
+{
+	struct nlmsghdr *nlh;
+
+	nlh = (struct nlmsghdr *) skb_put(skb, nlmsg_total_size(payload));
+	nlh->nlmsg_type = type;
+	nlh->nlmsg_len = nlmsg_msg_size(payload);
+	nlh->nlmsg_flags = flags;
+	nlh->nlmsg_pid = pid;
+	nlh->nlmsg_seq = seq;
+
+	memset((unsigned char *) nlmsg_data(nlh) + payload, 0,
+	       nlmsg_padlen(payload));
+
+	return nlh;
+}
+#endif
+
+/**
+ * nlmsg_put - Add a new netlink message to an skb
+ * @skb: socket buffer to store message in
+ * @pid: netlink process id
+ * @seq: sequence number of message
+ * @type: message type
+ * @payload: length of message payload
+ * @flags: message flags
+ *
+ * Returns NULL if the tailroom of the skb is insufficient to store
+ * the message header and payload.
+ */
+static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq,
+					 int type, int payload, int flags)
+{
+	if (unlikely(skb_tailroom(skb) < nlmsg_total_size(payload)))
+		return NULL;
+
+	return __nlmsg_put(skb, pid, seq, type, payload, flags);
+}
+
+/**
+ * nlmsg_put_answer - Add a new callback based netlink message to an skb
+ * @skb: socket buffer to store message in
+ * @cb: netlink callback
+ * @type: message type
+ * @payload: length of message payload
+ * @flags: message flags
+ *
+ * Returns NULL if the tailroom of the skb is insufficient to store
+ * the message header and payload.
+ */
+static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb,
+						struct netlink_callback *cb,
+						int type, int payload,
+						int flags)
+{
+	return nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+			 type, payload, flags);
+}
+
+/**
+ * nlmsg_new - Allocate a new netlink message
+ * @size: maximum size of message
+ *
+ * Use NLMSG_GOODSIZE if size isn't know and you need a good default size.
+ */
+static inline struct sk_buff *nlmsg_new(int size)
+{
+	return alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+}
+
+/**
+ * nlmsg_end - Finalize a netlink message
+ * @skb: socket buffer the message is stored in
+ * @nlh: netlink message header
+ *
+ * Corrects the netlink message header to include the appeneded
+ * attributes. Only necessary if attributes have been added to
+ * the message.
+ *
+ * Returns the total data length of the skb.
+ */
+static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	nlh->nlmsg_len = skb->tail - (unsigned char *) nlh;
+
+	return skb->len;
+}
+
+/**
+ * nlmsg_cancel - Cancel construction of a netlink message
+ * @skb: socket buffer the message is stored in
+ * @nlh: netlink message header
+ *
+ * Removes the complete netlink message including all
+ * attributes from the socket buffer again. Returns -1.
+ */
+static inline int nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	skb_trim(skb, (unsigned char *) nlh - skb->data);
+
+	return -1;
+}
+
+/**
+ * nlmsg_free - free a netlink message
+ * @skb: socket buffer of netlink message
+ */
+static inline void nlmsg_free(struct sk_buff *skb)
+{
+	kfree_skb(skb);
+}
+
+/**
+ * nlmsg_multicast - multicast a netlink message
+ * @sk: netlink socket to spread messages to
+ * @skb: netlink message as socket buffer
+ * @pid: own netlink pid to avoid sending to yourself
+ * @group: multicast group id
+ */
+static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb,
+				  u32 pid, unsigned int group)
+{
+	int err;
+
+	NETLINK_CB(skb).dst_group = group;
+
+	err = netlink_broadcast(sk, skb, pid, group, GFP_KERNEL);
+	if (err > 0)
+		err = 0;
+
+	return err;
+}
+
+/**
+ * nlmsg_unicast - unicast a netlink message
+ * @sk: netlink socket to spread message to
+ * @skb: netlink message as socket buffer
+ * @pid: netlink pid of the destination socket
+ */
+static inline int nlmsg_unicast(struct sock *sk, struct sk_buff *skb, u32 pid)
+{
+	int err;
+
+	err = netlink_unicast(sk, skb, pid, MSG_DONTWAIT);
+	if (err > 0)
+		err = 0;
+
+	return err;
+}
+
+/**
+ * nlmsg_for_each_msg - iterate over a stream of messages
+ * @pos: loop counter, set to current message
+ * @head: head of message stream
+ * @len: length of message stream
+ * @rem: initialized to len, holds bytes currently remaining in stream
+ */
+#define nlmsg_for_each_msg(pos, head, len, rem) \
+	for (pos = head, rem = len; \
+	     nlmsg_ok(pos, rem); \
+	     pos = nlmsg_next(pos, &(rem)))
+
+/**************************************************************************
+ * Netlink Attributes
+ **************************************************************************/
+
+/**
+ * nla_attr_size - length of attribute not including padding
+ * @payload: length of payload
+ */
+static inline int nla_attr_size(int payload)
+{
+	return NLA_HDRLEN + payload;
+}
+
+/**
+ * nla_total_size - total length of attribute including padding
+ * @payload: length of payload
+ */
+static inline int nla_total_size(int payload)
+{
+	return NLA_ALIGN(nla_attr_size(payload));
+}
+
+/**
+ * nla_padlen - length of padding at the tail of attribute
+ * @payload: length of payload
+ */
+static inline int nla_padlen(int payload)
+{
+	return nla_total_size(payload) - nla_attr_size(payload);
+}
+
+/**
+ * nla_data - head of payload
+ * @nla: netlink attribute
+ */
+static inline void *nla_data(const struct nlattr *nla)
+{
+	return (char *) nla + NLA_HDRLEN;
+}
+
+/**
+ * nla_len - length of payload
+ * @nla: netlink attribute
+ */
+static inline int nla_len(const struct nlattr *nla)
+{
+	return nla->nla_len - NLA_HDRLEN;
+}
+
+/**
+ * nla_ok - check if the netlink attribute fits into the remaining bytes
+ * @nla: netlink attribute
+ * @remaining: number of bytes remaining in attribute stream
+ */
+static inline int nla_ok(const struct nlattr *nla, int remaining)
+{
+	return remaining >= sizeof(*nla) &&
+	       nla->nla_len >= sizeof(*nla) &&
+	       nla->nla_len <= remaining;
+}
+
+/**
+ * nla_next - next netlink attribte in attribute stream
+ * @nla: netlink attribute
+ * @remaining: number of bytes remaining in attribute stream
+ *
+ * Returns the next netlink attribute in the attribute stream and
+ * decrements remaining by the size of the current attribute.
+ */
+static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
+{
+	int totlen = NLA_ALIGN(nla->nla_len);
+
+	*remaining -= totlen;
+	return (struct nlattr *) ((char *) nla + totlen);
+}
+
+/**
+ * nla_parse_nested - parse nested attributes
+ * @tb: destination array with maxtype+1 elements
+ * @maxtype: maximum attribute type to be expected
+ * @nla: attribute containing the nested attributes
+ * @policy: validation policy
+ *
+ * See nla_parse()
+ */
+static inline int nla_parse_nested(struct nlattr *tb[], int maxtype,
+				   struct nlattr *nla,
+				   struct nla_policy *policy)
+{
+	return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
+}
+/**
+ * nla_put_u8 - Add a u16 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_u8(struct sk_buff *skb, int attrtype, u8 value)
+{
+	return nla_put(skb, attrtype, sizeof(u8), &value);
+}
+
+/**
+ * nla_put_u16 - Add a u16 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_u16(struct sk_buff *skb, int attrtype, u16 value)
+{
+	return nla_put(skb, attrtype, sizeof(u16), &value);
+}
+
+/**
+ * nla_put_u32 - Add a u32 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_u32(struct sk_buff *skb, int attrtype, u32 value)
+{
+	return nla_put(skb, attrtype, sizeof(u32), &value);
+}
+
+/**
+ * nla_put_64 - Add a u64 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_u64(struct sk_buff *skb, int attrtype, u64 value)
+{
+	return nla_put(skb, attrtype, sizeof(u64), &value);
+}
+
+/**
+ * nla_put_string - Add a string netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @str: NUL terminated string
+ */
+static inline int nla_put_string(struct sk_buff *skb, int attrtype,
+				 const char *str)
+{
+	return nla_put(skb, attrtype, strlen(str) + 1, str);
+}
+
+/**
+ * nla_put_flag - Add a flag netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ */
+static inline int nla_put_flag(struct sk_buff *skb, int attrtype)
+{
+	return nla_put(skb, attrtype, 0, NULL);
+}
+
+/**
+ * nla_put_msecs - Add a msecs netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @jiffies: number of msecs in jiffies
+ */
+static inline int nla_put_msecs(struct sk_buff *skb, int attrtype,
+				unsigned long jiffies)
+{
+	u64 tmp = jiffies_to_msecs(jiffies);
+	return nla_put(skb, attrtype, sizeof(u64), &tmp);
+}
+
+#define NLA_PUT(skb, attrtype, attrlen, data) \
+	do { \
+		if (nla_put(skb, attrtype, attrlen, data) < 0) \
+			goto nla_put_failure; \
+	} while(0)
+
+#define NLA_PUT_TYPE(skb, type, attrtype, value) \
+	do { \
+		type __tmp = value; \
+		NLA_PUT(skb, attrtype, sizeof(type), &__tmp); \
+	} while(0)
+
+#define NLA_PUT_U8(skb, attrtype, value) \
+	NLA_PUT_TYPE(skb, u8, attrtype, value)
+
+#define NLA_PUT_U16(skb, attrtype, value) \
+	NLA_PUT_TYPE(skb, u16, attrtype, value)
+
+#define NLA_PUT_U32(skb, attrtype, value) \
+	NLA_PUT_TYPE(skb, u32, attrtype, value)
+
+#define NLA_PUT_U64(skb, attrtype, value) \
+	NLA_PUT_TYPE(skb, u64, attrtype, value)
+
+#define NLA_PUT_STRING(skb, attrtype, value) \
+	NLA_PUT(skb, attrtype, strlen(value) + 1, value)
+
+#define NLA_PUT_FLAG(skb, attrtype, value) \
+	NLA_PUT(skb, attrtype, 0, NULL)
+
+#define NLA_PUT_MSECS(skb, attrtype, jiffies) \
+	NLA_PUT_U64(skb, attrtype, jiffies_to_msecs(jiffies))
+
+/**
+ * nla_get_u32 - return payload of u32 attribute
+ * @nla: u32 netlink attribute
+ */
+static inline u32 nla_get_u32(struct nlattr *nla)
+{
+	return *(u32 *) nla_data(nla);
+}
+
+/**
+ * nla_get_u16 - return payload of u16 attribute
+ * @nla: u16 netlink attribute
+ */
+static inline u16 nla_get_u16(struct nlattr *nla)
+{
+	return *(u16 *) nla_data(nla);
+}
+
+/**
+ * nla_get_u8 - return payload of u8 attribute
+ * @nla: u8 netlink attribute
+ */
+static inline u8 nla_get_u8(struct nlattr *nla)
+{
+	return *(u8 *) nla_data(nla);
+}
+
+/**
+ * nla_get_u64 - return payload of u64 attribute
+ * @nla: u64 netlink attribute
+ */
+static inline u64 nla_get_u64(struct nlattr *nla)
+{
+	u64 tmp;
+
+	nla_memcpy(&tmp, nla, sizeof(tmp));
+
+	return tmp;
+}
+
+/**
+ * nla_get_flag - return payload of flag attribute
+ * @nla: flag netlink attribute
+ */
+static inline int nla_get_flag(struct nlattr *nla)
+{
+	return !!nla;
+}
+
+/**
+ * nla_get_msecs - return payload of msecs attribute
+ * @nla: msecs netlink attribute
+ *
+ * Returns the number of milliseconds in jiffies.
+ */
+static inline unsigned long nla_get_msecs(struct nlattr *nla)
+{
+	u64 msecs = nla_get_u64(nla);
+
+	return msecs_to_jiffies((unsigned long) msecs);
+}
+
+/**
+ * nla_nest_start - Start a new level of nested attributes
+ * @skb: socket buffer to add attributes to
+ * @attrtype: attribute type of container
+ *
+ * Returns the container attribute
+ */
+static inline struct nlattr *nla_nest_start(struct sk_buff *skb, int attrtype)
+{
+	struct nlattr *start = (struct nlattr *) skb->tail;
+
+	if (nla_put(skb, attrtype, 0, NULL) < 0)
+		return NULL;
+
+	return start;
+}
+
+/**
+ * nla_nest_end - Finalize nesting of attributes
+ * @skb: socket buffer the attribtues are stored in
+ * @start: container attribute
+ *
+ * Corrects the container attribute header to include the all
+ * appeneded attributes.
+ *
+ * Returns the total data length of the skb.
+ */
+static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start)
+{
+	start->nla_len = skb->tail - (unsigned char *) start;
+	return skb->len;
+}
+
+/**
+ * nla_nest_cancel - Cancel nesting of attributes
+ * @skb: socket buffer the message is stored in
+ * @start: container attribute
+ *
+ * Removes the container attribute and including all nested
+ * attributes. Returns -1.
+ */
+static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start)
+{
+	if (start)
+		skb_trim(skb, (unsigned char *) start - skb->data);
+
+	return -1;
+}
+
+/**
+ * nla_for_each_attr - iterate over a stream of attributes
+ * @pos: loop counter, set to current attribute
+ * @head: head of attribute stream
+ * @len: length of attribute stream
+ * @rem: initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_attr(pos, head, len, rem) \
+	for (pos = head, rem = len; \
+	     nla_ok(pos, rem); \
+	     pos = nla_next(pos, &(rem)))
+
+#endif
diff --git a/include/net/sock.h b/include/net/sock.h
index e0498bd..982b4ec 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -461,16 +461,16 @@
 }
 
 /* The per-socket spinlock must be held here. */
-#define sk_add_backlog(__sk, __skb)				\
-do {	if (!(__sk)->sk_backlog.tail) {				\
-		(__sk)->sk_backlog.head =			\
-		     (__sk)->sk_backlog.tail = (__skb);		\
-	} else {						\
-		((__sk)->sk_backlog.tail)->next = (__skb);	\
-		(__sk)->sk_backlog.tail = (__skb);		\
-	}							\
-	(__skb)->next = NULL;					\
-} while(0)
+static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb)
+{
+	if (!sk->sk_backlog.tail) {
+		sk->sk_backlog.head = sk->sk_backlog.tail = skb;
+	} else {
+		sk->sk_backlog.tail->next = skb;
+		sk->sk_backlog.tail = skb;
+	}
+	skb->next = NULL;
+}
 
 #define sk_wait_event(__sk, __timeo, __condition)		\
 ({	int rc;							\
@@ -1247,6 +1247,12 @@
 		     (skb != (struct sk_buff *)&(sk)->sk_write_queue);	\
 		     skb = skb->next)
 
+/*from STCP for fast SACK Process*/
+#define sk_stream_for_retrans_queue_from(skb, sk)			\
+		for (; (skb != (sk)->sk_send_head) &&                   \
+		     (skb != (struct sk_buff *)&(sk)->sk_write_queue);	\
+		     skb = skb->next)
+
 /*
  *	Default write policy as shown to user space via poll/select/SIGIO
  */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index c24339c..0f98480 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/cache.h>
 #include <linux/percpu.h>
+#include <linux/skbuff.h>
 
 #include <net/inet_connection_sock.h>
 #include <net/inet_timewait_sock.h>
@@ -88,10 +89,10 @@
 				 */
 
 #define TCP_SYN_RETRIES	 5	/* number of times to retry active opening a
-				 * connection: ~180sec is RFC minumum	*/
+				 * connection: ~180sec is RFC minimum	*/
 
 #define TCP_SYNACK_RETRIES 5	/* number of times to retry passive opening a
-				 * connection: ~180sec is RFC minumum	*/
+				 * connection: ~180sec is RFC minimum	*/
 
 
 #define TCP_ORPHAN_RETRIES 7	/* number of times to retry on an orphaned
@@ -179,7 +180,7 @@
 /* Flags in tp->nonagle */
 #define TCP_NAGLE_OFF		1	/* Nagle's algo is disabled */
 #define TCP_NAGLE_CORK		2	/* Socket is corked	    */
-#define TCP_NAGLE_PUSH		4	/* Cork is overriden for already queued data */
+#define TCP_NAGLE_PUSH		4	/* Cork is overridden for already queued data */
 
 extern struct inet_timewait_death_row tcp_death_row;
 
@@ -217,6 +218,7 @@
 extern int sysctl_tcp_nometrics_save;
 extern int sysctl_tcp_moderate_rcvbuf;
 extern int sysctl_tcp_tso_win_divisor;
+extern int sysctl_tcp_abc;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -550,13 +552,13 @@
 
 /* TCP timestamps are only 32-bits, this causes a slight
  * complication on 64-bit systems since we store a snapshot
- * of jiffies in the buffer control blocks below.  We decidely
+ * of jiffies in the buffer control blocks below.  We decidedly
  * only use of the low 32-bits of jiffies and hide the ugly
  * casts with the following macro.
  */
 #define tcp_time_stamp		((__u32)(jiffies))
 
-/* This is what the send packet queueing engine uses to pass
+/* This is what the send packet queuing engine uses to pass
  * TCP per-packet control information to the transmission
  * code.  We also store the host-order sequence numbers in
  * here too.  This is 36 bytes on 32-bit architectures,
@@ -596,7 +598,7 @@
 #define TCPCB_EVER_RETRANS	0x80	/* Ever retransmitted frame	*/
 #define TCPCB_RETRANS		(TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS)
 
-#define TCPCB_URG		0x20	/* Urgent pointer advenced here	*/
+#define TCPCB_URG		0x20	/* Urgent pointer advanced here	*/
 
 #define TCPCB_AT_TAIL		(TCPCB_URG)
 
@@ -764,6 +766,33 @@
 			    (tp->snd_cwnd >> 2)));
 }
 
+/*
+ * Linear increase during slow start
+ */
+static inline void tcp_slow_start(struct tcp_sock *tp)
+{
+	if (sysctl_tcp_abc) {
+		/* RFC3465: Slow Start
+		 * TCP sender SHOULD increase cwnd by the number of
+		 * previously unacknowledged bytes ACKed by each incoming
+		 * acknowledgment, provided the increase is not more than L
+		 */
+		if (tp->bytes_acked < tp->mss_cache)
+			return;
+
+		/* We MAY increase by 2 if discovered delayed ack */
+		if (sysctl_tcp_abc > 1 && tp->bytes_acked > 2*tp->mss_cache) {
+			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+				tp->snd_cwnd++;
+		}
+	}
+	tp->bytes_acked = 0;
+
+	if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+		tp->snd_cwnd++;
+}
+
+
 static inline void tcp_sync_left_out(struct tcp_sock *tp)
 {
 	if (tp->rx_opt.sack_ok &&
@@ -793,6 +822,7 @@
 	struct tcp_sock *tp = tcp_sk(sk);
 
 	tp->prior_ssthresh = 0;
+	tp->bytes_acked = 0;
 	if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) {
 		__tcp_enter_cwr(sk);
 		tcp_set_ca_state(sk, TCP_CA_CWR);
@@ -809,6 +839,27 @@
 	return 3;
 }
 
+/* RFC2861 Check whether we are limited by application or congestion window
+ * This is the inverse of cwnd check in tcp_tso_should_defer
+ */
+static inline int tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
+{
+	const struct tcp_sock *tp = tcp_sk(sk);
+	u32 left;
+
+	if (in_flight >= tp->snd_cwnd)
+		return 1;
+
+	if (!(sk->sk_route_caps & NETIF_F_TSO))
+		return 0;
+
+	left = tp->snd_cwnd - in_flight;
+	if (sysctl_tcp_tso_win_divisor)
+		return left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd;
+	else
+		return left <= tcp_max_burst(tp);
+}
+
 static __inline__ void tcp_minshall_update(struct tcp_sock *tp, int mss, 
 					   const struct sk_buff *skb)
 {
@@ -852,7 +903,7 @@
 
 static __inline__ int __tcp_checksum_complete(struct sk_buff *skb)
 {
-	return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
+	return __skb_checksum_complete(skb);
 }
 
 static __inline__ int tcp_checksum_complete(struct sk_buff *skb)
@@ -1156,6 +1207,15 @@
 	TCP_ADD_STATS_USER(TCP_MIB_MAXCONN, -1);
 }
 
+/*from STCP */
+static inline void clear_all_retrans_hints(struct tcp_sock *tp){
+	tp->lost_skb_hint = NULL;
+	tp->scoreboard_skb_hint = NULL;
+	tp->retransmit_skb_hint = NULL;
+	tp->forward_skb_hint = NULL;
+	tp->fastpath_skb_hint = NULL;
+}
+
 /* /proc */
 enum tcp_seq_states {
 	TCP_SEQ_STATE_LISTENING,
diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h
index 072f3a2..5ff1490 100644
--- a/include/rdma/ib_user_verbs.h
+++ b/include/rdma/ib_user_verbs.h
@@ -43,7 +43,7 @@
  * Increment this value if any changes that break userspace ABI
  * compatibility are made.
  */
-#define IB_USER_VERBS_ABI_VERSION	3
+#define IB_USER_VERBS_ABI_VERSION	4
 
 enum {
 	IB_USER_VERBS_CMD_GET_CONTEXT,
@@ -333,6 +333,11 @@
 struct ib_uverbs_create_qp_resp {
 	__u32 qp_handle;
 	__u32 qpn;
+	__u32 max_send_wr;
+	__u32 max_recv_wr;
+	__u32 max_send_sge;
+	__u32 max_recv_sge;
+	__u32 max_inline_data;
 };
 
 /*
@@ -552,9 +557,7 @@
 	__u32 srq_handle;
 	__u32 attr_mask;
 	__u32 max_wr;
-	__u32 max_sge;
 	__u32 srq_limit;
-	__u32 reserved;
 	__u64 driver_data[0];
 };
 
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index f72d46d..a7f4c35 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -881,7 +881,7 @@
 						struct ib_ucontext *context,
 						struct ib_udata *udata);
 	int                        (*destroy_cq)(struct ib_cq *cq);
-	int                        (*resize_cq)(struct ib_cq *cq, int *cqe);
+	int                        (*resize_cq)(struct ib_cq *cq, int cqe);
 	int                        (*poll_cq)(struct ib_cq *cq, int num_entries,
 					      struct ib_wc *wc);
 	int                        (*peek_cq)(struct ib_cq *cq, int wc_cnt);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index ecd53d7..6cbb198 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -7,6 +7,7 @@
 #include <linux/workqueue.h>
 
 struct block_device;
+struct completion;
 struct module;
 struct scsi_cmnd;
 struct scsi_device;
@@ -467,10 +468,8 @@
 
 	struct list_head	eh_cmd_q;
 	struct task_struct    * ehandler;  /* Error recovery thread. */
-	struct semaphore      * eh_action; /* Wait for specific actions on the
-                                          host. */
-	unsigned int            eh_active:1; /* Indicates the eh thread is awake and active if
-                                          this is true. */
+	struct completion     * eh_action; /* Wait for specific actions on the
+					      host. */
 	wait_queue_head_t       host_wait;
 	struct scsi_host_template *hostt;
 	struct scsi_transport_template *transportt;
diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h
index 2539deb..98d69fd 100644
--- a/include/scsi/scsi_request.h
+++ b/include/scsi/scsi_request.h
@@ -47,9 +47,6 @@
 
 extern struct scsi_request *scsi_allocate_request(struct scsi_device *, gfp_t);
 extern void scsi_release_request(struct scsi_request *);
-extern void scsi_wait_req(struct scsi_request *, const void *cmnd,
-			  void *buffer, unsigned bufflen,
-			  int timeout, int retries);
 extern void scsi_do_req(struct scsi_request *, const void *cmnd,
 			void *buffer, unsigned bufflen,
 			void (*done) (struct scsi_cmnd *),
diff --git a/init/main.c b/init/main.c
index f142d40..27f97f9 100644
--- a/init/main.c
+++ b/init/main.c
@@ -394,14 +394,16 @@
 	kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
 	numa_default_policy();
 	unlock_kernel();
-	preempt_enable_no_resched();
 
 	/*
 	 * The boot idle thread must execute schedule()
 	 * at least one to get things moving:
 	 */
+	preempt_enable_no_resched();
 	schedule();
+	preempt_disable();
 
+	/* Call into cpu_idle with preempt disabled */
 	cpu_idle();
 } 
 
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 3619e93..d61ba88 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -21,6 +21,24 @@
 
 static struct notifier_block *cpu_chain;
 
+/*
+ * Used to check by callers if they need to acquire the cpucontrol
+ * or not to protect a cpu from being removed. Its sometimes required to
+ * call these functions both for normal operations, and in response to
+ * a cpu being added/removed. If the context of the call is in the same
+ * thread context as a CPU hotplug thread, we dont need to take the lock
+ * since its already protected
+ * check drivers/cpufreq/cpufreq.c for its usage - Ashok Raj
+ */
+
+int current_in_cpu_hotplug(void)
+{
+	return (current->flags & PF_HOTPLUG_CPU);
+}
+
+EXPORT_SYMBOL_GPL(current_in_cpu_hotplug);
+
+
 /* Need to know about CPUs going up/down? */
 int register_cpu_notifier(struct notifier_block *nb)
 {
@@ -94,6 +112,13 @@
 		goto out;
 	}
 
+	/*
+	 * Leave a trace in current->flags indicating we are already in
+	 * process of performing CPU hotplug. Callers can check if cpucontrol
+	 * is already acquired by current thread, and if so not cause
+	 * a dead lock by not acquiring the lock
+	 */
+	current->flags |= PF_HOTPLUG_CPU;
 	err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
 						(void *)(long)cpu);
 	if (err == NOTIFY_BAD) {
@@ -146,6 +171,7 @@
 out_allowed:
 	set_cpus_allowed(current, old_allowed);
 out:
+	current->flags &= ~PF_HOTPLUG_CPU;
 	unlock_cpu_hotplug();
 	return err;
 }
@@ -163,6 +189,12 @@
 		ret = -EINVAL;
 		goto out;
 	}
+
+	/*
+	 * Leave a trace in current->flags indicating we are already in
+	 * process of performing CPU hotplug.
+	 */
+	current->flags |= PF_HOTPLUG_CPU;
 	ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
 	if (ret == NOTIFY_BAD) {
 		printk("%s: attempt to bring up CPU %u failed\n",
@@ -185,6 +217,7 @@
 	if (ret != 0)
 		notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu);
 out:
+	current->flags &= ~PF_HOTPLUG_CPU;
 	up(&cpucontrol);
 	return ret;
 }
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 18d7d69..6ee2cad 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -167,7 +167,7 @@
 {
 	int error;
 
-	if (pm_ops->valid && !pm_ops->valid(state))
+	if (pm_ops && pm_ops->valid && !pm_ops->valid(state))
 		return -ENODEV;
 	if (down_trylock(&pm_sem))
 		return -EBUSY;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index d4fd96a..6c042b5 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -65,8 +65,8 @@
 extern asmlinkage int swsusp_arch_suspend(void);
 extern asmlinkage int swsusp_arch_resume(void);
 
-extern int restore_highmem(void);
-extern struct pbe * alloc_pagedir(unsigned nr_pages);
+extern void free_pagedir(struct pbe *pblist);
+extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed);
 extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages);
 extern void swsusp_free(void);
-extern int enough_swap(unsigned nr_pages);
+extern int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed);
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 723f517..4a6dbce 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -88,8 +88,7 @@
 	return 0;
 }
 
-
-static int save_highmem(void)
+int save_highmem(void)
 {
 	struct zone *zone;
 	int res = 0;
@@ -120,11 +119,7 @@
 	}
 	return 0;
 }
-#else
-static int save_highmem(void) { return 0; }
-int restore_highmem(void) { return 0; }
-#endif /* CONFIG_HIGHMEM */
-
+#endif
 
 static int pfn_is_nosave(unsigned long pfn)
 {
@@ -216,7 +211,7 @@
  *	free_pagedir - free pages allocated with alloc_pagedir()
  */
 
-static void free_pagedir(struct pbe *pblist)
+void free_pagedir(struct pbe *pblist)
 {
 	struct pbe *pbe;
 
@@ -269,9 +264,30 @@
 	pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
 }
 
-static void *alloc_image_page(void)
+/**
+ *	@safe_needed - on resume, for storing the PBE list and the image,
+ *	we can only use memory pages that do not conflict with the pages
+ *	which had been used before suspend.
+ *
+ *	The unsafe pages are marked with the PG_nosave_free flag
+ *
+ *	Allocated but unusable (ie eaten) memory pages should be marked
+ *	so that swsusp_free() can release them
+ */
+
+static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed)
 {
-	void *res = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
+	void *res;
+
+	if (safe_needed)
+		do {
+			res = (void *)get_zeroed_page(gfp_mask);
+			if (res && PageNosaveFree(virt_to_page(res)))
+				/* This is for swsusp_free() */
+				SetPageNosave(virt_to_page(res));
+		} while (res && PageNosaveFree(virt_to_page(res)));
+	else
+		res = (void *)get_zeroed_page(gfp_mask);
 	if (res) {
 		SetPageNosave(virt_to_page(res));
 		SetPageNosaveFree(virt_to_page(res));
@@ -279,6 +295,11 @@
 	return res;
 }
 
+unsigned long get_safe_page(gfp_t gfp_mask)
+{
+	return (unsigned long)alloc_image_page(gfp_mask, 1);
+}
+
 /**
  *	alloc_pagedir - Allocate the page directory.
  *
@@ -292,7 +313,7 @@
  *	On each page we set up a list of struct_pbe elements.
  */
 
-struct pbe *alloc_pagedir(unsigned int nr_pages)
+struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, int safe_needed)
 {
 	unsigned int num;
 	struct pbe *pblist, *pbe;
@@ -301,12 +322,12 @@
 		return NULL;
 
 	pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages);
-	pblist = alloc_image_page();
+	pblist = alloc_image_page(gfp_mask, safe_needed);
 	/* FIXME: rewrite this ugly loop */
 	for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages;
         		pbe = pbe->next, num += PBES_PER_PAGE) {
 		pbe += PB_PAGE_SKIP;
-		pbe->next = alloc_image_page();
+		pbe->next = alloc_image_page(gfp_mask, safe_needed);
 	}
 	if (!pbe) { /* get_zeroed_page() failed */
 		free_pagedir(pblist);
@@ -354,24 +375,32 @@
 		(nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
 }
 
+int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed)
+{
+	struct pbe *p;
+
+	for_each_pbe (p, pblist) {
+		p->address = (unsigned long)alloc_image_page(gfp_mask, safe_needed);
+		if (!p->address)
+			return -ENOMEM;
+	}
+	return 0;
+}
 
 static struct pbe *swsusp_alloc(unsigned int nr_pages)
 {
-	struct pbe *pblist, *p;
+	struct pbe *pblist;
 
-	if (!(pblist = alloc_pagedir(nr_pages))) {
+	if (!(pblist = alloc_pagedir(nr_pages, GFP_ATOMIC | __GFP_COLD, 0))) {
 		printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
 		return NULL;
 	}
 	create_pbe_list(pblist, nr_pages);
 
-	for_each_pbe (p, pblist) {
-		p->address = (unsigned long)alloc_image_page();
-		if (!p->address) {
-			printk(KERN_ERR "suspend: Allocating image pages failed.\n");
-			swsusp_free();
-			return NULL;
-		}
+	if (alloc_data_pages(pblist, GFP_ATOMIC | __GFP_COLD, 0)) {
+		printk(KERN_ERR "suspend: Allocating image pages failed.\n");
+		swsusp_free();
+		return NULL;
 	}
 
 	return pblist;
@@ -382,11 +411,6 @@
 	unsigned int nr_pages;
 
 	pr_debug("swsusp: critical section: \n");
-	if (save_highmem()) {
-		printk(KERN_CRIT "swsusp: Not enough free pages for highmem\n");
-		restore_highmem();
-		return -ENOMEM;
-	}
 
 	drain_local_pages();
 	nr_pages = count_data_pages();
@@ -406,11 +430,6 @@
 		return -ENOMEM;
 	}
 
-	if (!enough_swap(nr_pages)) {
-		printk(KERN_ERR "swsusp: Not enough free swap\n");
-		return -ENOSPC;
-	}
-
 	pagedir_nosave = swsusp_alloc(nr_pages);
 	if (!pagedir_nosave)
 		return -ENOMEM;
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index e1ab28b..c05f46e 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -73,6 +73,14 @@
 
 #include "power.h"
 
+#ifdef CONFIG_HIGHMEM
+int save_highmem(void);
+int restore_highmem(void);
+#else
+static int save_highmem(void) { return 0; }
+static int restore_highmem(void) { return 0; }
+#endif
+
 #define CIPHER "aes"
 #define MAXKEY 32
 #define MAXIV  32
@@ -500,6 +508,26 @@
 }
 
 /**
+ *	enough_swap - Make sure we have enough swap to save the image.
+ *
+ *	Returns TRUE or FALSE after checking the total amount of swap
+ *	space avaiable.
+ *
+ *	FIXME: si_swapinfo(&i) returns all swap devices information.
+ *	We should only consider resume_device.
+ */
+
+static int enough_swap(unsigned int nr_pages)
+{
+	struct sysinfo i;
+
+	si_swapinfo(&i);
+	pr_debug("swsusp: available swap: %lu pages\n", i.freeswap);
+	return i.freeswap > (nr_pages + PAGES_FOR_IO +
+		(nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
+}
+
+/**
  *	write_suspend_image - Write entire image and metadata.
  *
  */
@@ -507,6 +535,11 @@
 {
 	int error;
 
+	if (!enough_swap(nr_copy_pages)) {
+		printk(KERN_ERR "swsusp: Not enough free swap\n");
+		return -ENOSPC;
+	}
+
 	init_header();
 	if ((error = data_write()))
 		goto FreeData;
@@ -526,27 +559,6 @@
 	goto Done;
 }
 
-/**
- *	enough_swap - Make sure we have enough swap to save the image.
- *
- *	Returns TRUE or FALSE after checking the total amount of swap
- *	space avaiable.
- *
- *	FIXME: si_swapinfo(&i) returns all swap devices information.
- *	We should only consider resume_device.
- */
-
-int enough_swap(unsigned int nr_pages)
-{
-	struct sysinfo i;
-
-	si_swapinfo(&i);
-	pr_debug("swsusp: available swap: %lu pages\n", i.freeswap);
-	return i.freeswap > (nr_pages + PAGES_FOR_IO +
-		(nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
-}
-
-
 /* It is important _NOT_ to umount filesystems at this point. We want
  * them synced (in case something goes wrong) but we DO not want to mark
  * filesystem clean: it is not. (And it does not matter, if we resume
@@ -556,12 +568,15 @@
 {
 	int error;
 
+	if ((error = swsusp_swap_check())) {
+		printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n");
+		return error;
+	}
 	lock_swapdevices();
 	error = write_suspend_image();
 	/* This will unlock ignored swap devices since writing is finished */
 	lock_swapdevices();
 	return error;
-
 }
 
 
@@ -569,6 +584,7 @@
 int swsusp_suspend(void)
 {
 	int error;
+
 	if ((error = arch_prepare_suspend()))
 		return error;
 	local_irq_disable();
@@ -580,15 +596,12 @@
 	 */
 	if ((error = device_power_down(PMSG_FREEZE))) {
 		printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
-		local_irq_enable();
-		return error;
+		goto Enable_irqs;
 	}
 
-	if ((error = swsusp_swap_check())) {
-		printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n");
-		device_power_up();
-		local_irq_enable();
-		return error;
+	if ((error = save_highmem())) {
+		printk(KERN_ERR "swsusp: Not enough free pages for highmem\n");
+		goto Restore_highmem;
 	}
 
 	save_processor_state();
@@ -596,8 +609,10 @@
 		printk(KERN_ERR "Error %d suspending\n", error);
 	/* Restore control flow magically appears here */
 	restore_processor_state();
+Restore_highmem:
 	restore_highmem();
 	device_power_up();
+Enable_irqs:
 	local_irq_enable();
 	return error;
 }
@@ -629,127 +644,43 @@
 }
 
 /**
- *	On resume, for storing the PBE list and the image,
- *	we can only use memory pages that do not conflict with the pages
- *	which had been used before suspend.
- *
- *	We don't know which pages are usable until we allocate them.
- *
- *	Allocated but unusable (ie eaten) memory pages are marked so that
- *	swsusp_free() can release them
+ *	mark_unsafe_pages - mark the pages that cannot be used for storing
+ *	the image during resume, because they conflict with the pages that
+ *	had been used before suspend
  */
 
-unsigned long get_safe_page(gfp_t gfp_mask)
-{
-	unsigned long m;
-
-	do {
-		m = get_zeroed_page(gfp_mask);
-		if (m && PageNosaveFree(virt_to_page(m)))
-			/* This is for swsusp_free() */
-			SetPageNosave(virt_to_page(m));
-	} while (m && PageNosaveFree(virt_to_page(m)));
-	if (m) {
-		/* This is for swsusp_free() */
-		SetPageNosave(virt_to_page(m));
-		SetPageNosaveFree(virt_to_page(m));
-	}
-	return m;
-}
-
-/**
- *	check_pagedir - We ensure here that pages that the PBEs point to
- *	won't collide with pages where we're going to restore from the loaded
- *	pages later
- */
-
-static int check_pagedir(struct pbe *pblist)
-{
-	struct pbe *p;
-
-	/* This is necessary, so that we can free allocated pages
-	 * in case of failure
-	 */
-	for_each_pbe (p, pblist)
-		p->address = 0UL;
-
-	for_each_pbe (p, pblist) {
-		p->address = get_safe_page(GFP_ATOMIC);
-		if (!p->address)
-			return -ENOMEM;
-	}
-	return 0;
-}
-
-/**
- *	swsusp_pagedir_relocate - It is possible, that some memory pages
- *	occupied by the list of PBEs collide with pages where we're going to
- *	restore from the loaded pages later.  We relocate them here.
- */
-
-static struct pbe *swsusp_pagedir_relocate(struct pbe *pblist)
+static void mark_unsafe_pages(struct pbe *pblist)
 {
 	struct zone *zone;
 	unsigned long zone_pfn;
-	struct pbe *pbpage, *tail, *p;
-	void *m;
-	int rel = 0;
+	struct pbe *p;
 
 	if (!pblist) /* a sanity check */
-		return NULL;
-
-	pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n",
-			swsusp_info.pagedir_pages);
+		return;
 
 	/* Clear page flags */
-
 	for_each_zone (zone) {
-        	for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
-        		if (pfn_valid(zone_pfn + zone->zone_start_pfn))
-                		ClearPageNosaveFree(pfn_to_page(zone_pfn +
+		for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+			if (pfn_valid(zone_pfn + zone->zone_start_pfn))
+				ClearPageNosaveFree(pfn_to_page(zone_pfn +
 					zone->zone_start_pfn));
 	}
 
 	/* Mark orig addresses */
-
 	for_each_pbe (p, pblist)
 		SetPageNosaveFree(virt_to_page(p->orig_address));
 
-	tail = pblist + PB_PAGE_SKIP;
+}
 
-	/* Relocate colliding pages */
-
-	for_each_pb_page (pbpage, pblist) {
-		if (PageNosaveFree(virt_to_page((unsigned long)pbpage))) {
-			m = (void *)get_safe_page(GFP_ATOMIC | __GFP_COLD);
-			if (!m)
-				return NULL;
-			memcpy(m, (void *)pbpage, PAGE_SIZE);
-			if (pbpage == pblist)
-				pblist = (struct pbe *)m;
-			else
-				tail->next = (struct pbe *)m;
-			pbpage = (struct pbe *)m;
-
-			/* We have to link the PBEs again */
-			for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++)
-				if (p->next) /* needed to save the end */
-					p->next = p + 1;
-
-			rel++;
-		}
-		tail = pbpage + PB_PAGE_SKIP;
+static void copy_page_backup_list(struct pbe *dst, struct pbe *src)
+{
+	/* We assume both lists contain the same number of elements */
+	while (src) {
+		dst->orig_address = src->orig_address;
+		dst->swap_address = src->swap_address;
+		dst = dst->next;
+		src = src->next;
 	}
-
-	/* This is for swsusp_free() */
-	for_each_pb_page (pbpage, pblist) {
-		SetPageNosave(virt_to_page(pbpage));
-		SetPageNosaveFree(virt_to_page(pbpage));
-	}
-
-	printk("swsusp: Relocated %d pages\n", rel);
-
-	return pblist;
 }
 
 /*
@@ -888,7 +819,7 @@
 		 * Reset swap signature now.
 		 */
 		error = bio_write_page(0, &swsusp_header);
-	} else { 
+	} else {
 		return -EINVAL;
 	}
 	if (!error)
@@ -990,20 +921,25 @@
 	int error = 0;
 	struct pbe *p;
 
-	if (!(p = alloc_pagedir(nr_copy_pages)))
+	if (!(p = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 0)))
 		return -ENOMEM;
 
 	if ((error = read_pagedir(p)))
 		return error;
-
 	create_pbe_list(p, nr_copy_pages);
-
-	if (!(pagedir_nosave = swsusp_pagedir_relocate(p)))
+	mark_unsafe_pages(p);
+	pagedir_nosave = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 1);
+	if (pagedir_nosave) {
+		create_pbe_list(pagedir_nosave, nr_copy_pages);
+		copy_page_backup_list(pagedir_nosave, p);
+	}
+	free_pagedir(p);
+	if (!pagedir_nosave)
 		return -ENOMEM;
 
 	/* Allocate memory for the image and read the data from swap */
 
-	error = check_pagedir(pagedir_nosave);
+	error = alloc_data_pages(pagedir_nosave, GFP_ATOMIC, 1);
 
 	if (!error)
 		error = data_read(pagedir_nosave);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 5b8dd98..b88d418 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -155,7 +155,7 @@
 	retval = -EPERM;
 	if (task->pid <= 1)
 		goto bad;
-	if (task == current)
+	if (task->tgid == current->tgid)
 		goto bad;
 	/* the same process cannot be attached many times */
 	if (task->ptrace & PT_PTRACED)
diff --git a/kernel/sched.c b/kernel/sched.c
index 3ce2695..b650667 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -206,6 +206,7 @@
 	 */
 	unsigned long nr_running;
 #ifdef CONFIG_SMP
+	unsigned long prio_bias;
 	unsigned long cpu_load[3];
 #endif
 	unsigned long long nr_switches;
@@ -659,13 +660,68 @@
 	return prio;
 }
 
+#ifdef CONFIG_SMP
+static inline void inc_prio_bias(runqueue_t *rq, int prio)
+{
+	rq->prio_bias += MAX_PRIO - prio;
+}
+
+static inline void dec_prio_bias(runqueue_t *rq, int prio)
+{
+	rq->prio_bias -= MAX_PRIO - prio;
+}
+
+static inline void inc_nr_running(task_t *p, runqueue_t *rq)
+{
+	rq->nr_running++;
+	if (rt_task(p)) {
+		if (p != rq->migration_thread)
+			/*
+			 * The migration thread does the actual balancing. Do
+			 * not bias by its priority as the ultra high priority
+			 * will skew balancing adversely.
+			 */
+			inc_prio_bias(rq, p->prio);
+	} else
+		inc_prio_bias(rq, p->static_prio);
+}
+
+static inline void dec_nr_running(task_t *p, runqueue_t *rq)
+{
+	rq->nr_running--;
+	if (rt_task(p)) {
+		if (p != rq->migration_thread)
+			dec_prio_bias(rq, p->prio);
+	} else
+		dec_prio_bias(rq, p->static_prio);
+}
+#else
+static inline void inc_prio_bias(runqueue_t *rq, int prio)
+{
+}
+
+static inline void dec_prio_bias(runqueue_t *rq, int prio)
+{
+}
+
+static inline void inc_nr_running(task_t *p, runqueue_t *rq)
+{
+	rq->nr_running++;
+}
+
+static inline void dec_nr_running(task_t *p, runqueue_t *rq)
+{
+	rq->nr_running--;
+}
+#endif
+
 /*
  * __activate_task - move a task to the runqueue.
  */
 static inline void __activate_task(task_t *p, runqueue_t *rq)
 {
 	enqueue_task(p, rq->active);
-	rq->nr_running++;
+	inc_nr_running(p, rq);
 }
 
 /*
@@ -674,7 +730,7 @@
 static inline void __activate_idle_task(task_t *p, runqueue_t *rq)
 {
 	enqueue_task_head(p, rq->active);
-	rq->nr_running++;
+	inc_nr_running(p, rq);
 }
 
 static int recalc_task_prio(task_t *p, unsigned long long now)
@@ -759,7 +815,8 @@
 	}
 #endif
 
-	p->prio = recalc_task_prio(p, now);
+	if (!rt_task(p))
+		p->prio = recalc_task_prio(p, now);
 
 	/*
 	 * This checks to make sure it's not an uninterruptible task
@@ -793,7 +850,7 @@
  */
 static void deactivate_task(struct task_struct *p, runqueue_t *rq)
 {
-	rq->nr_running--;
+	dec_nr_running(p, rq);
 	dequeue_task(p, p->array);
 	p->array = NULL;
 }
@@ -808,21 +865,28 @@
 #ifdef CONFIG_SMP
 static void resched_task(task_t *p)
 {
-	int need_resched, nrpolling;
+	int cpu;
 
 	assert_spin_locked(&task_rq(p)->lock);
 
-	/* minimise the chance of sending an interrupt to poll_idle() */
-	nrpolling = test_tsk_thread_flag(p,TIF_POLLING_NRFLAG);
-	need_resched = test_and_set_tsk_thread_flag(p,TIF_NEED_RESCHED);
-	nrpolling |= test_tsk_thread_flag(p,TIF_POLLING_NRFLAG);
+	if (unlikely(test_tsk_thread_flag(p, TIF_NEED_RESCHED)))
+		return;
 
-	if (!need_resched && !nrpolling && (task_cpu(p) != smp_processor_id()))
-		smp_send_reschedule(task_cpu(p));
+	set_tsk_thread_flag(p, TIF_NEED_RESCHED);
+
+	cpu = task_cpu(p);
+	if (cpu == smp_processor_id())
+		return;
+
+	/* NEED_RESCHED must be visible before we test POLLING_NRFLAG */
+	smp_mb();
+	if (!test_tsk_thread_flag(p, TIF_POLLING_NRFLAG))
+		smp_send_reschedule(cpu);
 }
 #else
 static inline void resched_task(task_t *p)
 {
+	assert_spin_locked(&task_rq(p)->lock);
 	set_tsk_need_resched(p);
 }
 #endif
@@ -930,27 +994,61 @@
  * We want to under-estimate the load of migration sources, to
  * balance conservatively.
  */
-static inline unsigned long source_load(int cpu, int type)
+static inline unsigned long __source_load(int cpu, int type, enum idle_type idle)
 {
 	runqueue_t *rq = cpu_rq(cpu);
-	unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
-	if (type == 0)
-		return load_now;
+	unsigned long running = rq->nr_running;
+	unsigned long source_load, cpu_load = rq->cpu_load[type-1],
+		load_now = running * SCHED_LOAD_SCALE;
 
-	return min(rq->cpu_load[type-1], load_now);
+	if (type == 0)
+		source_load = load_now;
+	else
+		source_load = min(cpu_load, load_now);
+
+	if (running > 1 || (idle == NOT_IDLE && running))
+		/*
+		 * If we are busy rebalancing the load is biased by
+		 * priority to create 'nice' support across cpus. When
+		 * idle rebalancing we should only bias the source_load if
+		 * there is more than one task running on that queue to
+		 * prevent idle rebalance from trying to pull tasks from a
+		 * queue with only one running task.
+		 */
+		source_load = source_load * rq->prio_bias / running;
+
+	return source_load;
+}
+
+static inline unsigned long source_load(int cpu, int type)
+{
+	return __source_load(cpu, type, NOT_IDLE);
 }
 
 /*
  * Return a high guess at the load of a migration-target cpu
  */
-static inline unsigned long target_load(int cpu, int type)
+static inline unsigned long __target_load(int cpu, int type, enum idle_type idle)
 {
 	runqueue_t *rq = cpu_rq(cpu);
-	unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
-	if (type == 0)
-		return load_now;
+	unsigned long running = rq->nr_running;
+	unsigned long target_load, cpu_load = rq->cpu_load[type-1],
+		load_now = running * SCHED_LOAD_SCALE;
 
-	return max(rq->cpu_load[type-1], load_now);
+	if (type == 0)
+		target_load = load_now;
+	else
+		target_load = max(cpu_load, load_now);
+
+	if (running > 1 || (idle == NOT_IDLE && running))
+		target_load = target_load * rq->prio_bias / running;
+
+	return target_load;
+}
+
+static inline unsigned long target_load(int cpu, int type)
+{
+	return __target_load(cpu, type, NOT_IDLE);
 }
 
 /*
@@ -1411,7 +1509,7 @@
 				list_add_tail(&p->run_list, &current->run_list);
 				p->array = current->array;
 				p->array->nr_active++;
-				rq->nr_running++;
+				inc_nr_running(p, rq);
 			}
 			set_need_resched();
 		} else
@@ -1756,9 +1854,9 @@
 	       runqueue_t *this_rq, prio_array_t *this_array, int this_cpu)
 {
 	dequeue_task(p, src_array);
-	src_rq->nr_running--;
+	dec_nr_running(p, src_rq);
 	set_task_cpu(p, this_cpu);
-	this_rq->nr_running++;
+	inc_nr_running(p, this_rq);
 	enqueue_task(p, this_array);
 	p->timestamp = (p->timestamp - src_rq->timestamp_last_tick)
 				+ this_rq->timestamp_last_tick;
@@ -1937,9 +2035,9 @@
 
 			/* Bias balancing toward cpus of our domain */
 			if (local_group)
-				load = target_load(i, load_idx);
+				load = __target_load(i, load_idx, idle);
 			else
-				load = source_load(i, load_idx);
+				load = __source_load(i, load_idx, idle);
 
 			avg_load += load;
 		}
@@ -2044,14 +2142,15 @@
 /*
  * find_busiest_queue - find the busiest runqueue among the cpus in group.
  */
-static runqueue_t *find_busiest_queue(struct sched_group *group)
+static runqueue_t *find_busiest_queue(struct sched_group *group,
+	enum idle_type idle)
 {
 	unsigned long load, max_load = 0;
 	runqueue_t *busiest = NULL;
 	int i;
 
 	for_each_cpu_mask(i, group->cpumask) {
-		load = source_load(i, 0);
+		load = __source_load(i, 0, idle);
 
 		if (load > max_load) {
 			max_load = load;
@@ -2095,7 +2194,7 @@
 		goto out_balanced;
 	}
 
-	busiest = find_busiest_queue(group);
+	busiest = find_busiest_queue(group, idle);
 	if (!busiest) {
 		schedstat_inc(sd, lb_nobusyq[idle]);
 		goto out_balanced;
@@ -2218,7 +2317,7 @@
 		goto out_balanced;
 	}
 
-	busiest = find_busiest_queue(group);
+	busiest = find_busiest_queue(group, NEWLY_IDLE);
 	if (!busiest) {
 		schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
 		goto out_balanced;
@@ -3451,8 +3550,10 @@
 		goto out_unlock;
 	}
 	array = p->array;
-	if (array)
+	if (array) {
 		dequeue_task(p, array);
+		dec_prio_bias(rq, p->static_prio);
+	}
 
 	old_prio = p->prio;
 	new_prio = NICE_TO_PRIO(nice);
@@ -3462,6 +3563,7 @@
 
 	if (array) {
 		enqueue_task(p, array);
+		inc_prio_bias(rq, p->static_prio);
 		/*
 		 * If the task increased its priority or is running and
 		 * lowered its priority, then reschedule its CPU:
diff --git a/kernel/signal.c b/kernel/signal.c
index 1bf3c39..80789a5 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1499,7 +1499,7 @@
 
 	psig = tsk->parent->sighand;
 	spin_lock_irqsave(&psig->siglock, flags);
-	if (sig == SIGCHLD &&
+	if (!tsk->ptrace && sig == SIGCHLD &&
 	    (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN ||
 	     (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) {
 		/*
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index a2dcceb..c67189a2 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -73,9 +73,6 @@
 static int watchdog(void * __bind_cpu)
 {
 	struct sched_param param = { .sched_priority = 99 };
-	int this_cpu = (long) __bind_cpu;
-
-	printk("softlockup thread %d started up.\n", this_cpu);
 
 	sched_setscheduler(current, SCHED_FIFO, &param);
 	current->flags |= PF_NOFREEZE;
diff --git a/kernel/sys.c b/kernel/sys.c
index c43b3e2..bce933e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1497,6 +1497,8 @@
 
 DECLARE_RWSEM(uts_sem);
 
+EXPORT_SYMBOL(uts_sem);
+
 asmlinkage long sys_newuname(struct new_utsname __user * name)
 {
 	int errno = 0;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c4f35f9..9990e10 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -169,7 +169,7 @@
 
 extern struct proc_dir_entry *proc_sys_root;
 
-static void register_proc_table(ctl_table *, struct proc_dir_entry *);
+static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *);
 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
 #endif
 
@@ -992,10 +992,51 @@
 
 extern void init_irq_proc (void);
 
+static DEFINE_SPINLOCK(sysctl_lock);
+
+/* called under sysctl_lock */
+static int use_table(struct ctl_table_header *p)
+{
+	if (unlikely(p->unregistering))
+		return 0;
+	p->used++;
+	return 1;
+}
+
+/* called under sysctl_lock */
+static void unuse_table(struct ctl_table_header *p)
+{
+	if (!--p->used)
+		if (unlikely(p->unregistering))
+			complete(p->unregistering);
+}
+
+/* called under sysctl_lock, will reacquire if has to wait */
+static void start_unregistering(struct ctl_table_header *p)
+{
+	/*
+	 * if p->used is 0, nobody will ever touch that entry again;
+	 * we'll eliminate all paths to it before dropping sysctl_lock
+	 */
+	if (unlikely(p->used)) {
+		struct completion wait;
+		init_completion(&wait);
+		p->unregistering = &wait;
+		spin_unlock(&sysctl_lock);
+		wait_for_completion(&wait);
+		spin_lock(&sysctl_lock);
+	}
+	/*
+	 * do not remove from the list until nobody holds it; walking the
+	 * list in do_sysctl() relies on that.
+	 */
+	list_del_init(&p->ctl_entry);
+}
+
 void __init sysctl_init(void)
 {
 #ifdef CONFIG_PROC_FS
-	register_proc_table(root_table, proc_sys_root);
+	register_proc_table(root_table, proc_sys_root, &root_table_header);
 	init_irq_proc();
 #endif
 }
@@ -1004,6 +1045,7 @@
 	       void __user *newval, size_t newlen)
 {
 	struct list_head *tmp;
+	int error = -ENOTDIR;
 
 	if (nlen <= 0 || nlen >= CTL_MAXNAME)
 		return -ENOTDIR;
@@ -1012,20 +1054,30 @@
 		if (!oldlenp || get_user(old_len, oldlenp))
 			return -EFAULT;
 	}
+	spin_lock(&sysctl_lock);
 	tmp = &root_table_header.ctl_entry;
 	do {
 		struct ctl_table_header *head =
 			list_entry(tmp, struct ctl_table_header, ctl_entry);
 		void *context = NULL;
-		int error = parse_table(name, nlen, oldval, oldlenp, 
+
+		if (!use_table(head))
+			continue;
+
+		spin_unlock(&sysctl_lock);
+
+		error = parse_table(name, nlen, oldval, oldlenp, 
 					newval, newlen, head->ctl_table,
 					&context);
 		kfree(context);
+
+		spin_lock(&sysctl_lock);
+		unuse_table(head);
 		if (error != -ENOTDIR)
-			return error;
-		tmp = tmp->next;
-	} while (tmp != &root_table_header.ctl_entry);
-	return -ENOTDIR;
+			break;
+	} while ((tmp = tmp->next) != &root_table_header.ctl_entry);
+	spin_unlock(&sysctl_lock);
+	return error;
 }
 
 asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
@@ -1236,12 +1288,16 @@
 		return NULL;
 	tmp->ctl_table = table;
 	INIT_LIST_HEAD(&tmp->ctl_entry);
+	tmp->used = 0;
+	tmp->unregistering = NULL;
+	spin_lock(&sysctl_lock);
 	if (insert_at_head)
 		list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
 	else
 		list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
+	spin_unlock(&sysctl_lock);
 #ifdef CONFIG_PROC_FS
-	register_proc_table(table, proc_sys_root);
+	register_proc_table(table, proc_sys_root, tmp);
 #endif
 	return tmp;
 }
@@ -1255,10 +1311,13 @@
  */
 void unregister_sysctl_table(struct ctl_table_header * header)
 {
-	list_del(&header->ctl_entry);
+	might_sleep();
+	spin_lock(&sysctl_lock);
+	start_unregistering(header);
 #ifdef CONFIG_PROC_FS
 	unregister_proc_table(header->ctl_table, proc_sys_root);
 #endif
+	spin_unlock(&sysctl_lock);
 	kfree(header);
 }
 
@@ -1269,7 +1328,7 @@
 #ifdef CONFIG_PROC_FS
 
 /* Scan the sysctl entries in table and add them all into /proc */
-static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
+static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set)
 {
 	struct proc_dir_entry *de;
 	int len;
@@ -1305,13 +1364,14 @@
 			de = create_proc_entry(table->procname, mode, root);
 			if (!de)
 				continue;
+			de->set = set;
 			de->data = (void *) table;
 			if (table->proc_handler)
 				de->proc_fops = &proc_sys_file_operations;
 		}
 		table->de = de;
 		if (de->mode & S_IFDIR)
-			register_proc_table(table->child, de);
+			register_proc_table(table->child, de, set);
 	}
 }
 
@@ -1336,6 +1396,13 @@
 				continue;
 		}
 
+		/*
+		 * In any case, mark the entry as goner; we'll keep it
+		 * around if it's busy, but we'll know to do nothing with
+		 * its fields.  We are under sysctl_lock here.
+		 */
+		de->data = NULL;
+
 		/* Don't unregister proc entries that are still being used.. */
 		if (atomic_read(&de->count))
 			continue;
@@ -1349,27 +1416,38 @@
 			  size_t count, loff_t *ppos)
 {
 	int op;
-	struct proc_dir_entry *de;
+	struct proc_dir_entry *de = PDE(file->f_dentry->d_inode);
 	struct ctl_table *table;
 	size_t res;
-	ssize_t error;
+	ssize_t error = -ENOTDIR;
 	
-	de = PDE(file->f_dentry->d_inode);
-	if (!de || !de->data)
-		return -ENOTDIR;
-	table = (struct ctl_table *) de->data;
-	if (!table || !table->proc_handler)
-		return -ENOTDIR;
-	op = (write ? 002 : 004);
-	if (ctl_perm(table, op))
-		return -EPERM;
-	
-	res = count;
-
-	error = (*table->proc_handler) (table, write, file, buf, &res, ppos);
-	if (error)
-		return error;
-	return res;
+	spin_lock(&sysctl_lock);
+	if (de && de->data && use_table(de->set)) {
+		/*
+		 * at that point we know that sysctl was not unregistered
+		 * and won't be until we finish
+		 */
+		spin_unlock(&sysctl_lock);
+		table = (struct ctl_table *) de->data;
+		if (!table || !table->proc_handler)
+			goto out;
+		error = -EPERM;
+		op = (write ? 002 : 004);
+		if (ctl_perm(table, op))
+			goto out;
+		
+		/* careful: calling conventions are nasty here */
+		res = count;
+		error = (*table->proc_handler)(table, write, file,
+						buf, &res, ppos);
+		if (!error)
+			error = res;
+	out:
+		spin_lock(&sysctl_lock);
+		unuse_table(de->set);
+	}
+	spin_unlock(&sysctl_lock);
+	return error;
 }
 
 static int proc_opensys(struct inode *inode, struct file *file)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ff81b5c..987225b 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1330,7 +1330,7 @@
 		} else
 			printk("\n");
 
-		for_each_cpu(cpu) {
+		for_each_online_cpu(cpu) {
 			struct per_cpu_pageset *pageset;
 
 			pageset = zone_pcp(zone, cpu);
diff --git a/net/802/p8023.c b/net/802/p8023.c
index 6368d3d..d23e906 100644
--- a/net/802/p8023.c
+++ b/net/802/p8023.c
@@ -54,8 +54,7 @@
  */
 void destroy_8023_client(struct datalink_proto *dl)
 {
-	if (dl)
-		kfree(dl);
+	kfree(dl);
 }
 
 EXPORT_SYMBOL(destroy_8023_client);
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 8e37e71..1b683f3 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1138,10 +1138,8 @@
 	sk->sk_state   = TCP_CLOSE;
 	sock->state = SS_UNCONNECTED;
 
-	if (ax25->digipeat != NULL) {
-		kfree(ax25->digipeat);
-		ax25->digipeat = NULL;
-	}
+	kfree(ax25->digipeat);
+	ax25->digipeat = NULL;
 
 	/*
 	 *	Handle digi-peaters to be used.
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index 73cfc34..4cf8754 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -401,10 +401,8 @@
 	}
 
 	if (dp.ndigi == 0) {
-		if (ax25->digipeat != NULL) {
-			kfree(ax25->digipeat);
-			ax25->digipeat = NULL;
-		}
+		kfree(ax25->digipeat);
+		ax25->digipeat = NULL;
 	} else {
 		/* Reverse the source SABM's path */
 		memcpy(ax25->digipeat, &reverse_dp, sizeof(ax25_digi));
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 26b77d9..b1e945bd 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -54,15 +54,13 @@
 		if (s->dev == dev) {
 			if (ax25_route_list == s) {
 				ax25_route_list = s->next;
-				if (s->digipeat != NULL)
-					kfree(s->digipeat);
+				kfree(s->digipeat);
 				kfree(s);
 			} else {
 				for (t = ax25_route_list; t != NULL; t = t->next) {
 					if (t->next == s) {
 						t->next = s->next;
-						if (s->digipeat != NULL)
-							kfree(s->digipeat);
+						kfree(s->digipeat);
 						kfree(s);
 						break;
 					}
@@ -90,10 +88,8 @@
 	while (ax25_rt != NULL) {
 		if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
 		            ax25_rt->dev == ax25_dev->dev) {
-			if (ax25_rt->digipeat != NULL) {
-				kfree(ax25_rt->digipeat);
-				ax25_rt->digipeat = NULL;
-			}
+			kfree(ax25_rt->digipeat);
+			ax25_rt->digipeat = NULL;
 			if (route->digi_count != 0) {
 				if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 					write_unlock(&ax25_route_lock);
@@ -145,8 +141,7 @@
 static void ax25_rt_destroy(ax25_route *ax25_rt)
 {
 	if (atomic_read(&ax25_rt->ref) == 0) {
-		if (ax25_rt->digipeat != NULL)
-			kfree(ax25_rt->digipeat);
+		kfree(ax25_rt->digipeat);
 		kfree(ax25_rt);
 		return;
 	}
@@ -530,9 +525,7 @@
 		s       = ax25_rt;
 		ax25_rt = ax25_rt->next;
 
-		if (s->digipeat != NULL)
-			kfree(s->digipeat);
-
+		kfree(s->digipeat);
 		kfree(s);
 	}
 	write_unlock(&ax25_route_lock);
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 03532062..ea616e3 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -36,7 +36,6 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/proc_fs.h>
 #include <net/sock.h>
 
 #if defined(CONFIG_KMOD)
@@ -50,10 +49,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.7"
-
-struct proc_dir_entry *proc_bt;
-EXPORT_SYMBOL(proc_bt);
+#define VERSION "2.8"
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO	8
@@ -312,10 +308,6 @@
 {
 	BT_INFO("Core ver %s", VERSION);
 
-	proc_bt = proc_mkdir("bluetooth", NULL);
-	if (proc_bt)
-		proc_bt->owner = THIS_MODULE;
-
 	sock_register(&bt_sock_family_ops);
 
 	BT_INFO("HCI device and connection manager initialized");
@@ -334,8 +326,6 @@
 	bt_sysfs_cleanup();
 
 	sock_unregister(PF_BLUETOOTH);
-
-	remove_proc_entry("bluetooth", NULL);
 }
 
 subsys_initcall(bt_init);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index cf0df1c..9106354 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -183,7 +183,7 @@
 static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 {
 	struct sk_buff *skb;
-	__u16 param;
+	__le16 param;
 
 	BT_DBG("%s %ld", hdev->name, opt);
 
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index b61b4e8..eb64555 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -242,7 +242,7 @@
 			break;
 
 		status = *((__u8 *) skb->data);
-		setting = __le16_to_cpu(get_unaligned((__u16 *) sent));
+		setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
 
 		if (!status && hdev->voice_setting != setting) {
 			hdev->voice_setting = setting;
@@ -728,7 +728,7 @@
 static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_num_comp_pkts *ev = (struct hci_ev_num_comp_pkts *) skb->data;
-	__u16 *ptr;
+	__le16 *ptr;
 	int i;
 
 	skb_pull(skb, sizeof(*ev));
@@ -742,7 +742,7 @@
 
 	tasklet_disable(&hdev->tx_task);
 
-	for (i = 0, ptr = (__u16 *) skb->data; i < ev->num_hndl; i++) {
+	for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
 		struct hci_conn *conn;
 		__u16  handle, count;
 
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 799e448..1d6d0a1 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -416,7 +416,7 @@
 	skb->dev = (void *) hdev;
 
 	if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
-		u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
+		u16 opcode = __le16_to_cpu(get_unaligned((__le16 *) skb->data));
 		u16 ogf = hci_opcode_ogf(opcode);
 		u16 ocf = hci_opcode_ocf(opcode);
 
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 7856bc2..bd7568a 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -103,7 +103,7 @@
 	kfree(hdev);
 }
 
-static struct class bt_class = {
+struct class bt_class = {
 	.name		= "bluetooth",
 	.release	= bt_release,
 #ifdef CONFIG_HOTPLUG
@@ -111,6 +111,8 @@
 #endif
 };
 
+EXPORT_SYMBOL_GPL(bt_class);
+
 int hci_register_sysfs(struct hci_dev *hdev)
 {
 	struct class_device *cdev = &hdev->class_dev;
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 860444a..cdb9cfa 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -660,9 +660,7 @@
 failed:
 	up_write(&hidp_session_sem);
 
-	if (session->input)
-		kfree(session->input);
-
+	kfree(session->input);
 	kfree(session);
 	return err;
 }
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 59b2dd3..e3bb11c 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -38,9 +38,8 @@
 #include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <linux/list.h>
+#include <linux/device.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
@@ -56,7 +55,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.7"
+#define VERSION "2.8"
 
 static struct proto_ops l2cap_sock_ops;
 
@@ -2137,94 +2136,29 @@
 	return 0;
 }
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *l2cap_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
 {
 	struct sock *sk;
 	struct hlist_node *node;
-	loff_t l = *pos;
+	char *str = buf;
 
 	read_lock_bh(&l2cap_sk_list.lock);
 
-	sk_for_each(sk, node, &l2cap_sk_list.head)
-		if (!l--)
-			goto found;
-	sk = NULL;
-found:
-	return sk;
-}
+	sk_for_each(sk, node, &l2cap_sk_list.head) {
+		struct l2cap_pinfo *pi = l2cap_pi(sk);
 
-static void *l2cap_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-	(*pos)++;
-	return sk_next(e);
-}
+		str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
+				batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+				sk->sk_state, pi->psm, pi->scid, pi->dcid, pi->imtu,
+				pi->omtu, pi->link_mode);
+	}
 
-static void l2cap_seq_stop(struct seq_file *seq, void *e)
-{
 	read_unlock_bh(&l2cap_sk_list.lock);
+
+	return (str - buf);
 }
 
-static int  l2cap_seq_show(struct seq_file *seq, void *e)
-{
-	struct sock *sk = e;
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
-
-	seq_printf(seq, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
-			batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), 
-			sk->sk_state, pi->psm, pi->scid, pi->dcid, pi->imtu,
-			pi->omtu, pi->link_mode);
-	return 0;
-}
-
-static struct seq_operations l2cap_seq_ops = {
-	.start	= l2cap_seq_start,
-	.next	= l2cap_seq_next,
-	.stop	= l2cap_seq_stop,
-	.show	= l2cap_seq_show 
-};
-
-static int l2cap_seq_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &l2cap_seq_ops);
-}
-
-static struct file_operations l2cap_seq_fops = {
-	.owner		= THIS_MODULE,
-	.open		= l2cap_seq_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-static int __init l2cap_proc_init(void)
-{
-	struct proc_dir_entry *p = create_proc_entry("l2cap", S_IRUGO, proc_bt);
-	if (!p)
-		return -ENOMEM;
-	p->owner     = THIS_MODULE;
-	p->proc_fops = &l2cap_seq_fops;
-	return 0;
-}
-
-static void __exit l2cap_proc_cleanup(void)
-{
-	remove_proc_entry("l2cap", proc_bt);
-}
-
-#else /* CONFIG_PROC_FS */
-
-static int __init l2cap_proc_init(void)
-{
-	return 0;
-}
-
-static void __exit l2cap_proc_cleanup(void)
-{
-	return;
-}
-#endif /* CONFIG_PROC_FS */
+static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL);
 
 static struct proto_ops l2cap_sock_ops = {
 	.family		= PF_BLUETOOTH,
@@ -2266,7 +2200,7 @@
 static int __init l2cap_init(void)
 {
 	int err;
-	
+
 	err = proto_register(&l2cap_proto, 0);
 	if (err < 0)
 		return err;
@@ -2284,7 +2218,7 @@
 		goto error;
 	}
 
-	l2cap_proc_init();
+	class_create_file(&bt_class, &class_attr_l2cap);
 
 	BT_INFO("L2CAP ver %s", VERSION);
 	BT_INFO("L2CAP socket layer initialized");
@@ -2298,7 +2232,7 @@
 
 static void __exit l2cap_exit(void)
 {
-	l2cap_proc_cleanup();
+	class_remove_file(&bt_class, &class_attr_l2cap);
 
 	if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
 		BT_ERR("L2CAP socket unregistration failed");
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index c3d56ea..0d89d64 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -35,9 +35,8 @@
 #include <linux/signal.h>
 #include <linux/init.h>
 #include <linux/wait.h>
+#include <linux/device.h>
 #include <linux/net.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
@@ -47,17 +46,13 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
-#define VERSION "1.5"
+#define VERSION "1.6"
 
 #ifndef CONFIG_BT_RFCOMM_DEBUG
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
 
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_bt_rfcomm;
-#endif
-
 static struct task_struct *rfcomm_thread;
 
 static DECLARE_MUTEX(rfcomm_sem);
@@ -2001,117 +1996,32 @@
 	.encrypt_cfm	= rfcomm_encrypt_cfm
 };
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf)
 {
 	struct rfcomm_session *s;
 	struct list_head *pp, *p;
-	loff_t l = *pos;
+	char *str = buf;
 
 	rfcomm_lock();
 
 	list_for_each(p, &session_list) {
 		s = list_entry(p, struct rfcomm_session, list);
-		list_for_each(pp, &s->dlcs)
-			if (!l--) {
-				seq->private = s;
-				return pp;
-			}
-	}
-	return NULL;
-}
+		list_for_each(pp, &s->dlcs) {
+			struct sock *sk = s->sock->sk;
+			struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list);
 
-static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-	struct rfcomm_session *s = seq->private;
-	struct list_head *pp, *p = e;
-	(*pos)++;
-
-	if (p->next != &s->dlcs)
-		return p->next;
-
-	list_for_each(p, &session_list) {
-		s = list_entry(p, struct rfcomm_session, list);
-		__list_for_each(pp, &s->dlcs) {
-			seq->private = s;
-			return pp;
+			str += sprintf(str, "%s %s %ld %d %d %d %d\n",
+					batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+					d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
 		}
 	}
-	return NULL;
-}
 
-static void rfcomm_seq_stop(struct seq_file *seq, void *e)
-{
 	rfcomm_unlock();
+
+	return (str - buf);
 }
 
-static int  rfcomm_seq_show(struct seq_file *seq, void *e)
-{
-	struct rfcomm_session *s = seq->private;
-	struct sock *sk = s->sock->sk;
-	struct rfcomm_dlc *d = list_entry(e, struct rfcomm_dlc, list);
-
-	seq_printf(seq, "%s %s %ld %d %d %d %d\n",
-			batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
-			d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
-	return 0;
-}
-
-static struct seq_operations rfcomm_seq_ops = {
-	.start  = rfcomm_seq_start,
-	.next   = rfcomm_seq_next,
-	.stop   = rfcomm_seq_stop,
-	.show   = rfcomm_seq_show 
-};
-
-static int rfcomm_seq_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &rfcomm_seq_ops);
-}
-
-static struct file_operations rfcomm_seq_fops = {
-	.owner	 = THIS_MODULE,
-	.open    = rfcomm_seq_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release,
-};
-
-static int  __init rfcomm_proc_init(void)
-{
-        struct proc_dir_entry *p;
-
-	proc_bt_rfcomm = proc_mkdir("rfcomm", proc_bt);
-	if (proc_bt_rfcomm) {
-		proc_bt_rfcomm->owner = THIS_MODULE;
-
-        	p = create_proc_entry("dlc", S_IRUGO, proc_bt_rfcomm);
-		if (p)
-        		p->proc_fops = &rfcomm_seq_fops;
-	}
-        return 0;
-}
-
-static void __exit rfcomm_proc_cleanup(void)
-{
-        remove_proc_entry("dlc", proc_bt_rfcomm);
-
-	remove_proc_entry("rfcomm", proc_bt);
-}
-
-#else /* CONFIG_PROC_FS */
-
-static int  __init rfcomm_proc_init(void)
-{
-        return 0;
-}
-
-static void __exit rfcomm_proc_cleanup(void)
-{
-        return;
-}
-#endif /* CONFIG_PROC_FS */
+static CLASS_ATTR(rfcomm_dlc, S_IRUGO, rfcomm_dlc_sysfs_show, NULL);
 
 /* ---- Initialization ---- */
 static int __init rfcomm_init(void)
@@ -2122,9 +2032,7 @@
 
 	kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
 
-	BT_INFO("RFCOMM ver %s", VERSION);
-
-	rfcomm_proc_init();
+	class_create_file(&bt_class, &class_attr_rfcomm_dlc);
 
 	rfcomm_init_sockets();
 
@@ -2132,11 +2040,15 @@
 	rfcomm_init_ttys();
 #endif
 
+	BT_INFO("RFCOMM ver %s", VERSION);
+
 	return 0;
 }
 
 static void __exit rfcomm_exit(void)
 {
+	class_remove_file(&bt_class, &class_attr_rfcomm_dlc);
+
 	hci_unregister_cb(&rfcomm_cb);
 
 	/* Terminate working thread.
@@ -2153,8 +2065,6 @@
 #endif
 
 	rfcomm_cleanup_sockets();
-
-	rfcomm_proc_cleanup();
 }
 
 module_init(rfcomm_init);
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index a2b30f0..6c34261 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -42,8 +42,7 @@
 #include <linux/socket.h>
 #include <linux/skbuff.h>
 #include <linux/list.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
+#include <linux/device.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
@@ -887,89 +886,26 @@
 	return result;
 }
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf)
 {
 	struct sock *sk;
 	struct hlist_node *node;
-	loff_t l = *pos;
+	char *str = buf;
 
 	read_lock_bh(&rfcomm_sk_list.lock);
 
-	sk_for_each(sk, node, &rfcomm_sk_list.head)
-		if (!l--)
-			return sk;
-	return NULL;
-}
+	sk_for_each(sk, node, &rfcomm_sk_list.head) {
+		str += sprintf(str, "%s %s %d %d\n",
+				batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+				sk->sk_state, rfcomm_pi(sk)->channel);
+	}
 
-static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-	struct sock *sk = e;
-	(*pos)++;
-	return sk_next(sk);
-}
-
-static void rfcomm_seq_stop(struct seq_file *seq, void *e)
-{
 	read_unlock_bh(&rfcomm_sk_list.lock);
+
+	return (str - buf);
 }
 
-static int  rfcomm_seq_show(struct seq_file *seq, void *e)
-{
-	struct sock *sk = e;
-	seq_printf(seq, "%s %s %d %d\n",
-			batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
-			sk->sk_state, rfcomm_pi(sk)->channel);
-	return 0;
-}
-
-static struct seq_operations rfcomm_seq_ops = {
-	.start  = rfcomm_seq_start,
-	.next   = rfcomm_seq_next,
-	.stop   = rfcomm_seq_stop,
-	.show   = rfcomm_seq_show 
-};
-
-static int rfcomm_seq_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &rfcomm_seq_ops);
-}
-
-static struct file_operations rfcomm_seq_fops = {
-	.owner	 = THIS_MODULE,
-	.open    = rfcomm_seq_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release,
-};
-
-static int  __init rfcomm_sock_proc_init(void)
-{
-        struct proc_dir_entry *p = create_proc_entry("sock", S_IRUGO, proc_bt_rfcomm);
-        if (!p)
-                return -ENOMEM;
-        p->proc_fops = &rfcomm_seq_fops;
-        return 0;
-}
-
-static void __exit rfcomm_sock_proc_cleanup(void)
-{
-        remove_proc_entry("sock", proc_bt_rfcomm);
-}
-
-#else /* CONFIG_PROC_FS */
-
-static int  __init rfcomm_sock_proc_init(void)
-{
-        return 0;
-}
-
-static void __exit rfcomm_sock_proc_cleanup(void)
-{
-        return;
-}
-#endif /* CONFIG_PROC_FS */
+static CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL);
 
 static struct proto_ops rfcomm_sock_ops = {
 	.family		= PF_BLUETOOTH,
@@ -997,7 +933,7 @@
 	.create		= rfcomm_sock_create
 };
 
-int  __init rfcomm_init_sockets(void)
+int __init rfcomm_init_sockets(void)
 {
 	int err;
 
@@ -1009,7 +945,7 @@
 	if (err < 0)
 		goto error;
 
-	rfcomm_sock_proc_init();
+	class_create_file(&bt_class, &class_attr_rfcomm);
 
 	BT_INFO("RFCOMM socket layer initialized");
 
@@ -1023,7 +959,7 @@
 
 void __exit rfcomm_cleanup_sockets(void)
 {
-	rfcomm_sock_proc_cleanup();
+	class_remove_file(&bt_class, &class_attr_rfcomm);
 
 	if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
 		BT_ERR("RFCOMM socket layer unregistration failed");
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 997e42d..9cb00dc 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -38,8 +38,7 @@
 #include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
+#include <linux/device.h>
 #include <linux/list.h>
 #include <net/sock.h>
 
@@ -55,7 +54,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "0.4"
+#define VERSION "0.5"
 
 static struct proto_ops sco_sock_ops;
 
@@ -893,91 +892,26 @@
 	return 0;
 }
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *sco_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t sco_sysfs_show(struct class *dev, char *buf)
 {
 	struct sock *sk;
 	struct hlist_node *node;
-	loff_t l = *pos;
+	char *str = buf;
 
 	read_lock_bh(&sco_sk_list.lock);
 
-	sk_for_each(sk, node, &sco_sk_list.head)
-		if (!l--)
-			goto found;
-	sk = NULL;
-found:
-	return sk;
-}
+	sk_for_each(sk, node, &sco_sk_list.head) {
+		str += sprintf(str, "%s %s %d\n",
+				batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+				sk->sk_state);
+	}
 
-static void *sco_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-	struct sock *sk = e;
-	(*pos)++;
-	return sk_next(sk);
-}
-
-static void sco_seq_stop(struct seq_file *seq, void *e)
-{
 	read_unlock_bh(&sco_sk_list.lock);
+
+	return (str - buf);
 }
 
-static int  sco_seq_show(struct seq_file *seq, void *e)
-{
-	struct sock *sk = e;
-	seq_printf(seq, "%s %s %d\n",
-			batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state);
-	return 0;
-}
-
-static struct seq_operations sco_seq_ops = {
-	.start	= sco_seq_start,
-	.next	= sco_seq_next,
-	.stop	= sco_seq_stop,
-	.show	= sco_seq_show 
-};
-
-static int sco_seq_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &sco_seq_ops);
-}
-
-static struct file_operations sco_seq_fops = {
-	.owner		= THIS_MODULE,
-	.open		= sco_seq_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-static int __init sco_proc_init(void)
-{
-	struct proc_dir_entry *p = create_proc_entry("sco", S_IRUGO, proc_bt);
-	if (!p)
-		return -ENOMEM;
-	p->owner     = THIS_MODULE;
-	p->proc_fops = &sco_seq_fops;
-	return 0;
-}
-
-static void __exit sco_proc_cleanup(void)
-{
-	remove_proc_entry("sco", proc_bt);
-}
-
-#else /* CONFIG_PROC_FS */
-
-static int __init sco_proc_init(void)
-{
-	return 0;
-}
-
-static void __exit sco_proc_cleanup(void)
-{
-	return;
-}
-#endif /* CONFIG_PROC_FS */
+static CLASS_ATTR(sco, S_IRUGO, sco_sysfs_show, NULL);
 
 static struct proto_ops sco_sock_ops = {
 	.family		= PF_BLUETOOTH,
@@ -1035,7 +969,7 @@
 		goto error;
 	}
 
-	sco_proc_init();
+	class_create_file(&bt_class, &class_attr_sco);
 
 	BT_INFO("SCO (Voice Link) ver %s", VERSION);
 	BT_INFO("SCO socket layer initialized");
@@ -1049,7 +983,7 @@
 
 static void __exit sco_exit(void)
 {
-	sco_proc_cleanup();
+	class_remove_file(&bt_class, &class_attr_sco);
 
 	if (bt_sock_unregister(BTPROTO_SCO) < 0)
 		BT_ERR("SCO socket unregistration failed");
diff --git a/net/core/datagram.c b/net/core/datagram.c
index d219435..1bcfef5 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -350,6 +350,20 @@
 	return -EFAULT;
 }
 
+unsigned int __skb_checksum_complete(struct sk_buff *skb)
+{
+	unsigned int sum;
+
+	sum = (u16)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
+	if (likely(!sum)) {
+		if (unlikely(skb->ip_summed == CHECKSUM_HW))
+			netdev_rx_csum_fault(skb->dev);
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	}
+	return sum;
+}
+EXPORT_SYMBOL(__skb_checksum_complete);
+
 /**
  *	skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec.
  *	@skb: skbuff
@@ -363,7 +377,7 @@
  *		 -EFAULT - fault during copy. Beware, in this case iovec
  *			   can be modified!
  */
-int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb,
+int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
 				     int hlen, struct iovec *iov)
 {
 	unsigned int csum;
@@ -376,8 +390,7 @@
 		iov++;
 
 	if (iov->iov_len < chunk) {
-		if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk + hlen,
-							   skb->csum)))
+		if (__skb_checksum_complete(skb))
 			goto csum_error;
 		if (skb_copy_datagram_iovec(skb, hlen, iov, chunk))
 			goto fault;
@@ -388,6 +401,8 @@
 			goto fault;
 		if ((unsigned short)csum_fold(csum))
 			goto csum_error;
+		if (unlikely(skb->ip_summed == CHECKSUM_HW))
+			netdev_rx_csum_fault(skb->dev);
 		iov->iov_len -= chunk;
 		iov->iov_base += chunk;
 	}
diff --git a/net/core/dev.c b/net/core/dev.c
index 8d15415..0b48e29 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1108,6 +1108,18 @@
 	return ret;
 }
 
+/* Take action when hardware reception checksum errors are detected. */
+#ifdef CONFIG_BUG
+void netdev_rx_csum_fault(struct net_device *dev)
+{
+	if (net_ratelimit()) {
+		printk(KERN_ERR "%s: hw csum failure.\n", dev->name);
+		dump_stack();
+	}
+}
+EXPORT_SYMBOL(netdev_rx_csum_fault);
+#endif
+
 #ifdef CONFIG_HIGHMEM
 /* Actually, we should eliminate this check as soon as we know, that:
  * 1. IOMMU is present and allows to map all the memory.
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index db098ff..cb530ee 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -194,8 +194,7 @@
 
 done:
 	spin_unlock_bh(&dev->xmit_lock);
-	if (dmi1)
-		kfree(dmi1);
+	kfree(dmi1);
 	return err;
 }
 
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 802fe11..49424a4 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -101,16 +101,20 @@
 static int checksum_udp(struct sk_buff *skb, struct udphdr *uh,
 			     unsigned short ulen, u32 saddr, u32 daddr)
 {
-	if (uh->check == 0)
+	unsigned int psum;
+
+	if (uh->check == 0 || skb->ip_summed == CHECKSUM_UNNECESSARY)
 		return 0;
 
-	if (skb->ip_summed == CHECKSUM_HW)
-		return csum_tcpudp_magic(
-			saddr, daddr, ulen, IPPROTO_UDP, skb->csum);
+	psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
 
-	skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
+	if (skb->ip_summed == CHECKSUM_HW &&
+	    !(u16)csum_fold(csum_add(psum, skb->csum)))
+		return 0;
 
-	return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
+	skb->csum = psum;
+
+	return __skb_checksum_complete(skb);
 }
 
 /*
@@ -489,7 +493,7 @@
 
 	if (ulen != len)
 		goto out;
-	if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0)
+	if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
 		goto out;
 	if (np->local_ip && np->local_ip != ntohl(iph->daddr))
 		goto out;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 9bed756..8700379 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -49,6 +49,7 @@
 #include <net/udp.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
+#include <net/netlink.h>
 
 DECLARE_MUTEX(rtnl_sem);
 
@@ -462,11 +463,6 @@
 	netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_KERNEL);
 }
 
-static int rtnetlink_done(struct netlink_callback *cb)
-{
-	return 0;
-}
-
 /* Protected by RTNL sempahore.  */
 static struct rtattr **rta_buf;
 static int rtattr_max;
@@ -524,8 +520,6 @@
 	}
 
 	if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
-		u32 rlen;
-
 		if (link->dumpit == NULL)
 			link = &(rtnetlink_links[PF_UNSPEC][type]);
 
@@ -533,14 +527,11 @@
 			goto err_inval;
 
 		if ((*errp = netlink_dump_start(rtnl, skb, nlh,
-						link->dumpit,
-						rtnetlink_done)) != 0) {
+						link->dumpit, NULL)) != 0) {
 			return -1;
 		}
-		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-		if (rlen > skb->len)
-			rlen = skb->len;
-		skb_pull(skb, rlen);
+
+		netlink_queue_skip(nlh, skb);
 		return -1;
 	}
 
@@ -579,75 +570,13 @@
 	return -1;
 }
 
-/* 
- * Process one packet of messages.
- * Malformed skbs with wrong lengths of messages are discarded silently.
- */
-
-static inline int rtnetlink_rcv_skb(struct sk_buff *skb)
-{
-	int err;
-	struct nlmsghdr * nlh;
-
-	while (skb->len >= NLMSG_SPACE(0)) {
-		u32 rlen;
-
-		nlh = (struct nlmsghdr *)skb->data;
-		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
-			return 0;
-		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-		if (rlen > skb->len)
-			rlen = skb->len;
-		if (rtnetlink_rcv_msg(skb, nlh, &err)) {
-			/* Not error, but we must interrupt processing here:
-			 *   Note, that in this case we do not pull message
-			 *   from skb, it will be processed later.
-			 */
-			if (err == 0)
-				return -1;
-			netlink_ack(skb, nlh, err);
-		} else if (nlh->nlmsg_flags&NLM_F_ACK)
-			netlink_ack(skb, nlh, 0);
-		skb_pull(skb, rlen);
-	}
-
-	return 0;
-}
-
-/*
- *  rtnetlink input queue processing routine:
- *	- process as much as there was in the queue upon entry.
- *	- feed skbs to rtnetlink_rcv_skb, until it refuse a message,
- *	  that will occur, when a dump started.
- */
-
 static void rtnetlink_rcv(struct sock *sk, int len)
 {
-	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
+	unsigned int qlen = 0;
 
 	do {
-		struct sk_buff *skb;
-
 		rtnl_lock();
-
-		if (qlen > skb_queue_len(&sk->sk_receive_queue))
-			qlen = skb_queue_len(&sk->sk_receive_queue);
-
-		for (; qlen; qlen--) {
-			skb = skb_dequeue(&sk->sk_receive_queue);
-			if (rtnetlink_rcv_skb(skb)) {
-				if (skb->len)
-					skb_queue_head(&sk->sk_receive_queue,
-						       skb);
-				else {
-					kfree_skb(skb);
-					qlen--;
-				}
-				break;
-			}
-			kfree_skb(skb);
-		}
-
+		netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg);
 		up(&rtnl_sem);
 
 		netdev_run_todo();
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 95501e4..b7d13a4 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -336,6 +336,9 @@
 	}
 #ifdef CONFIG_NETFILTER
 	nf_conntrack_put(skb->nfct);
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	nf_conntrack_put_reasm(skb->nfct_reasm);
+#endif
 #ifdef CONFIG_BRIDGE_NETFILTER
 	nf_bridge_put(skb->nf_bridge);
 #endif
@@ -414,9 +417,17 @@
 	C(nfct);
 	nf_conntrack_get(skb->nfct);
 	C(nfctinfo);
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	C(nfct_reasm);
+	nf_conntrack_get_reasm(skb->nfct_reasm);
+#endif
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
 	C(ipvs_property);
 #endif
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	C(nfct_reasm);
+	nf_conntrack_get_reasm(skb->nfct_reasm);
+#endif
 #ifdef CONFIG_BRIDGE_NETFILTER
 	C(nf_bridge);
 	nf_bridge_get(skb->nf_bridge);
@@ -474,6 +485,10 @@
 	new->nfct	= old->nfct;
 	nf_conntrack_get(old->nfct);
 	new->nfctinfo	= old->nfctinfo;
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	new->nfct_reasm = old->nfct_reasm;
+	nf_conntrack_get_reasm(old->nfct_reasm);
+#endif
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
 	new->ipvs_property = old->ipvs_property;
 #endif
diff --git a/net/core/sock.c b/net/core/sock.c
index 9602ceb..13cc3be 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1242,8 +1242,7 @@
 
 static void sock_def_destruct(struct sock *sk)
 {
-	if (sk->sk_protinfo)
-		kfree(sk->sk_protinfo);
+	kfree(sk->sk_protinfo);
 }
 
 void sk_send_sigurg(struct sock *sk)
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 4b9bc81..ca03521 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -1263,10 +1263,8 @@
 	if (inet_csk(sk)->icsk_bind_hash != NULL)
 		inet_put_port(&dccp_hashinfo, sk);
 
-	if (dp->dccps_service_list != NULL) {
-		kfree(dp->dccps_service_list);
-		dp->dccps_service_list = NULL;
-	}
+	kfree(dp->dccps_service_list);
+	dp->dccps_service_list = NULL;
 
 	ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
 	ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index a021c34..e0ace7c 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -238,8 +238,7 @@
 	lock_sock(sk);
 	dp->dccps_service = service;
 
-	if (dp->dccps_service_list != NULL)
-		kfree(dp->dccps_service_list);
+	kfree(dp->dccps_service_list);
 
 	dp->dccps_service_list = sl;
 	release_sock(sk);
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 3f25cad..f89e55f 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1664,17 +1664,15 @@
 		goto out;
 	}
 
+	if (sk->sk_shutdown & RCV_SHUTDOWN) {
+		rv = 0;
+		goto out;
+	}
+
 	rv = dn_check_state(sk, NULL, 0, &timeo, flags);
 	if (rv)
 		goto out;
 
-	if (sk->sk_shutdown & RCV_SHUTDOWN) {
-		if (!(flags & MSG_NOSIGNAL))
-			send_sig(SIGPIPE, current, 0);
-		rv = -EPIPE;
-		goto out;
-	}
-
 	if (flags & ~(MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) {
 		rv = -EOPNOTSUPP;
 		goto out;
@@ -1928,6 +1926,8 @@
 
 	if (sk->sk_shutdown & SEND_SHUTDOWN) {
 		err = -EPIPE;
+		if (!(flags & MSG_NOSIGNAL))
+			send_sig(SIGPIPE, current, 0);
 		goto out_err;
 	}
 
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index eeba56f..6f8b565 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -784,16 +784,14 @@
 
 static void dn_fib_del_tree(int n)
 {
-        struct dn_fib_table *t;
+	struct dn_fib_table *t;
 
-        write_lock(&dn_fib_tables_lock);
-        t = dn_fib_tables[n];
-        dn_fib_tables[n] = NULL;
-        write_unlock(&dn_fib_tables_lock);
+	write_lock(&dn_fib_tables_lock);
+	t = dn_fib_tables[n];
+	dn_fib_tables[n] = NULL;
+	write_unlock(&dn_fib_tables_lock);
 
-        if (t) {
-                kfree(t);
-        }
+	kfree(t);
 }
 
 struct dn_fib_table *dn_fib_empty_table(void)
diff --git a/net/ethernet/pe2.c b/net/ethernet/pe2.c
index 98a494b..9d57b4f 100644
--- a/net/ethernet/pe2.c
+++ b/net/ethernet/pe2.c
@@ -32,8 +32,7 @@
 
 void destroy_EII_client(struct datalink_proto *dl)
 {
-	if (dl)
-		kfree(dl);
+	kfree(dl);
 }
 
 EXPORT_SYMBOL(destroy_EII_client);
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
index 20cc580..ecc9bb1 100644
--- a/net/ieee80211/ieee80211_crypt.c
+++ b/net/ieee80211/ieee80211_crypt.c
@@ -11,15 +11,14 @@
  *
  */
 
-#include <linux/config.h>
+#include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <asm/string.h>
-#include <asm/errno.h>
-
+#include <linux/string.h>
 #include <net/ieee80211.h>
 
+
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("HostAP crypto");
 MODULE_LICENSE("GPL");
@@ -29,32 +28,20 @@
 	struct ieee80211_crypto_ops *ops;
 };
 
-struct ieee80211_crypto {
-	struct list_head algs;
-	spinlock_t lock;
-};
-
-static struct ieee80211_crypto *hcrypt;
+static LIST_HEAD(ieee80211_crypto_algs);
+static DEFINE_SPINLOCK(ieee80211_crypto_lock);
 
 void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
 {
-	struct list_head *ptr, *n;
-	struct ieee80211_crypt_data *entry;
+ 	struct ieee80211_crypt_data *entry, *next;
 	unsigned long flags;
 
 	spin_lock_irqsave(&ieee->lock, flags);
-
-	if (list_empty(&ieee->crypt_deinit_list))
-		goto unlock;
-
-	for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
-	     ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
-		entry = list_entry(ptr, struct ieee80211_crypt_data, list);
-
+ 	list_for_each_entry_safe(entry, next, &ieee->crypt_deinit_list, list) {
 		if (atomic_read(&entry->refcnt) != 0 && !force)
 			continue;
 
-		list_del(ptr);
+		list_del(&entry->list);
 
 		if (entry->ops) {
 			entry->ops->deinit(entry->priv);
@@ -62,7 +49,6 @@
 		}
 		kfree(entry);
 	}
-      unlock:
 	spin_unlock_irqrestore(&ieee->lock, flags);
 }
 
@@ -125,9 +111,6 @@
 	unsigned long flags;
 	struct ieee80211_crypto_alg *alg;
 
-	if (hcrypt == NULL)
-		return -1;
-
 	alg = kmalloc(sizeof(*alg), GFP_KERNEL);
 	if (alg == NULL)
 		return -ENOMEM;
@@ -135,9 +118,9 @@
 	memset(alg, 0, sizeof(*alg));
 	alg->ops = ops;
 
-	spin_lock_irqsave(&hcrypt->lock, flags);
-	list_add(&alg->list, &hcrypt->algs);
-	spin_unlock_irqrestore(&hcrypt->lock, flags);
+	spin_lock_irqsave(&ieee80211_crypto_lock, flags);
+	list_add(&alg->list, &ieee80211_crypto_algs);
+	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
 
 	printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n",
 	       ops->name);
@@ -147,64 +130,49 @@
 
 int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops)
 {
+	struct ieee80211_crypto_alg *alg;
 	unsigned long flags;
-	struct list_head *ptr;
-	struct ieee80211_crypto_alg *del_alg = NULL;
 
-	if (hcrypt == NULL)
-		return -1;
-
-	spin_lock_irqsave(&hcrypt->lock, flags);
-	for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
-		struct ieee80211_crypto_alg *alg =
-		    (struct ieee80211_crypto_alg *)ptr;
-		if (alg->ops == ops) {
-			list_del(&alg->list);
-			del_alg = alg;
-			break;
-		}
+	spin_lock_irqsave(&ieee80211_crypto_lock, flags);
+	list_for_each_entry(alg, &ieee80211_crypto_algs, list) {
+		if (alg->ops == ops)
+			goto found;
 	}
-	spin_unlock_irqrestore(&hcrypt->lock, flags);
+	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
+	return -EINVAL;
 
-	if (del_alg) {
-		printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
-		       "'%s'\n", ops->name);
-		kfree(del_alg);
-	}
-
-	return del_alg ? 0 : -1;
+ found:
+	printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
+			  "'%s'\n", ops->name);
+	list_del(&alg->list);
+	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
+	kfree(alg);
+	return 0;
 }
 
 struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name)
 {
+	struct ieee80211_crypto_alg *alg;
 	unsigned long flags;
-	struct list_head *ptr;
-	struct ieee80211_crypto_alg *found_alg = NULL;
 
-	if (hcrypt == NULL)
-		return NULL;
-
-	spin_lock_irqsave(&hcrypt->lock, flags);
-	for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
-		struct ieee80211_crypto_alg *alg =
-		    (struct ieee80211_crypto_alg *)ptr;
-		if (strcmp(alg->ops->name, name) == 0) {
-			found_alg = alg;
-			break;
-		}
+	spin_lock_irqsave(&ieee80211_crypto_lock, flags);
+	list_for_each_entry(alg, &ieee80211_crypto_algs, list) {
+		if (strcmp(alg->ops->name, name) == 0)
+			goto found;
 	}
-	spin_unlock_irqrestore(&hcrypt->lock, flags);
+	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
+	return NULL;
 
-	if (found_alg)
-		return found_alg->ops;
-	else
-		return NULL;
+ found:
+	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
+	return alg->ops;
 }
 
 static void *ieee80211_crypt_null_init(int keyidx)
 {
 	return (void *)1;
 }
+
 static void ieee80211_crypt_null_deinit(void *priv)
 {
 }
@@ -213,56 +181,18 @@
 	.name = "NULL",
 	.init = ieee80211_crypt_null_init,
 	.deinit = ieee80211_crypt_null_deinit,
-	.encrypt_mpdu = NULL,
-	.decrypt_mpdu = NULL,
-	.encrypt_msdu = NULL,
-	.decrypt_msdu = NULL,
-	.set_key = NULL,
-	.get_key = NULL,
-	.extra_mpdu_prefix_len = 0,
-	.extra_mpdu_postfix_len = 0,
 	.owner = THIS_MODULE,
 };
 
 static int __init ieee80211_crypto_init(void)
 {
-	int ret = -ENOMEM;
-
-	hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL);
-	if (!hcrypt)
-		goto out;
-
-	memset(hcrypt, 0, sizeof(*hcrypt));
-	INIT_LIST_HEAD(&hcrypt->algs);
-	spin_lock_init(&hcrypt->lock);
-
-	ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null);
-	if (ret < 0) {
-		kfree(hcrypt);
-		hcrypt = NULL;
-	}
-      out:
-	return ret;
+	return ieee80211_register_crypto_ops(&ieee80211_crypt_null);
 }
 
 static void __exit ieee80211_crypto_deinit(void)
 {
-	struct list_head *ptr, *n;
-
-	if (hcrypt == NULL)
-		return;
-
-	for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
-	     ptr = n, n = ptr->next) {
-		struct ieee80211_crypto_alg *alg =
-		    (struct ieee80211_crypto_alg *)ptr;
-		list_del(ptr);
-		printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
-		       "'%s' (deinit)\n", alg->ops->name);
-		kfree(alg);
-	}
-
-	kfree(hcrypt);
+	ieee80211_unregister_crypto_ops(&ieee80211_crypt_null);
+	BUG_ON(!list_empty(&ieee80211_crypto_algs));
 }
 
 EXPORT_SYMBOL(ieee80211_crypt_deinit_entries);
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 6ad8821..03efaac 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -369,6 +369,7 @@
 	/* Put this code here so that we avoid duplicating it in all
 	 * Rx paths. - Jean II */
 #ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
+#ifdef CONFIG_NET_RADIO
 	/* If spy monitoring on */
 	if (ieee->spy_data.spy_number > 0) {
 		struct iw_quality wstats;
@@ -395,6 +396,7 @@
 		/* Update spy records */
 		wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
 	}
+#endif				/* CONFIG_NET_RADIO */
 #endif				/* IW_WIRELESS_SPY */
 
 #ifdef NOT_YET
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 1ce7af9..181755f 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -161,9 +161,11 @@
 			     (ieee->perfect_rssi - ieee->worst_rssi) -
 			     (ieee->perfect_rssi - network->stats.rssi) *
 			     (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
-			      62 * (ieee->perfect_rssi - network->stats.rssi))) /
-			    ((ieee->perfect_rssi - ieee->worst_rssi) *
-			     (ieee->perfect_rssi - ieee->worst_rssi));
+			      62 * (ieee->perfect_rssi -
+				    network->stats.rssi))) /
+			    ((ieee->perfect_rssi -
+			      ieee->worst_rssi) * (ieee->perfect_rssi -
+						   ieee->worst_rssi));
 		if (iwe.u.qual.qual > 100)
 			iwe.u.qual.qual = 100;
 		else if (iwe.u.qual.qual < 1)
@@ -520,7 +522,8 @@
 		crypt = &ieee->crypt[idx];
 		group_key = 1;
 	} else {
-		if (idx != 0)
+		/* some Cisco APs use idx>0 for unicast in dynamic WEP */
+		if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
 			return -EINVAL;
 		if (ieee->iw_mode == IW_MODE_INFRA)
 			crypt = &ieee->crypt[idx];
@@ -688,7 +691,8 @@
 	} else
 		idx = ieee->tx_keyidx;
 
-	if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+	if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
+	    ext->alg != IW_ENCODE_ALG_WEP)
 		if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
 			return -EINVAL;
 
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index a9d84f9..eaa150c 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -147,8 +147,7 @@
 	BUG_TRAP(!sk->sk_wmem_queued);
 	BUG_TRAP(!sk->sk_forward_alloc);
 
-	if (inet->opt)
-		kfree(inet->opt);
+	kfree(inet->opt);
 	dst_release(sk->sk_dst_cache);
 	sk_refcnt_debug_dec(sk);
 }
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 990633c..2267c1f 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -266,8 +266,7 @@
 				if (tb)
 					err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
 			}
-			if (rta.rta_mx)
-				kfree(rta.rta_mx);
+			kfree(rta.rta_mx);
 		}
 		rtnl_unlock();
 		return err;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 175e093..e3eceec 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -934,11 +934,11 @@
 	case CHECKSUM_HW:
 		if (!(u16)csum_fold(skb->csum))
 			break;
-		LIMIT_NETDEBUG(KERN_DEBUG "icmp v4 hw csum failure\n");
+		/* fall through */
 	case CHECKSUM_NONE:
-		if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))
+		skb->csum = 0;
+		if (__skb_checksum_complete(skb))
 			goto error;
-	default:;
 	}
 
 	if (!pskb_pull(skb, sizeof(struct icmphdr)))
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index c6247fc..c04607b 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -872,11 +872,18 @@
 		return 0;
 	}
 
-	if (!pskb_may_pull(skb, sizeof(struct igmphdr)) || 
-	    (u16)csum_fold(skb_checksum(skb, 0, len, 0))) {
-		in_dev_put(in_dev);
-		kfree_skb(skb);
-		return 0;
+	if (!pskb_may_pull(skb, sizeof(struct igmphdr)))
+		goto drop;
+
+	switch (skb->ip_summed) {
+	case CHECKSUM_HW:
+		if (!(u16)csum_fold(skb->csum))
+			break;
+		/* fall through */
+	case CHECKSUM_NONE:
+		skb->csum = 0;
+		if (__skb_checksum_complete(skb))
+			goto drop;
 	}
 
 	ih = skb->h.igmph;
@@ -906,6 +913,8 @@
 	default:
 		NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type);
 	}
+
+drop:
 	in_dev_put(in_dev);
 	kfree_skb(skb);
 	return 0;
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 71f3c73..39061ed 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -724,12 +724,6 @@
 	return skb->len;
 }
 
-static int inet_diag_dump_done(struct netlink_callback *cb)
-{
-	return 0;
-}
-
-
 static __inline__ int
 inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
@@ -760,8 +754,7 @@
 				goto err_inval;
 		}
 		return netlink_dump_start(idiagnl, skb, nlh,
-					  inet_diag_dump,
-					  inet_diag_dump_done);
+					  inet_diag_dump, NULL);
 	} else {
 		return inet_diag_get_exact(skb, nlh);
 	}
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 896ce3f..4e9c74b 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -577,15 +577,16 @@
 			goto drop_nolock;
 
 		if (flags&GRE_CSUM) {
-			if (skb->ip_summed == CHECKSUM_HW) {
+			switch (skb->ip_summed) {
+			case CHECKSUM_HW:
 				csum = (u16)csum_fold(skb->csum);
-				if (csum)
-					skb->ip_summed = CHECKSUM_NONE;
-			}
-			if (skb->ip_summed == CHECKSUM_NONE) {
-				skb->csum = skb_checksum(skb, 0, skb->len, 0);
+				if (!csum)
+					break;
+				/* fall through */
+			case CHECKSUM_NONE:
+				skb->csum = 0;
+				csum = __skb_checksum_complete(skb);
 				skb->ip_summed = CHECKSUM_HW;
-				csum = (u16)csum_fold(skb->csum);
 			}
 			offset += 4;
 		}
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index bce4e87..dbe12da 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -510,8 +510,7 @@
 		kfree(opt);
 		return -EINVAL;
 	}
-	if (*optp)
-		kfree(*optp);
+	kfree(*optp);
 	*optp = opt;
 	return 0;
 }
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 1775823..11c2f68 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -353,7 +353,8 @@
 		ip_options_build(skb, opt, inet->daddr, rt, 0);
 	}
 
-	ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs);
+	ip_select_ident_more(iph, &rt->u.dst, sk,
+			     (skb_shinfo(skb)->tso_segs ?: 1) - 1);
 
 	/* Add an IP checksum. */
 	ip_send_check(iph);
@@ -1262,10 +1263,8 @@
 
 out:
 	inet->cork.flags &= ~IPCORK_OPT;
-	if (inet->cork.opt) {
-		kfree(inet->cork.opt);
-		inet->cork.opt = NULL;
-	}
+	kfree(inet->cork.opt);
+	inet->cork.opt = NULL;
 	if (inet->cork.rt) {
 		ip_rt_put(inet->cork.rt);
 		inet->cork.rt = NULL;
@@ -1289,10 +1288,8 @@
 		kfree_skb(skb);
 
 	inet->cork.flags &= ~IPCORK_OPT;
-	if (inet->cork.opt) {
-		kfree(inet->cork.opt);
-		inet->cork.opt = NULL;
-	}
+	kfree(inet->cork.opt);
+	inet->cork.opt = NULL;
 	if (inet->cork.rt) {
 		ip_rt_put(inet->cork.rt);
 		inet->cork.rt = NULL;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 2f0b47d..4f2d872 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -202,8 +202,7 @@
 		if (ra->sk == sk) {
 			if (on) {
 				write_unlock_bh(&ip_ra_lock);
-				if (new_ra)
-					kfree(new_ra);
+				kfree(new_ra);
 				return -EADDRINUSE;
 			}
 			*rap = ra->next;
@@ -446,8 +445,7 @@
 #endif
 			}
 			opt = xchg(&inet->opt, opt);
-			if (opt)
-				kfree(opt);
+			kfree(opt);
 			break;
 		}
 		case IP_PKTINFO:
@@ -828,10 +826,8 @@
 
 			err = ip_mc_msfilter(sk, msf, ifindex);
 mc_msf_out:
-			if (msf)
-				kfree(msf);
-			if (gsf)
-				kfree(gsf);
+			kfree(msf);
+			kfree(gsf);
 			break;
 		}
 		case IP_ROUTER_ALERT:	
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c
index fc6f95a..d7eb680 100644
--- a/net/ipv4/ipvs/ip_vs_app.c
+++ b/net/ipv4/ipvs/ip_vs_app.c
@@ -110,8 +110,7 @@
 	return 0;
 
   out:
-	if (inc->timeout_table)
-		kfree(inc->timeout_table);
+	kfree(inc->timeout_table);
 	kfree(inc);
 	return ret;
 }
@@ -136,8 +135,7 @@
 
 	list_del(&inc->a_list);
 
-	if (inc->timeout_table != NULL)
-		kfree(inc->timeout_table);
+	kfree(inc->timeout_table);
 	kfree(inc);
 }
 
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 981cc32..1a0843c 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -1009,11 +1009,10 @@
 		if (sysctl_ip_vs_expire_nodest_conn) {
 			/* try to expire the connection immediately */
 			ip_vs_conn_expire_now(cp);
-		} else {
-			/* don't restart its timer, and silently
-			   drop the packet. */
-			__ip_vs_conn_put(cp);
 		}
+		/* don't restart its timer, and silently
+		   drop the packet. */
+		__ip_vs_conn_put(cp);
 		return NF_DROP;
 	}
 
diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c
index bd7d75b..d34a9fa 100644
--- a/net/ipv4/multipath_wrandom.c
+++ b/net/ipv4/multipath_wrandom.c
@@ -207,16 +207,12 @@
 			decision = mpc->rt;
 
 		last_power = mpc->power;
-		if (last_mpc)
-			kfree(last_mpc);
-
+		kfree(last_mpc);
 		last_mpc = mpc;
 	}
 
-	if (last_mpc) {
-		/* concurrent __multipath_flush may lead to !last_mpc */
-		kfree(last_mpc);
-	}
+	/* concurrent __multipath_flush may lead to !last_mpc */
+	kfree(last_mpc);
 
 	decision->u.dst.__use++;
 	*rp = decision;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 7d917e4..9d3c8b5 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -5,6 +5,20 @@
 menu "IP: Netfilter Configuration"
 	depends on INET && NETFILTER
 
+config NF_CONNTRACK_IPV4
+	tristate "IPv4 support for new connection tracking (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && NF_CONNTRACK
+	---help---
+	  Connection tracking keeps a record of what packets have passed
+	  through your machine, in order to figure out how they are related
+	  into connections.
+
+	  This is IPv4 support on Layer 3 independent connection tracking.
+	  Layer 3 independent connection tracking is experimental scheme
+	  which generalize ip_conntrack to support other layer 3 protocols.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 # connection tracking, helpers and protocols
 config IP_NF_CONNTRACK
 	tristate "Connection tracking (required for masq/NAT)"
@@ -209,8 +223,8 @@
 	tristate "Packet type match support"
 	depends on IP_NF_IPTABLES
 	help
-         Packet type matching allows you to match a packet by
-         its "class", eg. BROADCAST, MULTICAST, ...
+	  Packet type matching allows you to match a packet by
+	  its "class", eg. BROADCAST, MULTICAST, ...
 
 	  Typical usage:
 	  iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
@@ -317,7 +331,8 @@
 
 config IP_NF_MATCH_HELPER
 	tristate "Helper match support"
-	depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
+	depends on IP_NF_IPTABLES
+	depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
 	help
 	  Helper matching allows you to match packets in dynamic connections
 	  tracked by a conntrack-helper, ie. ip_conntrack_ftp
@@ -326,7 +341,8 @@
 
 config IP_NF_MATCH_STATE
 	tristate "Connection state match support"
-	depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
+	depends on IP_NF_IPTABLES
+	depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
 	help
 	  Connection state matching allows you to match packets based on their
 	  relationship to a tracked connection (ie. previous packets).  This
@@ -336,7 +352,8 @@
 
 config IP_NF_MATCH_CONNTRACK
 	tristate "Connection tracking match support"
-	depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
+	depends on IP_NF_IPTABLES
+	depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
 	help
 	  This is a general conntrack match module, a superset of the state match.
 
@@ -422,7 +439,8 @@
 
 config IP_NF_MATCH_CONNMARK
 	tristate  'Connection mark match support'
-	depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES
+	depends on IP_NF_IPTABLES
+	depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
 	help
 	  This option adds a `connmark' match, which allows you to match the
 	  connection mark value previously set for the session by `CONNMARK'. 
@@ -433,7 +451,8 @@
 
 config IP_NF_MATCH_CONNBYTES
 	tristate  'Connection byte/packet counter match support'
-	depends on IP_NF_CT_ACCT && IP_NF_IPTABLES
+	depends on IP_NF_IPTABLES
+	depends on IP_NF_CT_ACCT || (NF_CT_ACCT && NF_CONNTRACK_IPV4)
 	help
 	  This option adds a `connbytes' match, which allows you to match the
 	  number of bytes and/or packets for each direction within a connection.
@@ -747,7 +766,8 @@
 
 config IP_NF_TARGET_CONNMARK
 	tristate  'CONNMARK target support'
-	depends on IP_NF_CONNTRACK_MARK && IP_NF_MANGLE
+	depends on IP_NF_MANGLE
+	depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
 	help
 	  This option adds a `CONNMARK' target, which allows one to manipulate
 	  the connection mark value.  Similar to the MARK target, but
@@ -759,7 +779,8 @@
 
 config IP_NF_TARGET_CLUSTERIP
 	tristate "CLUSTERIP target support (EXPERIMENTAL)"
-	depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES && EXPERIMENTAL
+	depends on IP_NF_IPTABLES && EXPERIMENTAL
+	depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
 	help
 	  The CLUSTERIP target allows you to build load-balancing clusters of
 	  network servers without having a dedicated load-balancing
@@ -782,7 +803,7 @@
 config IP_NF_TARGET_NOTRACK
 	tristate  'NOTRACK target support'
 	depends on IP_NF_RAW
-	depends on IP_NF_CONNTRACK
+	depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
 	help
 	  The NOTRACK target allows a select rule to specify
 	  which packets *not* to enter the conntrack/NAT
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index dab4b58..058c48e 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -103,3 +103,9 @@
 obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
 
 obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
+
+# objects for l3 independent conntrack
+nf_conntrack_ipv4-objs  :=  nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
+
+# l3 independent conntrack
+obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 82a6504..d2a4fec 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -28,11 +28,8 @@
 #include <linux/netlink.h>
 #include <linux/spinlock.h>
 #include <linux/notifier.h>
-#include <linux/rtnetlink.h>
 
 #include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
@@ -58,14 +55,17 @@
 			    const struct ip_conntrack_tuple *tuple)
 {
 	struct ip_conntrack_protocol *proto;
+	int ret = 0;
 
 	NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
 
 	proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
-	if (proto && proto->tuple_to_nfattr)
-		return proto->tuple_to_nfattr(skb, tuple);
+	if (likely(proto && proto->tuple_to_nfattr)) {
+		ret = proto->tuple_to_nfattr(skb, tuple);
+		ip_conntrack_proto_put(proto);
+	}
 
-	return 0;
+	return ret;
 
 nfattr_failure:
 	return -1;
@@ -175,7 +175,7 @@
 {
 	enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
 	struct nfattr *nest_count = NFA_NEST(skb, type);
-	u_int64_t tmp;
+	u_int32_t tmp;
 
 	tmp = htonl(ct->counters[dir].packets);
 	NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
@@ -479,9 +479,7 @@
 
 	DEBUGP("entered %s\n", __FUNCTION__);
 
-	
-	if (nfattr_parse_nested(tb, CTA_IP_MAX, attr) < 0)
-		goto nfattr_failure;
+	nfattr_parse_nested(tb, CTA_IP_MAX, attr);
 
 	if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
 		return -EINVAL;
@@ -497,9 +495,6 @@
 	DEBUGP("leaving\n");
 
 	return 0;
-
-nfattr_failure:
-	return -1;
 }
 
 static const int cta_min_proto[CTA_PROTO_MAX] = {
@@ -521,8 +516,7 @@
 
 	DEBUGP("entered %s\n", __FUNCTION__);
 
-	if (nfattr_parse_nested(tb, CTA_PROTO_MAX, attr) < 0)
-		goto nfattr_failure;
+	nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
 
 	if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
 		return -EINVAL;
@@ -539,9 +533,6 @@
 	}
 	
 	return ret;
-
-nfattr_failure:
-	return -1;
 }
 
 static inline int
@@ -555,8 +546,7 @@
 
 	memset(tuple, 0, sizeof(*tuple));
 
-	if (nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]) < 0)
-		goto nfattr_failure;
+	nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
 
 	if (!tb[CTA_TUPLE_IP-1])
 		return -EINVAL;
@@ -583,9 +573,6 @@
 	DEBUGP("leaving\n");
 
 	return 0;
-
-nfattr_failure:
-	return -1;
 }
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
@@ -603,11 +590,10 @@
 
 	DEBUGP("entered %s\n", __FUNCTION__);
 
-	if (nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr) < 0)
-		goto nfattr_failure;
+	nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
 
 	if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
-		goto nfattr_failure;
+		return -EINVAL;
 
 	npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
 	if (!npt)
@@ -626,9 +612,6 @@
 
 	DEBUGP("leaving\n");
 	return 0;
-
-nfattr_failure:
-	return -1;
 }
 
 static inline int
@@ -642,8 +625,7 @@
 
 	memset(range, 0, sizeof(*range));
 	
-	if (nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]) < 0)
-		goto nfattr_failure;
+	nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
 
 	if (tb[CTA_NAT_MINIP-1])
 		range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
@@ -665,9 +647,6 @@
 
 	DEBUGP("leaving\n");
 	return 0;
-
-nfattr_failure:
-	return -1;
 }
 #endif
 
@@ -678,8 +657,7 @@
 
 	DEBUGP("entered %s\n", __FUNCTION__);
 
-	if (nfattr_parse_nested(tb, CTA_HELP_MAX, attr) < 0)
-		goto nfattr_failure;
+	nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
 
 	if (!tb[CTA_HELP_NAME-1])
 		return -EINVAL;
@@ -687,9 +665,6 @@
 	*helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]);
 
 	return 0;
-
-nfattr_failure:
-	return -1;
 }
 
 static int
@@ -804,7 +779,7 @@
 	ct = tuplehash_to_ctrack(h);
 
 	err = -ENOMEM;
-	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
+	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (!skb2) {
 		ip_conntrack_put(ct);
 		return -ENOMEM;
@@ -827,7 +802,7 @@
 free:
 	kfree_skb(skb2);
 out:
-	return -1;
+	return err;
 }
 
 static inline int
@@ -957,8 +932,7 @@
 	u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
 	int err = 0;
 
-	if (nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr) < 0)
-		goto nfattr_failure;
+	nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr);
 
 	proto = ip_conntrack_proto_find_get(npt);
 	if (!proto)
@@ -969,9 +943,6 @@
 	ip_conntrack_proto_put(proto); 
 
 	return err;
-
-nfattr_failure:
-	return -ENOMEM;
 }
 
 static int
@@ -1005,6 +976,11 @@
 			return err;
 	}
 
+#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+	if (cda[CTA_MARK-1])
+		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+#endif
+
 	DEBUGP("all done\n");
 	return 0;
 }
@@ -1048,6 +1024,11 @@
 	if (ct->helper)
 		ip_conntrack_helper_put(ct->helper);
 
+#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+	if (cda[CTA_MARK-1])
+		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+#endif
+
 	DEBUGP("conntrack with id %u inserted\n", ct->id);
 	return 0;
 
@@ -1312,6 +1293,14 @@
 	if (!exp)
 		return -ENOENT;
 
+	if (cda[CTA_EXPECT_ID-1]) {
+		u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
+		if (exp->id != ntohl(id)) {
+			ip_conntrack_expect_put(exp);
+			return -ENOENT;
+		}
+	}	
+
 	err = -ENOMEM;
 	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (!skb2)
@@ -1387,7 +1376,7 @@
 				ip_conntrack_expect_put(exp);
 			}
 		}
-		write_unlock(&ip_conntrack_lock);
+		write_unlock_bh(&ip_conntrack_lock);
 	} else {
 		/* This basically means we have to flush everything*/
 		write_lock_bh(&ip_conntrack_lock);
@@ -1554,6 +1543,8 @@
 	.cb				= ctnl_exp_cb,
 };
 
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
+
 static int __init ctnetlink_init(void)
 {
 	int ret;
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
index 98f0015..e4d6b26 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -13,6 +13,7 @@
 #include <linux/in.h>
 #include <linux/icmp.h>
 #include <linux/seq_file.h>
+#include <linux/skbuff.h>
 #include <net/ip.h>
 #include <net/checksum.h>
 #include <linux/netfilter.h>
@@ -151,13 +152,13 @@
 	/* Not enough header? */
 	inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in);
 	if (inside == NULL)
-		return NF_ACCEPT;
+		return -NF_ACCEPT;
 
 	/* Ignore ICMP's containing fragments (shouldn't happen) */
 	if (inside->ip.frag_off & htons(IP_OFFSET)) {
 		DEBUGP("icmp_error_track: fragment of proto %u\n",
 		       inside->ip.protocol);
-		return NF_ACCEPT;
+		return -NF_ACCEPT;
 	}
 
 	innerproto = ip_conntrack_proto_find_get(inside->ip.protocol);
@@ -166,7 +167,7 @@
 	if (!ip_ct_get_tuple(&inside->ip, skb, dataoff, &origtuple, innerproto)) {
 		DEBUGP("icmp_error: ! get_tuple p=%u", inside->ip.protocol);
 		ip_conntrack_proto_put(innerproto);
-		return NF_ACCEPT;
+		return -NF_ACCEPT;
 	}
 
 	/* Ordinarily, we'd expect the inverted tupleproto, but it's
@@ -174,7 +175,7 @@
 	if (!ip_ct_invert_tuple(&innertuple, &origtuple, innerproto)) {
 		DEBUGP("icmp_error_track: Can't invert tuple\n");
 		ip_conntrack_proto_put(innerproto);
-		return NF_ACCEPT;
+		return -NF_ACCEPT;
 	}
 	ip_conntrack_proto_put(innerproto);
 
@@ -190,7 +191,7 @@
 
 		if (!h) {
 			DEBUGP("icmp_error_track: no match\n");
-			return NF_ACCEPT;
+			return -NF_ACCEPT;
 		}
 		/* Reverse direction from that found */
 		if (DIRECTION(h) != IP_CT_DIR_REPLY)
@@ -230,19 +231,15 @@
 	case CHECKSUM_HW:
 		if (!(u16)csum_fold(skb->csum)) 
 			break;
-		if (LOG_INVALID(IPPROTO_ICMP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				      "ip_ct_icmp: bad HW ICMP checksum ");
-		return -NF_ACCEPT;
+		/* fall through */
 	case CHECKSUM_NONE:
-		if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
+		skb->csum = 0;
+		if (__skb_checksum_complete(skb)) {
 			if (LOG_INVALID(IPPROTO_ICMP))
 				nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
 					      "ip_ct_icmp: bad ICMP checksum ");
 			return -NF_ACCEPT;
 		}
-	default:
-		break;
 	}
 
 checksum_skipped:
@@ -296,7 +293,8 @@
 				struct ip_conntrack_tuple *tuple)
 {
 	if (!tb[CTA_PROTO_ICMP_TYPE-1]
-	    || !tb[CTA_PROTO_ICMP_CODE-1])
+	    || !tb[CTA_PROTO_ICMP_CODE-1]
+	    || !tb[CTA_PROTO_ICMP_ID-1])
 		return -1;
 
 	tuple->dst.u.icmp.type = 
@@ -304,7 +302,7 @@
 	tuple->dst.u.icmp.code =
 			*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
 	tuple->src.u.icmp.id =
-			*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
+			*(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
 
 	return 0;
 }
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index d6701ca..468c600 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -362,8 +362,12 @@
 	struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1];
 	struct nfattr *tb[CTA_PROTOINFO_TCP_MAX];
 
-        if (nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr) < 0)
-                goto nfattr_failure;
+	/* updates could not contain anything about the private
+	 * protocol info, in that case skip the parsing */
+	if (!attr)
+		return 0;
+
+        nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr);
 
 	if (!tb[CTA_PROTOINFO_TCP_STATE-1])
 		return -EINVAL;
@@ -374,9 +378,6 @@
 	write_unlock_bh(&tcp_lock);
 
 	return 0;
-
-nfattr_failure:
-	return -1;
 }
 #endif
 
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c
index ee6ab74..e546203 100644
--- a/net/ipv4/netfilter/ip_nat_helper_pptp.c
+++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c
@@ -73,6 +73,7 @@
 	struct ip_conntrack_tuple t;
 	struct ip_ct_pptp_master *ct_pptp_info;
 	struct ip_nat_pptp *nat_pptp_info;
+	struct ip_nat_range range;
 
 	ct_pptp_info = &master->help.ct_pptp_info;
 	nat_pptp_info = &master->nat.help.nat_pptp_info;
@@ -110,7 +111,30 @@
 		DEBUGP("not found!\n");
 	}
 
-	ip_nat_follow_master(ct, exp);
+	/* This must be a fresh one. */
+	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+
+	/* Change src to where master sends to */
+	range.flags = IP_NAT_RANGE_MAP_IPS;
+	range.min_ip = range.max_ip
+		= ct->master->tuplehash[!exp->dir].tuple.dst.ip;
+	if (exp->dir == IP_CT_DIR_ORIGINAL) {
+		range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+		range.min = range.max = exp->saved_proto;
+	}
+	/* hook doesn't matter, but it has to do source manip */
+	ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
+
+	/* For DST manip, map port here to where it's expected. */
+	range.flags = IP_NAT_RANGE_MAP_IPS;
+	range.min_ip = range.max_ip
+		= ct->master->tuplehash[!exp->dir].tuple.src.ip;
+	if (exp->dir == IP_CT_DIR_REPLY) {
+		range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+		range.min = range.max = exp->saved_proto;
+	}
+	/* hook doesn't matter, but it has to do destination manip */
+	ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
 }
 
 /* outbound packets == from PNS to PAC */
@@ -213,7 +237,7 @@
 
 	/* alter expectation for PNS->PAC direction */
 	invert_tuplepr(&inv_t, &expect_orig->tuple);
-	expect_orig->saved_proto.gre.key = htons(nat_pptp_info->pac_call_id);
+	expect_orig->saved_proto.gre.key = htons(ct_pptp_info->pns_call_id);
 	expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id);
 	expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);
 	expect_orig->dir = IP_CT_DIR_ORIGINAL;
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
index 93b2c51..8acb7ed 100644
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c
@@ -1161,8 +1161,7 @@
 		
 		if (!snmp_object_decode(&ctx, obj)) {
 			if (*obj) {
-				if ((*obj)->id)
-					kfree((*obj)->id);
+				kfree((*obj)->id);
 				kfree(*obj);
 			}	
 			kfree(obj);
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 9bcb398..45c52d8 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -29,7 +29,7 @@
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <net/netfilter/nf_conntrack_compat.h>
 
 #define CLUSTERIP_VERSION "0.8"
 
@@ -316,14 +316,14 @@
 {
 	const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
 	enum ip_conntrack_info ctinfo;
-	struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
-	u_int32_t hash;
+	u_int32_t *mark, hash;
 
 	/* don't need to clusterip_config_get() here, since refcount
 	 * is only decremented by destroy() - and ip_tables guarantees
 	 * that the ->target() function isn't called after ->destroy() */
 
-	if (!ct) {
+	mark = nf_ct_get_mark((*pskb), &ctinfo);
+	if (mark == NULL) {
 		printk(KERN_ERR "CLUSTERIP: no conntrack!\n");
 			/* FIXME: need to drop invalid ones, since replies
 			 * to outgoing connections of other nodes will be 
@@ -346,7 +346,7 @@
 
 	switch (ctinfo) {
 		case IP_CT_NEW:
-			ct->mark = hash;
+			*mark = hash;
 			break;
 		case IP_CT_RELATED:
 		case IP_CT_RELATED+IP_CT_IS_REPLY:
@@ -363,7 +363,7 @@
 #ifdef DEBUG_CLUSTERP
 	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
 #endif
-	DEBUGP("hash=%u ct_hash=%u ", hash, ct->mark);
+	DEBUGP("hash=%u ct_hash=%u ", hash, *mark);
 	if (!clusterip_responsible(cipinfo->config, hash)) {
 		DEBUGP("not responsible\n");
 		return NF_DROP;
diff --git a/net/ipv4/netfilter/ipt_CONNMARK.c b/net/ipv4/netfilter/ipt_CONNMARK.c
index 05d66ab..8acac5a 100644
--- a/net/ipv4/netfilter/ipt_CONNMARK.c
+++ b/net/ipv4/netfilter/ipt_CONNMARK.c
@@ -29,7 +29,7 @@
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_CONNMARK.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <net/netfilter/nf_conntrack_compat.h>
 
 static unsigned int
 target(struct sk_buff **pskb,
@@ -43,24 +43,24 @@
 	u_int32_t diff;
 	u_int32_t nfmark;
 	u_int32_t newmark;
+	u_int32_t ctinfo;
+	u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
 
-	enum ip_conntrack_info ctinfo;
-	struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
-	if (ct) {
+	if (ctmark) {
 	    switch(markinfo->mode) {
 	    case IPT_CONNMARK_SET:
-		newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
-		if (newmark != ct->mark)
-		    ct->mark = newmark;
+		newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
+		if (newmark != *ctmark)
+		    *ctmark = newmark;
 		break;
 	    case IPT_CONNMARK_SAVE:
-		newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
-		if (ct->mark != newmark)
-		    ct->mark = newmark;
+		newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
+		if (*ctmark != newmark)
+		    *ctmark = newmark;
 		break;
 	    case IPT_CONNMARK_RESTORE:
 		nfmark = (*pskb)->nfmark;
-		diff = (ct->mark ^ nfmark) & markinfo->mask;
+		diff = (*ctmark ^ nfmark) & markinfo->mask;
 		if (diff != 0)
 		    (*pskb)->nfmark = nfmark ^ diff;
 		break;
diff --git a/net/ipv4/netfilter/ipt_NOTRACK.c b/net/ipv4/netfilter/ipt_NOTRACK.c
index a4bb9b3..e3c69d0 100644
--- a/net/ipv4/netfilter/ipt_NOTRACK.c
+++ b/net/ipv4/netfilter/ipt_NOTRACK.c
@@ -5,7 +5,7 @@
 #include <linux/skbuff.h>
 
 #include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <net/netfilter/nf_conntrack_compat.h>
 
 static unsigned int
 target(struct sk_buff **pskb,
@@ -23,7 +23,7 @@
 	   If there is a real ct entry correspondig to this packet, 
 	   it'll hang aroun till timing out. We don't deal with it
 	   for performance reasons. JK */
-	(*pskb)->nfct = &ip_conntrack_untracked.ct_general;
+	nf_ct_untrack(*pskb);
 	(*pskb)->nfctinfo = IP_CT_NEW;
 	nf_conntrack_get((*pskb)->nfct);
 
diff --git a/net/ipv4/netfilter/ipt_connbytes.c b/net/ipv4/netfilter/ipt_connbytes.c
index df4a42c..d68a048 100644
--- a/net/ipv4/netfilter/ipt_connbytes.c
+++ b/net/ipv4/netfilter/ipt_connbytes.c
@@ -10,7 +10,7 @@
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <net/netfilter/nf_conntrack_compat.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_connbytes.h>
 
@@ -46,60 +46,59 @@
       int *hotdrop)
 {
 	const struct ipt_connbytes_info *sinfo = matchinfo;
-	enum ip_conntrack_info ctinfo;
-	struct ip_conntrack *ct;
 	u_int64_t what = 0;	/* initialize to make gcc happy */
+	const struct ip_conntrack_counter *counters;
 
-	if (!(ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)))
+	if (!(counters = nf_ct_get_counters(skb)))
 		return 0; /* no match */
 
 	switch (sinfo->what) {
 	case IPT_CONNBYTES_PKTS:
 		switch (sinfo->direction) {
 		case IPT_CONNBYTES_DIR_ORIGINAL:
-			what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
+			what = counters[IP_CT_DIR_ORIGINAL].packets;
 			break;
 		case IPT_CONNBYTES_DIR_REPLY:
-			what = ct->counters[IP_CT_DIR_REPLY].packets;
+			what = counters[IP_CT_DIR_REPLY].packets;
 			break;
 		case IPT_CONNBYTES_DIR_BOTH:
-			what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
-			what += ct->counters[IP_CT_DIR_REPLY].packets;
+			what = counters[IP_CT_DIR_ORIGINAL].packets;
+			what += counters[IP_CT_DIR_REPLY].packets;
 			break;
 		}
 		break;
 	case IPT_CONNBYTES_BYTES:
 		switch (sinfo->direction) {
 		case IPT_CONNBYTES_DIR_ORIGINAL:
-			what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
+			what = counters[IP_CT_DIR_ORIGINAL].bytes;
 			break;
 		case IPT_CONNBYTES_DIR_REPLY:
-			what = ct->counters[IP_CT_DIR_REPLY].bytes;
+			what = counters[IP_CT_DIR_REPLY].bytes;
 			break;
 		case IPT_CONNBYTES_DIR_BOTH:
-			what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
-			what += ct->counters[IP_CT_DIR_REPLY].bytes;
+			what = counters[IP_CT_DIR_ORIGINAL].bytes;
+			what += counters[IP_CT_DIR_REPLY].bytes;
 			break;
 		}
 		break;
 	case IPT_CONNBYTES_AVGPKT:
 		switch (sinfo->direction) {
 		case IPT_CONNBYTES_DIR_ORIGINAL:
-			what = div64_64(ct->counters[IP_CT_DIR_ORIGINAL].bytes,
-					ct->counters[IP_CT_DIR_ORIGINAL].packets);
+			what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes,
+					counters[IP_CT_DIR_ORIGINAL].packets);
 			break;
 		case IPT_CONNBYTES_DIR_REPLY:
-			what = div64_64(ct->counters[IP_CT_DIR_REPLY].bytes,
-					ct->counters[IP_CT_DIR_REPLY].packets);
+			what = div64_64(counters[IP_CT_DIR_REPLY].bytes,
+					counters[IP_CT_DIR_REPLY].packets);
 			break;
 		case IPT_CONNBYTES_DIR_BOTH:
 			{
 				u_int64_t bytes;
 				u_int64_t pkts;
-				bytes = ct->counters[IP_CT_DIR_ORIGINAL].bytes +
-					ct->counters[IP_CT_DIR_REPLY].bytes;
-				pkts = ct->counters[IP_CT_DIR_ORIGINAL].packets+
-					ct->counters[IP_CT_DIR_REPLY].packets;
+				bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
+					counters[IP_CT_DIR_REPLY].bytes;
+				pkts = counters[IP_CT_DIR_ORIGINAL].packets+
+					counters[IP_CT_DIR_REPLY].packets;
 
 				/* FIXME_THEORETICAL: what to do if sum
 				 * overflows ? */
diff --git a/net/ipv4/netfilter/ipt_connmark.c b/net/ipv4/netfilter/ipt_connmark.c
index bf8de47..5306ef2 100644
--- a/net/ipv4/netfilter/ipt_connmark.c
+++ b/net/ipv4/netfilter/ipt_connmark.c
@@ -28,7 +28,7 @@
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_connmark.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <net/netfilter/nf_conntrack_compat.h>
 
 static int
 match(const struct sk_buff *skb,
@@ -39,12 +39,12 @@
       int *hotdrop)
 {
 	const struct ipt_connmark_info *info = matchinfo;
-	enum ip_conntrack_info ctinfo;
-	struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
-	if (!ct)
+	u_int32_t ctinfo;
+	const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo);
+	if (!ctmark)
 		return 0;
 
-	return ((ct->mark & info->mask) == info->mark) ^ info->invert;
+	return (((*ctmark) & info->mask) == info->mark) ^ info->invert;
 }
 
 static int
diff --git a/net/ipv4/netfilter/ipt_conntrack.c b/net/ipv4/netfilter/ipt_conntrack.c
index c1d2280..c8d1870 100644
--- a/net/ipv4/netfilter/ipt_conntrack.c
+++ b/net/ipv4/netfilter/ipt_conntrack.c
@@ -10,7 +10,14 @@
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
+
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
 #include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#else
+#include <net/netfilter/nf_conntrack.h>
+#endif
+
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_conntrack.h>
 
@@ -18,6 +25,8 @@
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
 MODULE_DESCRIPTION("iptables connection tracking match module");
 
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
+
 static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
@@ -102,6 +111,93 @@
 	return 1;
 }
 
+#else /* CONFIG_IP_NF_CONNTRACK */
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      int *hotdrop)
+{
+	const struct ipt_conntrack_info *sinfo = matchinfo;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+	unsigned int statebit;
+
+	ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
+
+#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
+
+	if (ct == &nf_conntrack_untracked)
+		statebit = IPT_CONNTRACK_STATE_UNTRACKED;
+	else if (ct)
+ 		statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
+ 	else
+ 		statebit = IPT_CONNTRACK_STATE_INVALID;
+ 
+	if(sinfo->flags & IPT_CONNTRACK_STATE) {
+		if (ct) {
+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip !=
+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)
+				statebit |= IPT_CONNTRACK_STATE_SNAT;
+
+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip !=
+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)
+				statebit |= IPT_CONNTRACK_STATE_DNAT;
+		}
+
+		if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_PROTO) {
+		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
+                	return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_STATUS) {
+		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
+		unsigned long expires;
+
+		if(!ct)
+			return 0;
+
+		expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
+
+		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
+			return 0;
+	}
+
+	return 1;
+}
+
+#endif /* CONFIG_NF_IP_CONNTRACK */
+
 static int check(const char *tablename,
 		 const struct ipt_ip *ip,
 		 void *matchinfo,
diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c
index 3e7dd01..bf14e1c 100644
--- a/net/ipv4/netfilter/ipt_helper.c
+++ b/net/ipv4/netfilter/ipt_helper.c
@@ -13,9 +13,15 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#else
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#endif
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_helper.h>
 
@@ -29,6 +35,7 @@
 #define DEBUGP(format, args...)
 #endif
 
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
 static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
@@ -73,6 +80,53 @@
 	return ret;
 }
 
+#else /* CONFIG_IP_NF_CONNTRACK */
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      int *hotdrop)
+{
+	const struct ipt_helper_info *info = matchinfo;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+	int ret = info->invert;
+	
+	ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
+	if (!ct) {
+		DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
+		return ret;
+	}
+
+	if (!ct->master) {
+		DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
+		return ret;
+	}
+
+	read_lock_bh(&nf_conntrack_lock);
+	if (!ct->master->helper) {
+		DEBUGP("ipt_helper: master ct %p has no helper\n", 
+			exp->expectant);
+		goto out_unlock;
+	}
+
+	DEBUGP("master's name = %s , info->name = %s\n", 
+		ct->master->helper->name, info->name);
+
+	if (info->name[0] == '\0')
+		ret ^= 1;
+	else
+		ret ^= !strncmp(ct->master->helper->name, info->name, 
+		                strlen(ct->master->helper->name));
+out_unlock:
+	read_unlock_bh(&nf_conntrack_lock);
+	return ret;
+}
+#endif
+
 static int check(const char *tablename,
 		 const struct ipt_ip *ip,
 		 void *matchinfo,
diff --git a/net/ipv4/netfilter/ipt_state.c b/net/ipv4/netfilter/ipt_state.c
index b1511b9..4d7f16b 100644
--- a/net/ipv4/netfilter/ipt_state.c
+++ b/net/ipv4/netfilter/ipt_state.c
@@ -10,7 +10,7 @@
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <net/netfilter/nf_conntrack_compat.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_state.h>
 
@@ -30,9 +30,9 @@
 	enum ip_conntrack_info ctinfo;
 	unsigned int statebit;
 
-	if (skb->nfct == &ip_conntrack_untracked.ct_general)
+	if (nf_ct_is_untracked(skb))
 		statebit = IPT_STATE_UNTRACKED;
-	else if (!ip_conntrack_get(skb, &ctinfo))
+	else if (!nf_ct_get_ctinfo(skb, &ctinfo))
 		statebit = IPT_STATE_INVALID;
 	else
 		statebit = IPT_STATE_BIT(ctinfo);
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
new file mode 100644
index 0000000..8202c1c
--- /dev/null
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -0,0 +1,571 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- move L3 protocol dependent part to this file.
+ * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- add get_features() to support various size of conntrack
+ *	  structures.
+ *
+ * Derived from net/ipv4/netfilter/ip_conntrack_standalone.c
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/icmp.h>
+#include <linux/sysctl.h>
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+#include <net/netfilter/nf_conntrack_l3proto.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat);
+
+static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
+			     struct nf_conntrack_tuple *tuple)
+{
+	u_int32_t _addrs[2], *ap;
+	ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr),
+				sizeof(u_int32_t) * 2, _addrs);
+	if (ap == NULL)
+		return 0;
+
+	tuple->src.u3.ip = ap[0];
+	tuple->dst.u3.ip = ap[1];
+
+	return 1;
+}
+
+static int ipv4_invert_tuple(struct nf_conntrack_tuple *tuple,
+			   const struct nf_conntrack_tuple *orig)
+{
+	tuple->src.u3.ip = orig->dst.u3.ip;
+	tuple->dst.u3.ip = orig->src.u3.ip;
+
+	return 1;
+}
+
+static int ipv4_print_tuple(struct seq_file *s,
+			    const struct nf_conntrack_tuple *tuple)
+{
+	return seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
+		          NIPQUAD(tuple->src.u3.ip),
+			  NIPQUAD(tuple->dst.u3.ip));
+}
+
+static int ipv4_print_conntrack(struct seq_file *s,
+				const struct nf_conn *conntrack)
+{
+	return 0;
+}
+
+/* Returns new sk_buff, or NULL */
+static struct sk_buff *
+nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
+{
+	skb_orphan(skb);
+
+        local_bh_disable();
+        skb = ip_defrag(skb, user);
+        local_bh_enable();
+
+        if (skb)
+		ip_send_check(skb->nh.iph);
+
+        return skb;
+}
+
+static int
+ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
+	     u_int8_t *protonum)
+{
+	/* Never happen */
+	if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
+		if (net_ratelimit()) {
+			printk(KERN_ERR "ipv4_prepare: Frag of proto %u (hook=%u)\n",
+			(*pskb)->nh.iph->protocol, hooknum);
+		}
+		return -NF_DROP;
+	}
+
+	*dataoff = (*pskb)->nh.raw - (*pskb)->data + (*pskb)->nh.iph->ihl*4;
+	*protonum = (*pskb)->nh.iph->protocol;
+
+	return NF_ACCEPT;
+}
+
+int nat_module_is_loaded = 0;
+static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple)
+{
+	if (nat_module_is_loaded)
+		return NF_CT_F_NAT;
+
+	return NF_CT_F_BASIC;
+}
+
+static unsigned int ipv4_confirm(unsigned int hooknum,
+				 struct sk_buff **pskb,
+				 const struct net_device *in,
+				 const struct net_device *out,
+				 int (*okfn)(struct sk_buff *))
+{
+	/* We've seen it coming out the other side: confirm it */
+	return nf_conntrack_confirm(pskb);
+}
+
+static unsigned int ipv4_conntrack_help(unsigned int hooknum,
+				      struct sk_buff **pskb,
+				      const struct net_device *in,
+				      const struct net_device *out,
+				      int (*okfn)(struct sk_buff *))
+{
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+
+	/* This is where we call the helper: as the packet goes out. */
+	ct = nf_ct_get(*pskb, &ctinfo);
+	if (ct && ct->helper) {
+		unsigned int ret;
+		ret = ct->helper->help(pskb,
+				       (*pskb)->nh.raw - (*pskb)->data
+						       + (*pskb)->nh.iph->ihl*4,
+				       ct, ctinfo);
+		if (ret != NF_ACCEPT)
+			return ret;
+	}
+	return NF_ACCEPT;
+}
+
+static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
+					  struct sk_buff **pskb,
+					  const struct net_device *in,
+					  const struct net_device *out,
+					  int (*okfn)(struct sk_buff *))
+{
+#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE)
+	/* Previously seen (loopback)?  Ignore.  Do this before
+	   fragment check. */
+	if ((*pskb)->nfct)
+		return NF_ACCEPT;
+#endif
+
+	/* Gather fragments. */
+	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+		*pskb = nf_ct_ipv4_gather_frags(*pskb,
+						hooknum == NF_IP_PRE_ROUTING ?
+						IP_DEFRAG_CONNTRACK_IN :
+						IP_DEFRAG_CONNTRACK_OUT);
+		if (!*pskb)
+			return NF_STOLEN;
+	}
+	return NF_ACCEPT;
+}
+
+static unsigned int ipv4_refrag(unsigned int hooknum,
+				struct sk_buff **pskb,
+				const struct net_device *in,
+				const struct net_device *out,
+				int (*okfn)(struct sk_buff *))
+{
+	struct rtable *rt = (struct rtable *)(*pskb)->dst;
+
+	/* We've seen it coming out the other side: confirm */
+	if (ipv4_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
+		return NF_DROP;
+
+	/* Local packets are never produced too large for their
+	   interface.  We degfragment them at LOCAL_OUT, however,
+	   so we have to refragment them here. */
+	if ((*pskb)->len > dst_mtu(&rt->u.dst) &&
+	    !skb_shinfo(*pskb)->tso_size) {
+		/* No hook can be after us, so this should be OK. */
+		ip_fragment(*pskb, okfn);
+		return NF_STOLEN;
+	}
+	return NF_ACCEPT;
+}
+
+static unsigned int ipv4_conntrack_in(unsigned int hooknum,
+				      struct sk_buff **pskb,
+				      const struct net_device *in,
+				      const struct net_device *out,
+				      int (*okfn)(struct sk_buff *))
+{
+	return nf_conntrack_in(PF_INET, hooknum, pskb);
+}
+
+static unsigned int ipv4_conntrack_local(unsigned int hooknum,
+				         struct sk_buff **pskb,
+				         const struct net_device *in,
+				         const struct net_device *out,
+				         int (*okfn)(struct sk_buff *))
+{
+	/* root is playing with raw sockets. */
+	if ((*pskb)->len < sizeof(struct iphdr)
+	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
+		if (net_ratelimit())
+			printk("ipt_hook: happy cracking.\n");
+		return NF_ACCEPT;
+	}
+	return nf_conntrack_in(PF_INET, hooknum, pskb);
+}
+
+/* Connection tracking may drop packets, but never alters them, so
+   make it the first hook. */
+static struct nf_hook_ops ipv4_conntrack_defrag_ops = {
+	.hook		= ipv4_conntrack_defrag,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_PRE_ROUTING,
+	.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
+};
+
+static struct nf_hook_ops ipv4_conntrack_in_ops = {
+	.hook		= ipv4_conntrack_in,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_PRE_ROUTING,
+	.priority	= NF_IP_PRI_CONNTRACK,
+};
+
+static struct nf_hook_ops ipv4_conntrack_defrag_local_out_ops = {
+	.hook           = ipv4_conntrack_defrag,
+	.owner          = THIS_MODULE,
+	.pf             = PF_INET,
+	.hooknum        = NF_IP_LOCAL_OUT,
+	.priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
+};
+
+static struct nf_hook_ops ipv4_conntrack_local_out_ops = {
+	.hook		= ipv4_conntrack_local,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_LOCAL_OUT,
+	.priority	= NF_IP_PRI_CONNTRACK,
+};
+
+/* helpers */
+static struct nf_hook_ops ipv4_conntrack_helper_out_ops = {
+	.hook		= ipv4_conntrack_help,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_POST_ROUTING,
+	.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+};
+
+static struct nf_hook_ops ipv4_conntrack_helper_in_ops = {
+	.hook		= ipv4_conntrack_help,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_LOCAL_IN,
+	.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+};
+
+
+/* Refragmenter; last chance. */
+static struct nf_hook_ops ipv4_conntrack_out_ops = {
+	.hook		= ipv4_refrag,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_POST_ROUTING,
+	.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
+};
+
+static struct nf_hook_ops ipv4_conntrack_local_in_ops = {
+	.hook		= ipv4_confirm,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_LOCAL_IN,
+	.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
+};
+
+#ifdef CONFIG_SYSCTL
+/* From nf_conntrack_proto_icmp.c */
+extern unsigned long nf_ct_icmp_timeout;
+static struct ctl_table_header *nf_ct_ipv4_sysctl_header;
+
+static ctl_table nf_ct_sysctl_table[] = {
+	{
+		.ctl_name	= NET_NF_CONNTRACK_ICMP_TIMEOUT,
+		.procname	= "nf_conntrack_icmp_timeout",
+		.data		= &nf_ct_icmp_timeout,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+        { .ctl_name = 0 }
+};
+
+static ctl_table nf_ct_netfilter_table[] = {
+	{
+		.ctl_name       = NET_NETFILTER,
+		.procname       = "netfilter",
+		.mode           = 0555,
+		.child          = nf_ct_sysctl_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table nf_ct_net_table[] = {
+	{
+		.ctl_name       = CTL_NET,
+		.procname       = "net",
+		.mode           = 0555,
+		.child          = nf_ct_netfilter_table,
+	},
+	{ .ctl_name = 0 }
+};
+#endif
+
+/* Fast function for those who don't want to parse /proc (and I don't
+   blame them). */
+/* Reversing the socket's dst/src point of view gives us the reply
+   mapping. */
+static int
+getorigdst(struct sock *sk, int optval, void __user *user, int *len)
+{
+	struct inet_sock *inet = inet_sk(sk);
+	struct nf_conntrack_tuple_hash *h;
+	struct nf_conntrack_tuple tuple;
+	
+	NF_CT_TUPLE_U_BLANK(&tuple);
+	tuple.src.u3.ip = inet->rcv_saddr;
+	tuple.src.u.tcp.port = inet->sport;
+	tuple.dst.u3.ip = inet->daddr;
+	tuple.dst.u.tcp.port = inet->dport;
+	tuple.src.l3num = PF_INET;
+	tuple.dst.protonum = IPPROTO_TCP;
+
+	/* We only do TCP at the moment: is there a better way? */
+	if (strcmp(sk->sk_prot->name, "TCP")) {
+		DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
+		return -ENOPROTOOPT;
+	}
+
+	if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
+		DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
+		       *len, sizeof(struct sockaddr_in));
+		return -EINVAL;
+	}
+
+	h = nf_conntrack_find_get(&tuple, NULL);
+	if (h) {
+		struct sockaddr_in sin;
+		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
+
+		sin.sin_family = AF_INET;
+		sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL]
+			.tuple.dst.u.tcp.port;
+		sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL]
+			.tuple.dst.u3.ip;
+
+		DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
+		       NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
+		nf_ct_put(ct);
+		if (copy_to_user(user, &sin, sizeof(sin)) != 0)
+			return -EFAULT;
+		else
+			return 0;
+	}
+	DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
+	       NIPQUAD(tuple.src.u3.ip), ntohs(tuple.src.u.tcp.port),
+	       NIPQUAD(tuple.dst.u3.ip), ntohs(tuple.dst.u.tcp.port));
+	return -ENOENT;
+}
+
+static struct nf_sockopt_ops so_getorigdst = {
+	.pf		= PF_INET,
+	.get_optmin	= SO_ORIGINAL_DST,
+	.get_optmax	= SO_ORIGINAL_DST+1,
+	.get		= &getorigdst,
+};
+
+struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
+	.l3proto	 = PF_INET,
+	.name		 = "ipv4",
+	.pkt_to_tuple	 = ipv4_pkt_to_tuple,
+	.invert_tuple	 = ipv4_invert_tuple,
+	.print_tuple	 = ipv4_print_tuple,
+	.print_conntrack = ipv4_print_conntrack,
+	.prepare	 = ipv4_prepare,
+	.get_features	 = ipv4_get_features,
+	.me		 = THIS_MODULE,
+};
+
+extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp;
+static int init_or_cleanup(int init)
+{
+	int ret = 0;
+
+	if (!init) goto cleanup;
+
+	ret = nf_register_sockopt(&so_getorigdst);
+	if (ret < 0) {
+		printk(KERN_ERR "Unable to register netfilter socket option\n");
+		goto cleanup_nothing;
+	}
+
+	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp4);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register tcp.\n");
+		goto cleanup_sockopt;
+	}
+
+	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp4);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register udp.\n");
+		goto cleanup_tcp;
+	}
+
+	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmp);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register icmp.\n");
+		goto cleanup_udp;
+	}
+
+	ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register ipv4\n");
+		goto cleanup_icmp;
+	}
+
+	ret = nf_register_hook(&ipv4_conntrack_defrag_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register pre-routing defrag hook.\n");
+		goto cleanup_ipv4;
+	}
+	ret = nf_register_hook(&ipv4_conntrack_defrag_local_out_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register local_out defrag hook.\n");
+		goto cleanup_defragops;
+	}
+
+	ret = nf_register_hook(&ipv4_conntrack_in_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register pre-routing hook.\n");
+		goto cleanup_defraglocalops;
+	}
+
+	ret = nf_register_hook(&ipv4_conntrack_local_out_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register local out hook.\n");
+		goto cleanup_inops;
+	}
+
+	ret = nf_register_hook(&ipv4_conntrack_helper_in_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register local helper hook.\n");
+		goto cleanup_inandlocalops;
+	}
+
+	ret = nf_register_hook(&ipv4_conntrack_helper_out_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register postrouting helper hook.\n");
+		goto cleanup_helperinops;
+	}
+
+	ret = nf_register_hook(&ipv4_conntrack_out_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register post-routing hook.\n");
+		goto cleanup_helperoutops;
+	}
+
+	ret = nf_register_hook(&ipv4_conntrack_local_in_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv4: can't register local in hook.\n");
+		goto cleanup_inoutandlocalops;
+	}
+
+#ifdef CONFIG_SYSCTL
+	nf_ct_ipv4_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
+	if (nf_ct_ipv4_sysctl_header == NULL) {
+		printk("nf_conntrack: can't register to sysctl.\n");
+		ret = -ENOMEM;
+		goto cleanup_localinops;
+	}
+#endif
+
+	/* For use by REJECT target */
+	ip_ct_attach = __nf_conntrack_attach;
+
+	return ret;
+
+ cleanup:
+	synchronize_net();
+	ip_ct_attach = NULL;
+#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(nf_ct_ipv4_sysctl_header);
+ cleanup_localinops:
+#endif
+	nf_unregister_hook(&ipv4_conntrack_local_in_ops);
+ cleanup_inoutandlocalops:
+	nf_unregister_hook(&ipv4_conntrack_out_ops);
+ cleanup_helperoutops:
+	nf_unregister_hook(&ipv4_conntrack_helper_out_ops);
+ cleanup_helperinops:
+	nf_unregister_hook(&ipv4_conntrack_helper_in_ops);
+ cleanup_inandlocalops:
+	nf_unregister_hook(&ipv4_conntrack_local_out_ops);
+ cleanup_inops:
+	nf_unregister_hook(&ipv4_conntrack_in_ops);
+ cleanup_defraglocalops:
+	nf_unregister_hook(&ipv4_conntrack_defrag_local_out_ops);
+ cleanup_defragops:
+	nf_unregister_hook(&ipv4_conntrack_defrag_ops);
+ cleanup_ipv4:
+	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
+ cleanup_icmp:
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp);
+ cleanup_udp:
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4);
+ cleanup_tcp:
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4);
+ cleanup_sockopt:
+	nf_unregister_sockopt(&so_getorigdst);
+ cleanup_nothing:
+	return ret;
+}
+
+MODULE_LICENSE("GPL");
+
+static int __init init(void)
+{
+	need_nf_conntrack();
+	return init_or_cleanup(1);
+}
+
+static void __exit fini(void)
+{
+	init_or_cleanup(0);
+}
+
+module_init(init);
+module_exit(fini);
+
+void need_ip_conntrack(void)
+{
+}
+
+EXPORT_SYMBOL(need_ip_conntrack);
+EXPORT_SYMBOL(nf_ct_ipv4_gather_frags);
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
new file mode 100644
index 0000000..7ddb5c0
--- /dev/null
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -0,0 +1,301 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- enable working with Layer 3 protocol independent connection tracking.
+ *
+ * Derived from net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/in.h>
+#include <linux/icmp.h>
+#include <linux/seq_file.h>
+#include <net/ip.h>
+#include <net/checksum.h>
+#include <linux/netfilter_ipv4.h>
+#include <net/netfilter/nf_conntrack_tuple.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+#include <net/netfilter/nf_conntrack_core.h>
+
+unsigned long nf_ct_icmp_timeout = 30*HZ;
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static int icmp_pkt_to_tuple(const struct sk_buff *skb,
+			     unsigned int dataoff,
+			     struct nf_conntrack_tuple *tuple)
+{
+	struct icmphdr _hdr, *hp;
+
+	hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+	if (hp == NULL)
+		return 0;
+
+	tuple->dst.u.icmp.type = hp->type;
+	tuple->src.u.icmp.id = hp->un.echo.id;
+	tuple->dst.u.icmp.code = hp->code;
+
+	return 1;
+}
+
+static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple,
+			     const struct nf_conntrack_tuple *orig)
+{
+	/* Add 1; spaces filled with 0. */
+	static u_int8_t invmap[]
+		= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
+		    [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
+		    [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
+		    [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
+		    [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
+		    [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
+		    [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
+		    [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
+
+	if (orig->dst.u.icmp.type >= sizeof(invmap)
+	    || !invmap[orig->dst.u.icmp.type])
+		return 0;
+
+	tuple->src.u.icmp.id = orig->src.u.icmp.id;
+	tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1;
+	tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
+	return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static int icmp_print_tuple(struct seq_file *s,
+			    const struct nf_conntrack_tuple *tuple)
+{
+	return seq_printf(s, "type=%u code=%u id=%u ",
+			  tuple->dst.u.icmp.type,
+			  tuple->dst.u.icmp.code,
+			  ntohs(tuple->src.u.icmp.id));
+}
+
+/* Print out the private part of the conntrack. */
+static int icmp_print_conntrack(struct seq_file *s,
+				const struct nf_conn *conntrack)
+{
+	return 0;
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int icmp_packet(struct nf_conn *ct,
+		       const struct sk_buff *skb,
+		       unsigned int dataoff,
+		       enum ip_conntrack_info ctinfo,
+		       int pf,
+		       unsigned int hooknum)
+{
+	/* Try to delete connection immediately after all replies:
+           won't actually vanish as we still have skb, and del_timer
+           means this will only run once even if count hits zero twice
+           (theoretically possible with SMP) */
+	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
+		if (atomic_dec_and_test(&ct->proto.icmp.count)
+		    && del_timer(&ct->timeout))
+			ct->timeout.function((unsigned long)ct);
+	} else {
+		atomic_inc(&ct->proto.icmp.count);
+		nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout);
+	}
+
+	return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int icmp_new(struct nf_conn *conntrack,
+		    const struct sk_buff *skb, unsigned int dataoff)
+{
+	static u_int8_t valid_new[]
+		= { [ICMP_ECHO] = 1,
+		    [ICMP_TIMESTAMP] = 1,
+		    [ICMP_INFO_REQUEST] = 1,
+		    [ICMP_ADDRESS] = 1 };
+
+	if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
+	    || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
+		/* Can't create a new ICMP `conn' with this. */
+		DEBUGP("icmp: can't create new conn with type %u\n",
+		       conntrack->tuplehash[0].tuple.dst.u.icmp.type);
+		NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
+		return 0;
+	}
+	atomic_set(&conntrack->proto.icmp.count, 0);
+	return 1;
+}
+
+extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
+/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
+static int
+icmp_error_message(struct sk_buff *skb,
+                 enum ip_conntrack_info *ctinfo,
+                 unsigned int hooknum)
+{
+	struct nf_conntrack_tuple innertuple, origtuple;
+	struct {
+		struct icmphdr icmp;
+		struct iphdr ip;
+	} _in, *inside;
+	struct nf_conntrack_protocol *innerproto;
+	struct nf_conntrack_tuple_hash *h;
+	int dataoff;
+
+	NF_CT_ASSERT(skb->nfct == NULL);
+
+	/* Not enough header? */
+	inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in);
+	if (inside == NULL)
+		return -NF_ACCEPT;
+
+	/* Ignore ICMP's containing fragments (shouldn't happen) */
+	if (inside->ip.frag_off & htons(IP_OFFSET)) {
+		DEBUGP("icmp_error_message: fragment of proto %u\n",
+		       inside->ip.protocol);
+		return -NF_ACCEPT;
+	}
+
+	innerproto = nf_ct_find_proto(PF_INET, inside->ip.protocol);
+	dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp);
+	/* Are they talking about one of our connections? */
+	if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
+			     inside->ip.protocol, &origtuple,
+			     &nf_conntrack_l3proto_ipv4, innerproto)) {
+		DEBUGP("icmp_error_message: ! get_tuple p=%u",
+		       inside->ip.protocol);
+		return -NF_ACCEPT;
+	}
+
+        /* Ordinarily, we'd expect the inverted tupleproto, but it's
+           been preserved inside the ICMP. */
+        if (!nf_ct_invert_tuple(&innertuple, &origtuple,
+				&nf_conntrack_l3proto_ipv4, innerproto)) {
+		DEBUGP("icmp_error_message: no match\n");
+		return -NF_ACCEPT;
+	}
+
+	*ctinfo = IP_CT_RELATED;
+
+	h = nf_conntrack_find_get(&innertuple, NULL);
+	if (!h) {
+		/* Locally generated ICMPs will match inverted if they
+		   haven't been SNAT'ed yet */
+		/* FIXME: NAT code has to handle half-done double NAT --RR */
+		if (hooknum == NF_IP_LOCAL_OUT)
+			h = nf_conntrack_find_get(&origtuple, NULL);
+
+		if (!h) {
+			DEBUGP("icmp_error_message: no match\n");
+			return -NF_ACCEPT;
+		}
+
+		/* Reverse direction from that found */
+		if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
+			*ctinfo += IP_CT_IS_REPLY;
+	} else {
+		if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
+			*ctinfo += IP_CT_IS_REPLY;
+	}
+
+        /* Update skb to refer to this connection */
+        skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
+        skb->nfctinfo = *ctinfo;
+        return -NF_ACCEPT;
+}
+
+/* Small and modified version of icmp_rcv */
+static int
+icmp_error(struct sk_buff *skb, unsigned int dataoff,
+	   enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
+{
+	struct icmphdr _ih, *icmph;
+
+	/* Not enough header? */
+	icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
+	if (icmph == NULL) {
+		if (LOG_INVALID(IPPROTO_ICMP))
+			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
+				      "nf_ct_icmp: short packet ");
+		return -NF_ACCEPT;
+	}
+
+	/* See ip_conntrack_proto_tcp.c */
+	if (hooknum != NF_IP_PRE_ROUTING)
+		goto checksum_skipped;
+
+	switch (skb->ip_summed) {
+	case CHECKSUM_HW:
+		if (!(u16)csum_fold(skb->csum))
+			break;
+		if (LOG_INVALID(IPPROTO_ICMP))
+			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
+				      "nf_ct_icmp: bad HW ICMP checksum ");
+		return -NF_ACCEPT;
+	case CHECKSUM_NONE:
+		if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
+			if (LOG_INVALID(IPPROTO_ICMP))
+				nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+					      NULL,
+					      "nf_ct_icmp: bad ICMP checksum ");
+			return -NF_ACCEPT;
+		}
+	default:
+		break;
+	}
+
+checksum_skipped:
+	/*
+	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
+	 *
+	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently
+	 *		  discarded.
+	 */
+	if (icmph->type > NR_ICMP_TYPES) {
+		if (LOG_INVALID(IPPROTO_ICMP))
+			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
+				      "nf_ct_icmp: invalid ICMP type ");
+		return -NF_ACCEPT;
+	}
+
+	/* Need to track icmp error message? */
+	if (icmph->type != ICMP_DEST_UNREACH
+	    && icmph->type != ICMP_SOURCE_QUENCH
+	    && icmph->type != ICMP_TIME_EXCEEDED
+	    && icmph->type != ICMP_PARAMETERPROB
+	    && icmph->type != ICMP_REDIRECT)
+		return NF_ACCEPT;
+
+	return icmp_error_message(skb, ctinfo, hooknum);
+}
+
+struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
+{
+	.list			= { NULL, NULL },
+	.l3proto		= PF_INET,
+	.proto			= IPPROTO_ICMP,
+	.name			= "icmp",
+	.pkt_to_tuple		= icmp_pkt_to_tuple,
+	.invert_tuple		= icmp_invert_tuple,
+	.print_tuple		= icmp_print_tuple,
+	.print_conntrack	= icmp_print_conntrack,
+	.packet			= icmp_packet,
+	.new			= icmp_new,
+	.error			= icmp_error,
+	.destroy		= NULL,
+	.me			= NULL
+};
+
+EXPORT_SYMBOL(nf_conntrack_protocol_icmp);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 6526856..01444a0 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -645,6 +645,14 @@
 		.proc_handler	= &proc_tcp_congestion_control,
 		.strategy	= &sysctl_tcp_congestion_control,
 	},
+	{
+		.ctl_name	= NET_TCP_ABC,
+		.procname	= "tcp_abc",
+		.data		= &sysctl_tcp_abc,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
 
 	{ .ctl_name = 0 }
 };
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 72b7c22..9ac7a4f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1640,7 +1640,7 @@
 	} else if (tcp_need_reset(old_state) ||
 		   (tp->snd_nxt != tp->write_seq &&
 		    (1 << old_state) & (TCPF_CLOSING | TCPF_LAST_ACK))) {
-		/* The last check adjusts for discrepance of Linux wrt. RFC
+		/* The last check adjusts for discrepancy of Linux wrt. RFC
 		 * states
 		 */
 		tcp_send_active_reset(sk, gfp_any());
@@ -1669,6 +1669,7 @@
 	tp->packets_out = 0;
 	tp->snd_ssthresh = 0x7fffffff;
 	tp->snd_cwnd_cnt = 0;
+	tp->bytes_acked = 0;
 	tcp_set_ca_state(sk, TCP_CA_Open);
 	tcp_clear_retrans(tp);
 	inet_csk_delack_init(sk);
diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c
index ae35e06..1d0cd86 100644
--- a/net/ipv4/tcp_bic.c
+++ b/net/ipv4/tcp_bic.c
@@ -217,17 +217,15 @@
 
 	bictcp_low_utilization(sk, data_acked);
 
-	if (in_flight < tp->snd_cwnd)
+	if (!tcp_is_cwnd_limited(sk, in_flight))
 		return;
 
-	if (tp->snd_cwnd <= tp->snd_ssthresh) {
-		/* In "safe" area, increase. */
-		if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-			tp->snd_cwnd++;
-	} else {
+	if (tp->snd_cwnd <= tp->snd_ssthresh)
+		tcp_slow_start(tp);
+	else {
 		bictcp_update(ca, tp->snd_cwnd);
 
-                /* In dangerous area, increase slowly.
+		/* In dangerous area, increase slowly.
 		 * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd
 		 */
 		if (tp->snd_cwnd_cnt >= ca->cnt) {
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index bbf2d66..c7cc62c 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -186,24 +186,32 @@
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
-	if (in_flight < tp->snd_cwnd)
+	if (!tcp_is_cwnd_limited(sk, in_flight))
 		return;
 
-        if (tp->snd_cwnd <= tp->snd_ssthresh) {
-                /* In "safe" area, increase. */
-		if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-			tp->snd_cwnd++;
-	} else {
-                /* In dangerous area, increase slowly.
-		 * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd
-		 */
-		if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
-			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-				tp->snd_cwnd++;
-			tp->snd_cwnd_cnt = 0;
-		} else
-			tp->snd_cwnd_cnt++;
-	}
+	/* In "safe" area, increase. */
+        if (tp->snd_cwnd <= tp->snd_ssthresh)
+		tcp_slow_start(tp);
+
+ 	/* In dangerous area, increase slowly. */
+	else if (sysctl_tcp_abc) {
+ 		/* RFC3465: Apppriate Byte Count
+ 		 * increase once for each full cwnd acked
+ 		 */
+ 		if (tp->bytes_acked >= tp->snd_cwnd*tp->mss_cache) {
+ 			tp->bytes_acked -= tp->snd_cwnd*tp->mss_cache;
+ 			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+ 				tp->snd_cwnd++;
+ 		}
+ 	} else {
+ 		/* In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd */
+ 		if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
+ 			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+ 				tp->snd_cwnd++;
+ 			tp->snd_cwnd_cnt = 0;
+ 		} else
+ 			tp->snd_cwnd_cnt++;
+ 	}
 }
 EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid);
 
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
index 6acc04b..82b3c18 100644
--- a/net/ipv4/tcp_highspeed.c
+++ b/net/ipv4/tcp_highspeed.c
@@ -111,18 +111,17 @@
 }
 
 static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt,
-			     u32 in_flight, int good)
+			     u32 in_flight, u32 pkts_acked)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct hstcp *ca = inet_csk_ca(sk);
 
-	if (in_flight < tp->snd_cwnd)
+	if (!tcp_is_cwnd_limited(sk, in_flight))
 		return;
 
-	if (tp->snd_cwnd <= tp->snd_ssthresh) {
-		if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-			tp->snd_cwnd++;
-	} else {
+	if (tp->snd_cwnd <= tp->snd_ssthresh)
+		tcp_slow_start(tp);
+	else {
 		/* Update AIMD parameters */
 		if (tp->snd_cwnd > hstcp_aimd_vals[ca->ai].cwnd) {
 			while (tp->snd_cwnd > hstcp_aimd_vals[ca->ai].cwnd &&
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
index e47b379..3284cfb 100644
--- a/net/ipv4/tcp_htcp.c
+++ b/net/ipv4/tcp_htcp.c
@@ -207,14 +207,13 @@
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct htcp *ca = inet_csk_ca(sk);
 
-	if (in_flight < tp->snd_cwnd)
+	if (!tcp_is_cwnd_limited(sk, in_flight))
 		return;
 
-        if (tp->snd_cwnd <= tp->snd_ssthresh) {
-                /* In "safe" area, increase. */
-		if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-			tp->snd_cwnd++;
-	} else {
+        if (tp->snd_cwnd <= tp->snd_ssthresh)
+		tcp_slow_start(tp);
+	else {
+
 		measure_rtt(sk);
 
 		/* keep track of number of round-trip times since last backoff event */
@@ -224,7 +223,7 @@
 			htcp_alpha_update(ca);
 		}
 
-                /* In dangerous area, increase slowly.
+		/* In dangerous area, increase slowly.
 		 * In theory this is tp->snd_cwnd += alpha / tp->snd_cwnd
 		 */
 		if ((tp->snd_cwnd_cnt++ * ca->alpha)>>7 >= tp->snd_cwnd) {
diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c
index 77add636..40dbb38 100644
--- a/net/ipv4/tcp_hybla.c
+++ b/net/ipv4/tcp_hybla.c
@@ -100,12 +100,12 @@
 		ca->minrtt = tp->srtt;
 	}
 
+	if (!tcp_is_cwnd_limited(sk, in_flight))
+		return;
+
 	if (!ca->hybla_en)
 		return tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
 
-	if (in_flight < tp->snd_cwnd)
-		return;
-
 	if (ca->rho == 0)
 		hybla_recalc_param(sk);
 
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3e98b57..40a26b7 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -42,7 +42,7 @@
  *		Andi Kleen	:	Moved open_request checking here
  *					and process RSTs for open_requests.
  *		Andi Kleen	:	Better prune_queue, and other fixes.
- *		Andrey Savochkin:	Fix RTT measurements in the presnce of
+ *		Andrey Savochkin:	Fix RTT measurements in the presence of
  *					timestamps.
  *		Andrey Savochkin:	Check sequence numbers correctly when
  *					removing SACKs due to in sequence incoming
@@ -89,6 +89,7 @@
 int sysctl_tcp_nometrics_save;
 
 int sysctl_tcp_moderate_rcvbuf = 1;
+int sysctl_tcp_abc = 1;
 
 #define FLAG_DATA		0x01 /* Incoming frame contained data.		*/
 #define FLAG_WIN_UPDATE		0x02 /* Incoming ACK was a window update.	*/
@@ -223,7 +224,7 @@
  *   of receiver window. Check #2.
  *
  * The scheme does not work when sender sends good segments opening
- * window and then starts to feed us spagetti. But it should work
+ * window and then starts to feed us spaghetti. But it should work
  * in common situations. Otherwise, we have to rely on queue collapsing.
  */
 
@@ -233,7 +234,7 @@
 {
 	/* Optimize this! */
 	int truesize = tcp_win_from_space(skb->truesize)/2;
-	int window = tcp_full_space(sk)/2;
+	int window = tcp_win_from_space(sysctl_tcp_rmem[2])/2;
 
 	while (tp->rcv_ssthresh <= window) {
 		if (truesize <= skb->len)
@@ -277,7 +278,7 @@
 	int rcvmem = tp->advmss + MAX_TCP_HEADER + 16 + sizeof(struct sk_buff);
 
 	/* Try to select rcvbuf so that 4 mss-sized segments
-	 * will fit to window and correspoding skbs will fit to our rcvbuf.
+	 * will fit to window and corresponding skbs will fit to our rcvbuf.
 	 * (was 3; 4 is minimum to allow fast retransmit to work.)
 	 */
 	while (tcp_win_from_space(rcvmem) < tp->advmss)
@@ -286,7 +287,7 @@
 		sk->sk_rcvbuf = min(4 * rcvmem, sysctl_tcp_rmem[2]);
 }
 
-/* 4. Try to fixup all. It is made iimediately after connection enters
+/* 4. Try to fixup all. It is made immediately after connection enters
  *    established state.
  */
 static void tcp_init_buffer_space(struct sock *sk)
@@ -326,37 +327,18 @@
 static void tcp_clamp_window(struct sock *sk, struct tcp_sock *tp)
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
-	struct sk_buff *skb;
-	unsigned int app_win = tp->rcv_nxt - tp->copied_seq;
-	int ofo_win = 0;
 
 	icsk->icsk_ack.quick = 0;
 
-	skb_queue_walk(&tp->out_of_order_queue, skb) {
-		ofo_win += skb->len;
+	if (sk->sk_rcvbuf < sysctl_tcp_rmem[2] &&
+	    !(sk->sk_userlocks & SOCK_RCVBUF_LOCK) &&
+	    !tcp_memory_pressure &&
+	    atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) {
+		sk->sk_rcvbuf = min(atomic_read(&sk->sk_rmem_alloc),
+				    sysctl_tcp_rmem[2]);
 	}
-
-	/* If overcommit is due to out of order segments,
-	 * do not clamp window. Try to expand rcvbuf instead.
-	 */
-	if (ofo_win) {
-		if (sk->sk_rcvbuf < sysctl_tcp_rmem[2] &&
-		    !(sk->sk_userlocks & SOCK_RCVBUF_LOCK) &&
-		    !tcp_memory_pressure &&
-		    atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0])
-			sk->sk_rcvbuf = min(atomic_read(&sk->sk_rmem_alloc),
-					    sysctl_tcp_rmem[2]);
-	}
-	if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) {
-		app_win += ofo_win;
-		if (atomic_read(&sk->sk_rmem_alloc) >= 2 * sk->sk_rcvbuf)
-			app_win >>= 1;
-		if (app_win > icsk->icsk_ack.rcv_mss)
-			app_win -= icsk->icsk_ack.rcv_mss;
-		app_win = max(app_win, 2U*tp->advmss);
-
+	if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf)
 		tp->rcv_ssthresh = min(tp->window_clamp, 2U*tp->advmss);
-	}
 }
 
 /* Receiver "autotuning" code.
@@ -385,8 +367,8 @@
 		 * are stalled on filesystem I/O.
 		 *
 		 * Also, since we are only going for a minimum in the
-		 * non-timestamp case, we do not smoothe things out
-		 * else with timestamps disabled convergance takes too
+		 * non-timestamp case, we do not smoother things out
+		 * else with timestamps disabled convergence takes too
 		 * long.
 		 */
 		if (!win_dep) {
@@ -395,7 +377,7 @@
 		} else if (m < new_sample)
 			new_sample = m << 3;
 	} else {
-		/* No previous mesaure. */
+		/* No previous measure. */
 		new_sample = m << 3;
 	}
 
@@ -524,7 +506,7 @@
 			if (icsk->icsk_ack.ato > icsk->icsk_rto)
 				icsk->icsk_ack.ato = icsk->icsk_rto;
 		} else if (m > icsk->icsk_rto) {
-			/* Too long gap. Apparently sender falled to
+			/* Too long gap. Apparently sender failed to
 			 * restart window, so that we send ACKs quickly.
 			 */
 			tcp_incr_quickack(sk);
@@ -548,10 +530,9 @@
  * To save cycles in the RFC 1323 implementation it was better to break
  * it up into three procedures. -- erics
  */
-static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt, u32 *usrtt)
+static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	const struct inet_connection_sock *icsk = inet_csk(sk);
 	long m = mrtt; /* RTT */
 
 	/*	The following amusing code comes from Jacobson's
@@ -565,7 +546,7 @@
 	 *
 	 * Funny. This algorithm seems to be very broken.
 	 * These formulae increase RTO, when it should be decreased, increase
-	 * too slowly, when it should be incresed fastly, decrease too fastly
+	 * too slowly, when it should be increased fastly, decrease too fastly
 	 * etc. I guess in BSD RTO takes ONE value, so that it is absolutely
 	 * does not matter how to _calculate_ it. Seems, it was trap
 	 * that VJ failed to avoid. 8)
@@ -610,9 +591,6 @@
 		tp->mdev_max = tp->rttvar = max(tp->mdev, TCP_RTO_MIN);
 		tp->rtt_seq = tp->snd_nxt;
 	}
-
-	if (icsk->icsk_ca_ops->rtt_sample)
-		icsk->icsk_ca_ops->rtt_sample(sk, *usrtt);
 }
 
 /* Calculate rto without backoff.  This is the second half of Van Jacobson's
@@ -629,14 +607,14 @@
 	 *    at least by solaris and freebsd. "Erratic ACKs" has _nothing_
 	 *    to do with delayed acks, because at cwnd>2 true delack timeout
 	 *    is invisible. Actually, Linux-2.4 also generates erratic
-	 *    ACKs in some curcumstances.
+	 *    ACKs in some circumstances.
 	 */
 	inet_csk(sk)->icsk_rto = (tp->srtt >> 3) + tp->rttvar;
 
 	/* 2. Fixups made earlier cannot be right.
 	 *    If we do not estimate RTO correctly without them,
 	 *    all the algo is pure shit and should be replaced
-	 *    with correct one. It is exaclty, which we pretend to do.
+	 *    with correct one. It is exactly, which we pretend to do.
 	 */
 }
 
@@ -794,7 +772,7 @@
 	 * to make it more realistic.
 	 *
 	 * A bit of theory. RTT is time passed after "normal" sized packet
-	 * is sent until it is ACKed. In normal curcumstances sending small
+	 * is sent until it is ACKed. In normal circumstances sending small
 	 * packets force peer to delay ACKs and calculation is correct too.
 	 * The algorithm is adaptive and, provided we follow specs, it
 	 * NEVER underestimate RTT. BUT! If peer tries to make some clever
@@ -919,18 +897,32 @@
 	int prior_fackets;
 	u32 lost_retrans = 0;
 	int flag = 0;
+	int dup_sack = 0;
 	int i;
 
 	if (!tp->sacked_out)
 		tp->fackets_out = 0;
 	prior_fackets = tp->fackets_out;
 
-	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 = 0;
-		int dup_sack = 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);
+
+		if (i == 0){
+			if (tp->recv_sack_cache[i].start_seq != start_seq)
+				flag = 0;
+		} else {
+			if ((tp->recv_sack_cache[i].start_seq != start_seq) ||
+			    (tp->recv_sack_cache[i].end_seq != end_seq))
+				flag = 0;
+		}
+		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) {
@@ -962,15 +954,58 @@
 			if (before(ack, prior_snd_una - tp->max_window))
 				return 0;
 		}
+	}
+
+	if (flag)
+		num_sacks = 1;
+	else {
+		int j;
+		tp->fastpath_skb_hint = NULL;
+
+		/* order SACK blocks to allow in order walk of the retrans queue */
+		for (i = num_sacks-1; i > 0; i--) {
+			for (j = 0; j < i; j++){
+				if (after(ntohl(sp[j].start_seq),
+					  ntohl(sp[j+1].start_seq))){
+					sp[j].start_seq = htonl(tp->recv_sack_cache[j+1].start_seq);
+					sp[j].end_seq = htonl(tp->recv_sack_cache[j+1].end_seq);
+					sp[j+1].start_seq = htonl(tp->recv_sack_cache[j].start_seq);
+					sp[j+1].end_seq = htonl(tp->recv_sack_cache[j].end_seq);
+				}
+
+			}
+		}
+	}
+
+	/* clear flag as used for different purpose in following code */
+	flag = 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;
+		}
 
 		/* Event "B" in the comment above. */
 		if (after(end_seq, tp->high_seq))
 			flag |= FLAG_DATA_LOST;
 
-		sk_stream_for_retrans_queue(skb, sk) {
+		sk_stream_for_retrans_queue_from(skb, sk) {
 			int in_sack, pcount;
 			u8 sacked;
 
+			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.
 			 */
@@ -1045,6 +1080,9 @@
 						TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
 						tp->lost_out -= tcp_skb_pcount(skb);
 						tp->retrans_out -= tcp_skb_pcount(skb);
+
+						/* clear lost hint */
+						tp->retransmit_skb_hint = NULL;
 					}
 				} else {
 					/* New sack for not retransmitted frame,
@@ -1057,6 +1095,9 @@
 					if (sacked & TCPCB_LOST) {
 						TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
 						tp->lost_out -= tcp_skb_pcount(skb);
+
+						/* clear lost hint */
+						tp->retransmit_skb_hint = NULL;
 					}
 				}
 
@@ -1080,6 +1121,7 @@
 			    (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS)) {
 				TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
 				tp->retrans_out -= tcp_skb_pcount(skb);
+				tp->retransmit_skb_hint = NULL;
 			}
 		}
 	}
@@ -1107,6 +1149,9 @@
 				TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
 				tp->retrans_out -= tcp_skb_pcount(skb);
 
+				/* clear lost hint */
+				tp->retransmit_skb_hint = NULL;
+
 				if (!(TCP_SKB_CB(skb)->sacked&(TCPCB_LOST|TCPCB_SACKED_ACKED))) {
 					tp->lost_out += tcp_skb_pcount(skb);
 					TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
@@ -1214,6 +1259,8 @@
 	tcp_set_ca_state(sk, TCP_CA_Loss);
 	tp->high_seq = tp->frto_highmark;
 	TCP_ECN_queue_cwr(tp);
+
+	clear_all_retrans_hints(tp);
 }
 
 void tcp_clear_retrans(struct tcp_sock *tp)
@@ -1251,6 +1298,7 @@
 	tp->snd_cwnd_cnt   = 0;
 	tp->snd_cwnd_stamp = tcp_time_stamp;
 
+	tp->bytes_acked = 0;
 	tcp_clear_retrans(tp);
 
 	/* Push undo marker, if it was plain RTO and nothing
@@ -1279,6 +1327,8 @@
 	tcp_set_ca_state(sk, TCP_CA_Loss);
 	tp->high_seq = tp->snd_nxt;
 	TCP_ECN_queue_cwr(tp);
+
+	clear_all_retrans_hints(tp);
 }
 
 static int tcp_check_sack_reneging(struct sock *sk)
@@ -1503,17 +1553,37 @@
 			       int packets, u32 high_seq)
 {
 	struct sk_buff *skb;
-	int cnt = packets;
+	int cnt;
 
-	BUG_TRAP(cnt <= tp->packets_out);
+	BUG_TRAP(packets <= tp->packets_out);
+	if (tp->lost_skb_hint) {
+		skb = tp->lost_skb_hint;
+		cnt = tp->lost_cnt_hint;
+	} else {
+		skb = sk->sk_write_queue.next;
+		cnt = 0;
+	}
 
-	sk_stream_for_retrans_queue(skb, sk) {
-		cnt -= tcp_skb_pcount(skb);
-		if (cnt < 0 || after(TCP_SKB_CB(skb)->end_seq, high_seq))
+	sk_stream_for_retrans_queue_from(skb, sk) {
+		/* TODO: do this better */
+		/* this is not the most efficient way to do this... */
+		tp->lost_skb_hint = skb;
+		tp->lost_cnt_hint = cnt;
+		cnt += tcp_skb_pcount(skb);
+		if (cnt > packets || after(TCP_SKB_CB(skb)->end_seq, high_seq))
 			break;
 		if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) {
 			TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
 			tp->lost_out += tcp_skb_pcount(skb);
+
+			/* clear xmit_retransmit_queue hints
+			 *  if this is beyond hint */
+			if(tp->retransmit_skb_hint != NULL &&
+			   before(TCP_SKB_CB(skb)->seq,
+				  TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) {
+
+				tp->retransmit_skb_hint = NULL;
+			}
 		}
 	}
 	tcp_sync_left_out(tp);
@@ -1540,13 +1610,28 @@
 	if (tcp_head_timedout(sk, tp)) {
 		struct sk_buff *skb;
 
-		sk_stream_for_retrans_queue(skb, sk) {
-			if (tcp_skb_timedout(sk, skb) &&
-			    !(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) {
+		skb = tp->scoreboard_skb_hint ? tp->scoreboard_skb_hint
+			: sk->sk_write_queue.next;
+
+		sk_stream_for_retrans_queue_from(skb, sk) {
+			if (!tcp_skb_timedout(sk, skb))
+				break;
+
+			if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) {
 				TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
 				tp->lost_out += tcp_skb_pcount(skb);
+
+				/* clear xmit_retrans hint */
+				if (tp->retransmit_skb_hint &&
+				    before(TCP_SKB_CB(skb)->seq,
+					   TCP_SKB_CB(tp->retransmit_skb_hint)->seq))
+
+					tp->retransmit_skb_hint = NULL;
 			}
 		}
+
+		tp->scoreboard_skb_hint = skb;
+
 		tcp_sync_left_out(tp);
 	}
 }
@@ -1626,6 +1711,10 @@
 	}
 	tcp_moderate_cwnd(tp);
 	tp->snd_cwnd_stamp = tcp_time_stamp;
+
+	/* There is something screwy going on with the retrans hints after
+	   an undo */
+	clear_all_retrans_hints(tp);
 }
 
 static inline int tcp_may_undo(struct tcp_sock *tp)
@@ -1709,6 +1798,9 @@
 		sk_stream_for_retrans_queue(skb, sk) {
 			TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
 		}
+
+		clear_all_retrans_hints(tp);
+
 		DBGUNDO(sk, tp, "partial loss");
 		tp->lost_out = 0;
 		tp->left_out = tp->sacked_out;
@@ -1908,6 +2000,7 @@
 			TCP_ECN_queue_cwr(tp);
 		}
 
+		tp->bytes_acked = 0;
 		tp->snd_cwnd_cnt = 0;
 		tcp_set_ca_state(sk, TCP_CA_Recovery);
 	}
@@ -1919,9 +2012,9 @@
 }
 
 /* Read draft-ietf-tcplw-high-performance before mucking
- * with this code. (Superceeds RFC1323)
+ * with this code. (Supersedes RFC1323)
  */
-static void tcp_ack_saw_tstamp(struct sock *sk, u32 *usrtt, int flag)
+static void tcp_ack_saw_tstamp(struct sock *sk, int flag)
 {
 	/* RTTM Rule: A TSecr value received in a segment is used to
 	 * update the averaged RTT measurement only if the segment
@@ -1932,7 +2025,7 @@
 	 * 1998/04/10 Andrey V. Savochkin <saw@msu.ru>
 	 *
 	 * Changed: reset backoff as soon as we see the first valid sample.
-	 * If we do not, we get strongly overstimated rto. With timestamps
+	 * If we do not, we get strongly overestimated rto. With timestamps
 	 * samples are accepted even from very old segments: f.e., when rtt=1
 	 * increases to 8, we retransmit 5 times and after 8 seconds delayed
 	 * answer arrives rto becomes 120 seconds! If at least one of segments
@@ -1940,13 +2033,13 @@
 	 */
 	struct tcp_sock *tp = tcp_sk(sk);
 	const __u32 seq_rtt = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
-	tcp_rtt_estimator(sk, seq_rtt, usrtt);
+	tcp_rtt_estimator(sk, seq_rtt);
 	tcp_set_rto(sk);
 	inet_csk(sk)->icsk_backoff = 0;
 	tcp_bound_rto(sk);
 }
 
-static void tcp_ack_no_tstamp(struct sock *sk, u32 seq_rtt, u32 *usrtt, int flag)
+static void tcp_ack_no_tstamp(struct sock *sk, u32 seq_rtt, int flag)
 {
 	/* We don't have a timestamp. Can only use
 	 * packets that are not retransmitted to determine
@@ -1960,21 +2053,21 @@
 	if (flag & FLAG_RETRANS_DATA_ACKED)
 		return;
 
-	tcp_rtt_estimator(sk, seq_rtt, usrtt);
+	tcp_rtt_estimator(sk, seq_rtt);
 	tcp_set_rto(sk);
 	inet_csk(sk)->icsk_backoff = 0;
 	tcp_bound_rto(sk);
 }
 
 static inline void tcp_ack_update_rtt(struct sock *sk, const int flag,
-				      const s32 seq_rtt, u32 *usrtt)
+				      const s32 seq_rtt)
 {
 	const struct tcp_sock *tp = tcp_sk(sk);
 	/* Note that peer MAY send zero echo. In this case it is ignored. (rfc1323) */
 	if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr)
-		tcp_ack_saw_tstamp(sk, usrtt, flag);
+		tcp_ack_saw_tstamp(sk, flag);
 	else if (seq_rtt >= 0)
-		tcp_ack_no_tstamp(sk, seq_rtt, usrtt, flag);
+		tcp_ack_no_tstamp(sk, seq_rtt, flag);
 }
 
 static inline void tcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
@@ -2054,20 +2147,27 @@
 	return acked;
 }
 
+static inline u32 tcp_usrtt(const struct sk_buff *skb)
+{
+	struct timeval tv, now;
+
+	do_gettimeofday(&now);
+	skb_get_timestamp(skb, &tv);
+	return (now.tv_sec - tv.tv_sec) * 1000000 + (now.tv_usec - tv.tv_usec);
+}
 
 /* Remove acknowledged frames from the retransmission queue. */
-static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p, s32 *seq_usrtt)
+static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
+	const struct inet_connection_sock *icsk = inet_csk(sk);
 	struct sk_buff *skb;
 	__u32 now = tcp_time_stamp;
 	int acked = 0;
 	__s32 seq_rtt = -1;
-	struct timeval usnow;
 	u32 pkts_acked = 0;
-
-	if (seq_usrtt)
-		do_gettimeofday(&usnow);
+	void (*rtt_sample)(struct sock *sk, u32 usrtt)
+		= icsk->icsk_ca_ops->rtt_sample;
 
 	while ((skb = skb_peek(&sk->sk_write_queue)) &&
 	       skb != sk->sk_send_head) {
@@ -2107,16 +2207,11 @@
 					tp->retrans_out -= tcp_skb_pcount(skb);
 				acked |= FLAG_RETRANS_DATA_ACKED;
 				seq_rtt = -1;
-			} else if (seq_rtt < 0)
+			} else if (seq_rtt < 0) {
 				seq_rtt = now - scb->when;
-			if (seq_usrtt) {
-				struct timeval tv;
-			
-				skb_get_timestamp(skb, &tv);
-				*seq_usrtt = (usnow.tv_sec - tv.tv_sec) * 1000000
-					+ (usnow.tv_usec - tv.tv_usec);
+				if (rtt_sample)
+					(*rtt_sample)(sk, tcp_usrtt(skb));
 			}
-
 			if (sacked & TCPCB_SACKED_ACKED)
 				tp->sacked_out -= tcp_skb_pcount(skb);
 			if (sacked & TCPCB_LOST)
@@ -2126,17 +2221,20 @@
 				    !before(scb->end_seq, tp->snd_up))
 					tp->urg_mode = 0;
 			}
-		} else if (seq_rtt < 0)
+		} else if (seq_rtt < 0) {
 			seq_rtt = now - scb->when;
+			if (rtt_sample)
+				(*rtt_sample)(sk, tcp_usrtt(skb));
+		}
 		tcp_dec_pcount_approx(&tp->fackets_out, skb);
 		tcp_packets_out_dec(tp, skb);
 		__skb_unlink(skb, &sk->sk_write_queue);
 		sk_stream_free_skb(sk, skb);
+		clear_all_retrans_hints(tp);
 	}
 
 	if (acked&FLAG_ACKED) {
-		const struct inet_connection_sock *icsk = inet_csk(sk);
-		tcp_ack_update_rtt(sk, acked, seq_rtt, seq_usrtt);
+		tcp_ack_update_rtt(sk, acked, seq_rtt);
 		tcp_ack_packets_out(sk, tp);
 
 		if (icsk->icsk_ca_ops->pkts_acked)
@@ -2284,7 +2382,7 @@
 	}
 
 	/* F-RTO affects on two new ACKs following RTO.
-	 * At latest on third ACK the TCP behavor is back to normal.
+	 * At latest on third ACK the TCP behavior is back to normal.
 	 */
 	tp->frto_counter = (tp->frto_counter + 1) % 3;
 }
@@ -2299,7 +2397,6 @@
 	u32 ack = TCP_SKB_CB(skb)->ack_seq;
 	u32 prior_in_flight;
 	s32 seq_rtt;
-	s32 seq_usrtt = 0;
 	int prior_packets;
 
 	/* If the ack is newer than sent or older than previous acks
@@ -2311,6 +2408,9 @@
 	if (before(ack, prior_snd_una))
 		goto old_ack;
 
+	if (sysctl_tcp_abc && icsk->icsk_ca_state < TCP_CA_CWR)
+		tp->bytes_acked += ack - prior_snd_una;
+
 	if (!(flag&FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
 		/* Window is constant, pure forward advance.
 		 * No more checks are required.
@@ -2352,14 +2452,13 @@
 	prior_in_flight = tcp_packets_in_flight(tp);
 
 	/* See if we can take anything off of the retransmit queue. */
-	flag |= tcp_clean_rtx_queue(sk, &seq_rtt,
-				    icsk->icsk_ca_ops->rtt_sample ? &seq_usrtt : NULL);
+	flag |= tcp_clean_rtx_queue(sk, &seq_rtt);
 
 	if (tp->frto_counter)
 		tcp_process_frto(sk, prior_snd_una);
 
 	if (tcp_ack_is_dubious(sk, flag)) {
-		/* Advanve CWND, if state allows this. */
+		/* Advance CWND, if state allows this. */
 		if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(sk, flag))
 			tcp_cong_avoid(sk, ack,  seq_rtt, prior_in_flight, 0);
 		tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
@@ -3148,7 +3247,7 @@
 {
 	struct sk_buff *skb;
 
-	/* First, check that queue is collapsable and find
+	/* First, check that queue is collapsible and find
 	 * the point where collapsing can be useful. */
 	for (skb = head; skb != tail; ) {
 		/* No new bits? It is possible on ofo queue. */
@@ -3456,7 +3555,7 @@
 
 /*
  *	This routine is only called when we have urgent data
- *	signalled. Its the 'slow' part of tcp_urg. It could be
+ *	signaled. Its the 'slow' part of tcp_urg. It could be
  *	moved inline now as tcp_urg is only called from one
  *	place. We handle URGent data wrong. We have to - as
  *	BSD still doesn't use the correction from RFC961.
@@ -3501,7 +3600,7 @@
 	 * urgent. To do this requires some care. We cannot just ignore
 	 * tp->copied_seq since we would read the last urgent byte again
 	 * as data, nor can we alter copied_seq until this data arrives
-	 * or we break the sematics of SIOCATMARK (and thus sockatmark())
+	 * or we break the semantics of SIOCATMARK (and thus sockatmark())
 	 *
 	 * NOTE. Double Dutch. Rendering to plain English: author of comment
 	 * above did something sort of 	send("A", MSG_OOB); send("B", MSG_OOB);
@@ -3646,7 +3745,7 @@
 	tp->rx_opt.saw_tstamp = 0;
 
 	/*	pred_flags is 0xS?10 << 16 + snd_wnd
-	 *	if header_predition is to be made
+	 *	if header_prediction is to be made
 	 *	'S' will always be tp->tcp_header_len >> 2
 	 *	'?' will be 0 for the fast path, otherwise pred_flags is 0 to
 	 *  turn it off	(when there are holes in the receive 
@@ -4242,7 +4341,7 @@
 				 */
 				if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&
 				    !tp->srtt)
-					tcp_ack_saw_tstamp(sk, NULL, 0);
+					tcp_ack_saw_tstamp(sk, 0);
 
 				if (tp->rx_opt.tstamp_ok)
 					tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;
@@ -4372,6 +4471,7 @@
 
 EXPORT_SYMBOL(sysctl_tcp_ecn);
 EXPORT_SYMBOL(sysctl_tcp_reordering);
+EXPORT_SYMBOL(sysctl_tcp_abc);
 EXPORT_SYMBOL(tcp_parse_options);
 EXPORT_SYMBOL(tcp_rcv_established);
 EXPORT_SYMBOL(tcp_rcv_state_process);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 49d67cd..4d5021e 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -39,7 +39,7 @@
  *					request_sock handling and moved
  *					most of it into the af independent code.
  *					Added tail drop and some other bugfixes.
- *					Added new listen sematics.
+ *					Added new listen semantics.
  *		Mike McLagan	:	Routing by source
  *	Juan Jose Ciarlante:		ip_dynaddr bits
  *		Andi Kleen:		various fixes.
@@ -823,8 +823,7 @@
  */
 static void tcp_v4_reqsk_destructor(struct request_sock *req)
 {
-	if (inet_rsk(req)->opt)
-		kfree(inet_rsk(req)->opt);
+	kfree(inet_rsk(req)->opt);
 }
 
 static inline void syn_flood_warning(struct sk_buff *skb)
@@ -1111,24 +1110,18 @@
 static int tcp_v4_checksum_init(struct sk_buff *skb)
 {
 	if (skb->ip_summed == CHECKSUM_HW) {
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
 		if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr,
-				  skb->nh.iph->daddr, skb->csum))
+				  skb->nh.iph->daddr, skb->csum)) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			return 0;
-
-		LIMIT_NETDEBUG(KERN_DEBUG "hw tcp v4 csum failed\n");
-		skb->ip_summed = CHECKSUM_NONE;
+		}
 	}
+
+	skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, skb->nh.iph->daddr,
+				       skb->len, IPPROTO_TCP, 0);
+
 	if (skb->len <= 76) {
-		if (tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr,
-				 skb->nh.iph->daddr,
-				 skb_checksum(skb, 0, skb->len, 0)))
-			return -1;
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	} else {
-		skb->csum = ~tcp_v4_check(skb->h.th, skb->len,
-					  skb->nh.iph->saddr,
-					  skb->nh.iph->daddr, 0);
+		return __skb_checksum_complete(skb);
 	}
 	return 0;
 }
@@ -1217,10 +1210,10 @@
 
 	/* An explanation is required here, I think.
 	 * Packet length and doff are validated by header prediction,
-	 * provided case of th->doff==0 is elimineted.
+	 * provided case of th->doff==0 is eliminated.
 	 * So, we defer the checks. */
 	if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
-	     tcp_v4_checksum_init(skb) < 0))
+	     tcp_v4_checksum_init(skb)))
 		goto bad_packet;
 
 	th = skb->h.th;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index b1a63b2..1b66a2a 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -158,7 +158,7 @@
 		/* I am shamed, but failed to make it more elegant.
 		 * Yes, it is direct reference to IP, which is impossible
 		 * to generalize to IPv6. Taking into account that IPv6
-		 * do not undertsnad recycling in any case, it not
+		 * do not understand recycling in any case, it not
 		 * a big problem in practice. --ANK */
 		if (tw->tw_family == AF_INET &&
 		    tcp_death_row.sysctl_tw_recycle && tcptw->tw_ts_recent_stamp &&
@@ -194,7 +194,7 @@
 		/* In window segment, it may be only reset or bare ack. */
 
 		if (th->rst) {
-			/* This is TIME_WAIT assasination, in two flavors.
+			/* This is TIME_WAIT assassination, in two flavors.
 			 * Oh well... nobody has a sufficient solution to this
 			 * protocol bug yet.
 			 */
@@ -380,6 +380,7 @@
 		 */
 		newtp->snd_cwnd = 2;
 		newtp->snd_cwnd_cnt = 0;
+		newtp->bytes_acked = 0;
 
 		newtp->frto_counter = 0;
 		newtp->frto_highmark = 0;
@@ -550,7 +551,7 @@
 
 	/* RFC793 page 36: "If the connection is in any non-synchronized state ...
 	 *                  and the incoming segment acknowledges something not yet
-	 *                  sent (the segment carries an unaccaptable ACK) ...
+	 *                  sent (the segment carries an unacceptable ACK) ...
 	 *                  a reset is sent."
 	 *
 	 * Invalid ACK: reset will be sent by listening socket
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index b907456..029c70d 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -436,6 +436,8 @@
 	u16 flags;
 
 	BUG_ON(len > skb->len);
+
+ 	clear_all_retrans_hints(tp);
 	nsize = skb_headlen(skb) - len;
 	if (nsize < 0)
 		nsize = 0;
@@ -599,7 +601,7 @@
    for TCP options, but includes only bare TCP header.
 
    tp->rx_opt.mss_clamp is mss negotiated at connection setup.
-   It is minumum of user_mss and mss received with SYN.
+   It is minimum of user_mss and mss received with SYN.
    It also does not include TCP options.
 
    tp->pmtu_cookie is last pmtu, seen by this function.
@@ -1171,7 +1173,7 @@
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
-	/* MSS for the peer's data.  Previous verions used mss_clamp
+	/* MSS for the peer's data.  Previous versions used mss_clamp
 	 * here.  I don't know if the value based on our guesses
 	 * of peer's MSS is better for the performance.  It's more correct
 	 * but may be worse for the performance because of rcv_mss
@@ -1260,7 +1262,10 @@
 		BUG_ON(tcp_skb_pcount(skb) != 1 ||
 		       tcp_skb_pcount(next_skb) != 1);
 
-		/* Ok.  We will be able to collapse the packet. */
+		/* changing transmit queue under us so clear hints */
+		clear_all_retrans_hints(tp);
+
+		/* Ok.	We will be able to collapse the packet. */
 		__skb_unlink(next_skb, &sk->sk_write_queue);
 
 		memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size);
@@ -1330,6 +1335,8 @@
 		}
 	}
 
+	clear_all_retrans_hints(tp);
+
 	if (!lost)
 		return;
 
@@ -1361,7 +1368,7 @@
 	int err;
 
 	/* Do not sent more than we queued. 1/4 is reserved for possible
-	 * copying overhead: frgagmentation, tunneling, mangling etc.
+	 * copying overhead: fragmentation, tunneling, mangling etc.
 	 */
 	if (atomic_read(&sk->sk_wmem_alloc) >
 	    min(sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), sk->sk_sndbuf))
@@ -1468,13 +1475,25 @@
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
-	int packet_cnt = tp->lost_out;
+	int packet_cnt;
+
+	if (tp->retransmit_skb_hint) {
+		skb = tp->retransmit_skb_hint;
+		packet_cnt = tp->retransmit_cnt_hint;
+	}else{
+		skb = sk->sk_write_queue.next;
+		packet_cnt = 0;
+	}
 
 	/* First pass: retransmit lost packets. */
-	if (packet_cnt) {
-		sk_stream_for_retrans_queue(skb, sk) {
+	if (tp->lost_out) {
+		sk_stream_for_retrans_queue_from(skb, sk) {
 			__u8 sacked = TCP_SKB_CB(skb)->sacked;
 
+			/* we could do better than to assign each time */
+			tp->retransmit_skb_hint = skb;
+			tp->retransmit_cnt_hint = packet_cnt;
+
 			/* Assume this retransmit will generate
 			 * only one packet for congestion window
 			 * calculation purposes.  This works because
@@ -1485,10 +1504,12 @@
 			if (tcp_packets_in_flight(tp) >= tp->snd_cwnd)
 				return;
 
-			if (sacked&TCPCB_LOST) {
+			if (sacked & TCPCB_LOST) {
 				if (!(sacked&(TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))) {
-					if (tcp_retransmit_skb(sk, skb))
+					if (tcp_retransmit_skb(sk, skb)) {
+						tp->retransmit_skb_hint = NULL;
 						return;
+					}
 					if (icsk->icsk_ca_state != TCP_CA_Loss)
 						NET_INC_STATS_BH(LINUX_MIB_TCPFASTRETRANS);
 					else
@@ -1501,8 +1522,8 @@
 									  TCP_RTO_MAX);
 				}
 
-				packet_cnt -= tcp_skb_pcount(skb);
-				if (packet_cnt <= 0)
+				packet_cnt += tcp_skb_pcount(skb);
+				if (packet_cnt >= tp->lost_out)
 					break;
 			}
 		}
@@ -1528,9 +1549,18 @@
 	if (tcp_may_send_now(sk, tp))
 		return;
 
-	packet_cnt = 0;
+	if (tp->forward_skb_hint) {
+		skb = tp->forward_skb_hint;
+		packet_cnt = tp->forward_cnt_hint;
+	} else{
+		skb = sk->sk_write_queue.next;
+		packet_cnt = 0;
+	}
 
-	sk_stream_for_retrans_queue(skb, sk) {
+	sk_stream_for_retrans_queue_from(skb, sk) {
+		tp->forward_cnt_hint = packet_cnt;
+		tp->forward_skb_hint = skb;
+
 		/* Similar to the retransmit loop above we
 		 * can pretend that the retransmitted SKB
 		 * we send out here will be composed of one
@@ -1547,8 +1577,10 @@
 			continue;
 
 		/* Ok, retransmit it. */
-		if (tcp_retransmit_skb(sk, skb))
+		if (tcp_retransmit_skb(sk, skb)) {
+			tp->forward_skb_hint = NULL;
 			break;
+		}
 
 		if (skb == skb_peek(&sk->sk_write_queue))
 			inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
@@ -2058,3 +2090,4 @@
 EXPORT_SYMBOL(tcp_make_synack);
 EXPORT_SYMBOL(tcp_simple_retransmit);
 EXPORT_SYMBOL(tcp_sync_mss);
+EXPORT_SYMBOL(sysctl_tcp_tso_win_divisor);
diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c
index 327770b..26d7486 100644
--- a/net/ipv4/tcp_scalable.c
+++ b/net/ipv4/tcp_scalable.c
@@ -20,20 +20,20 @@
 				    u32 in_flight, int flag)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	if (in_flight < tp->snd_cwnd)
+
+	if (!tcp_is_cwnd_limited(sk, in_flight))
 		return;
 
-	if (tp->snd_cwnd <= tp->snd_ssthresh) {
-		tp->snd_cwnd++;
-	} else {
+	if (tp->snd_cwnd <= tp->snd_ssthresh)
+		tcp_slow_start(tp);
+	else {
 		tp->snd_cwnd_cnt++;
 		if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){
-			tp->snd_cwnd++;
+			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+				tp->snd_cwnd++;
 			tp->snd_cwnd_cnt = 0;
 		}
 	}
-	tp->snd_cwnd = min_t(u32, tp->snd_cwnd, tp->snd_cwnd_clamp);
-	tp->snd_cwnd_stamp = tcp_time_stamp;
 }
 
 static u32 tcp_scalable_ssthresh(struct sock *sk)
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 415ee47..e188095 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -58,7 +58,7 @@
  * to prevent DoS attacks. It is called when a retransmission timeout
  * or zero probe timeout occurs on orphaned socket.
  *
- * Criterium is still not confirmed experimentally and may change.
+ * Criteria is still not confirmed experimentally and may change.
  * We kill the socket, if:
  * 1. If number of orphaned sockets exceeds an administratively configured
  *    limit.
@@ -132,7 +132,7 @@
 			   hole detection. :-(
 
 			   It is place to make it. It is not made. I do not want
-			   to make it. It is disguisting. It does not work in any
+			   to make it. It is disgusting. It does not work in any
 			   case. Let me to cite the same draft, which requires for
 			   us to implement this:
 
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
index 93c5f92..b7d296a 100644
--- a/net/ipv4/tcp_vegas.c
+++ b/net/ipv4/tcp_vegas.c
@@ -236,8 +236,7 @@
 			/* We don't have enough RTT samples to do the Vegas
 			 * calculation, so we'll behave like Reno.
 			 */
-			if (tp->snd_cwnd > tp->snd_ssthresh)
-				tp->snd_cwnd++;
+			tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
 		} else {
 			u32 rtt, target_cwnd, diff;
 
@@ -275,7 +274,7 @@
 			 */
 			diff = (old_wnd << V_PARAM_SHIFT) - target_cwnd;
 
-			if (tp->snd_cwnd < tp->snd_ssthresh) {
+			if (tp->snd_cwnd <= tp->snd_ssthresh) {
 				/* Slow start.  */
 				if (diff > gamma) {
 					/* Going too fast. Time to slow down
@@ -295,6 +294,7 @@
 							    V_PARAM_SHIFT)+1);
 
 				}
+				tcp_slow_start(tp);
 			} else {
 				/* Congestion avoidance. */
 				u32 next_snd_cwnd;
@@ -327,37 +327,17 @@
 				else if (next_snd_cwnd < tp->snd_cwnd)
 					tp->snd_cwnd--;
 			}
-		}
 
-		/* Wipe the slate clean for the next RTT. */
-		vegas->cntRTT = 0;
-		vegas->minRTT = 0x7fffffff;
+			if (tp->snd_cwnd < 2)
+				tp->snd_cwnd = 2;
+			else if (tp->snd_cwnd > tp->snd_cwnd_clamp)
+				tp->snd_cwnd = tp->snd_cwnd_clamp;
+		}
 	}
 
-	/* The following code is executed for every ack we receive,
-	 * except for conditions checked in should_advance_cwnd()
-	 * before the call to tcp_cong_avoid(). Mainly this means that
-	 * we only execute this code if the ack actually acked some
-	 * data.
-	 */
-
-	/* If we are in slow start, increase our cwnd in response to this ACK.
-	 * (If we are not in slow start then we are in congestion avoidance,
-	 * and adjust our congestion window only once per RTT. See the code
-	 * above.)
-	 */
-	if (tp->snd_cwnd <= tp->snd_ssthresh)
-		tp->snd_cwnd++;
-
-	/* to keep cwnd from growing without bound */
-	tp->snd_cwnd = min_t(u32, tp->snd_cwnd, tp->snd_cwnd_clamp);
-
-	/* Make sure that we are never so timid as to reduce our cwnd below
-	 * 2 MSS.
-	 *
-	 * Going below 2 MSS would risk huge delayed ACKs from our receiver.
-	 */
-	tp->snd_cwnd = max(tp->snd_cwnd, 2U);
+	/* Wipe the slate clean for the next RTT. */
+	vegas->cntRTT = 0;
+	vegas->minRTT = 0x7fffffff;
 }
 
 /* Extract info for Tcp socket info provided via netlink. */
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index e0bd101..2422a5f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -761,7 +761,7 @@
 
 static __inline__ int __udp_checksum_complete(struct sk_buff *skb)
 {
-	return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
+	return __skb_checksum_complete(skb);
 }
 
 static __inline__ int udp_checksum_complete(struct sk_buff *skb)
@@ -1100,11 +1100,8 @@
 	if (uh->check == 0) {
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	} else if (skb->ip_summed == CHECKSUM_HW) {
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
 		if (!udp_check(uh, ulen, saddr, daddr, skb->csum))
-			return 0;
-		LIMIT_NETDEBUG(KERN_DEBUG "udp v4 hw csum failure.\n");
-		skb->ip_summed = CHECKSUM_NONE;
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
 	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
 		skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2c5f572..ddcf775 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -35,6 +35,9 @@
  *	YOSHIFUJI Hideaki @USAGI	:	ARCnet support
  *	YOSHIFUJI Hideaki @USAGI	:	convert /proc/net/if_inet6 to
  *						seq_file.
+ *	YOSHIFUJI Hideaki @USAGI	:	improved source address
+ *						selection; consider scope,
+ *						status etc.
  */
 
 #include <linux/config.h>
@@ -193,46 +196,51 @@
 #endif
 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 
-int ipv6_addr_type(const struct in6_addr *addr)
+#define IPV6_ADDR_SCOPE_TYPE(scope)	((scope) << 16)
+
+static inline unsigned ipv6_addr_scope2type(unsigned scope)
 {
-	int type;
+	switch(scope) {
+	case IPV6_ADDR_SCOPE_NODELOCAL:
+		return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
+			IPV6_ADDR_LOOPBACK);
+	case IPV6_ADDR_SCOPE_LINKLOCAL:
+		return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
+			IPV6_ADDR_LINKLOCAL);
+	case IPV6_ADDR_SCOPE_SITELOCAL:
+		return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
+			IPV6_ADDR_SITELOCAL);
+	}
+	return IPV6_ADDR_SCOPE_TYPE(scope);
+}
+
+int __ipv6_addr_type(const struct in6_addr *addr)
+{
 	u32 st;
 
 	st = addr->s6_addr32[0];
 
-	if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
-		type = IPV6_ADDR_MULTICAST;
-
-		switch((st & htonl(0x00FF0000))) {
-			case __constant_htonl(0x00010000):
-				type |= IPV6_ADDR_LOOPBACK;
-				break;
-
-			case __constant_htonl(0x00020000):
-				type |= IPV6_ADDR_LINKLOCAL;
-				break;
-
-			case __constant_htonl(0x00050000):
-				type |= IPV6_ADDR_SITELOCAL;
-				break;
-		};
-		return type;
-	}
-
-	type = IPV6_ADDR_UNICAST;
-
 	/* Consider all addresses with the first three bits different of
-	   000 and 111 as finished.
+	   000 and 111 as unicasts.
 	 */
 	if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
 	    (st & htonl(0xE0000000)) != htonl(0xE0000000))
-		return type;
-	
-	if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
-		return (IPV6_ADDR_LINKLOCAL | type);
+		return (IPV6_ADDR_UNICAST | 
+			IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
 
+	if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
+		/* multicast */
+		/* addr-select 3.1 */
+		return (IPV6_ADDR_MULTICAST |
+			ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
+	}
+
+	if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
+		return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST | 
+			IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));		/* addr-select 3.1 */
 	if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
-		return (IPV6_ADDR_SITELOCAL | type);
+		return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
+			IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));		/* addr-select 3.1 */
 
 	if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
 		if (addr->s6_addr32[2] == 0) {
@@ -240,24 +248,20 @@
 				return IPV6_ADDR_ANY;
 
 			if (addr->s6_addr32[3] == htonl(0x00000001))
-				return (IPV6_ADDR_LOOPBACK | type);
+				return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
+					IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));	/* addr-select 3.4 */
 
-			return (IPV6_ADDR_COMPATv4 | type);
+			return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
+				IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));	/* addr-select 3.3 */
 		}
 
 		if (addr->s6_addr32[2] == htonl(0x0000ffff))
-			return IPV6_ADDR_MAPPED;
+			return (IPV6_ADDR_MAPPED | 
+				IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));	/* addr-select 3.3 */
 	}
 
-	st &= htonl(0xFF000000);
-	if (st == 0)
-		return IPV6_ADDR_RESERVED;
-	st &= htonl(0xFE000000);
-	if (st == htonl(0x02000000))
-		return IPV6_ADDR_RESERVED;	/* for NSAP */
-	if (st == htonl(0x04000000))
-		return IPV6_ADDR_RESERVED;	/* for IPX */
-	return type;
+	return (IPV6_ADDR_RESERVED | 
+		IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));	/* addr-select 3.4 */
 }
 
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
@@ -805,138 +809,275 @@
 #endif
 
 /*
- *	Choose an appropriate source address
- *	should do:
- *	i)	get an address with an appropriate scope
- *	ii)	see if there is a specific route for the destination and use
- *		an address of the attached interface 
- *	iii)	don't use deprecated addresses
+ *	Choose an appropriate source address (RFC3484)
  */
-static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref)
+struct ipv6_saddr_score {
+	int		addr_type;
+	unsigned int	attrs;
+	int		matchlen;
+	unsigned int	scope;
+	unsigned int	rule;
+};
+
+#define IPV6_SADDR_SCORE_LOCAL		0x0001
+#define IPV6_SADDR_SCORE_PREFERRED	0x0004
+#define IPV6_SADDR_SCORE_HOA		0x0008
+#define IPV6_SADDR_SCORE_OIF		0x0010
+#define IPV6_SADDR_SCORE_LABEL		0x0020
+#define IPV6_SADDR_SCORE_PRIVACY	0x0040
+
+static int inline ipv6_saddr_preferred(int type)
 {
-	int pref;
-	pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2;
-#ifdef CONFIG_IPV6_PRIVACY
-	pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1;
-#endif
-	return pref;
+	if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|
+		    IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED))
+		return 1;
+	return 0;
 }
 
-#ifdef CONFIG_IPV6_PRIVACY
-#define IPV6_GET_SADDR_MAXSCORE(score)	((score) == 3)
-#else
-#define IPV6_GET_SADDR_MAXSCORE(score)	(score)
-#endif
+/* static matching label */
+static int inline ipv6_saddr_label(const struct in6_addr *addr, int type)
+{
+ /*
+  * 	prefix (longest match)	label
+  * 	-----------------------------
+  * 	::1/128			0
+  * 	::/0			1
+  * 	2002::/16		2
+  * 	::/96			3
+  * 	::ffff:0:0/96		4
+  */
+	if (type & IPV6_ADDR_LOOPBACK)
+		return 0;
+	else if (type & IPV6_ADDR_COMPATv4)
+		return 3;
+	else if (type & IPV6_ADDR_MAPPED)
+		return 4;
+	else if (addr->s6_addr16[0] == htons(0x2002))
+		return 2;
+	return 1;
+}
 
-int ipv6_dev_get_saddr(struct net_device *dev,
+int ipv6_dev_get_saddr(struct net_device *daddr_dev,
 		       struct in6_addr *daddr, struct in6_addr *saddr)
 {
-	struct inet6_ifaddr *ifp = NULL;
-	struct inet6_ifaddr *match = NULL;
-	struct inet6_dev *idev;
-	int scope;
-	int err;
-	int hiscore = -1, score;
+	struct ipv6_saddr_score hiscore;
+	struct inet6_ifaddr *ifa_result = NULL;
+	int daddr_type = __ipv6_addr_type(daddr);
+	int daddr_scope = __ipv6_addr_src_scope(daddr_type);
+	u32 daddr_label = ipv6_saddr_label(daddr, daddr_type);
+	struct net_device *dev;
 
-	scope = ipv6_addr_scope(daddr);
-
-	/*
-	 *	known dev
-	 *	search dev and walk through dev addresses
-	 */
-
-	if (dev) {
-		if (dev->flags & IFF_LOOPBACK)
-			scope = IFA_HOST;
-
-		read_lock(&addrconf_lock);
-		idev = __in6_dev_get(dev);
-		if (idev) {
-			read_lock_bh(&idev->lock);
-			for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
-				if (ifp->scope == scope) {
-					if (ifp->flags&IFA_F_TENTATIVE)
-						continue;
-#ifdef CONFIG_IPV6_PRIVACY
-					score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
-#else
-					score = ipv6_saddr_pref(ifp, 0);
-#endif
-					if (score <= hiscore)
-						continue;
-
-					if (match)
-						in6_ifa_put(match);
-					match = ifp;
-					hiscore = score;
-					in6_ifa_hold(ifp);
-
-					if (IPV6_GET_SADDR_MAXSCORE(score)) {
-						read_unlock_bh(&idev->lock);
-						read_unlock(&addrconf_lock);
-						goto out;
-					}
-				}
-			}
-			read_unlock_bh(&idev->lock);
-		}
-		read_unlock(&addrconf_lock);
-	}
-
-	if (scope == IFA_LINK)
-		goto out;
-
-	/*
-	 *	dev == NULL or search failed for specified dev
-	 */
+	memset(&hiscore, 0, sizeof(hiscore));
 
 	read_lock(&dev_base_lock);
 	read_lock(&addrconf_lock);
+
 	for (dev = dev_base; dev; dev=dev->next) {
+		struct inet6_dev *idev;
+		struct inet6_ifaddr *ifa;
+
+		/* Rule 0: Candidate Source Address (section 4)
+		 *  - multicast and link-local destination address,
+		 *    the set of candidate source address MUST only
+		 *    include addresses assigned to interfaces
+		 *    belonging to the same link as the outgoing
+		 *    interface.
+		 * (- For site-local destination addresses, the
+		 *    set of candidate source addresses MUST only
+		 *    include addresses assigned to interfaces
+		 *    belonging to the same site as the outgoing
+		 *    interface.)
+		 */
+		if ((daddr_type & IPV6_ADDR_MULTICAST ||
+		     daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
+		    daddr_dev && dev != daddr_dev)
+			continue;
+
 		idev = __in6_dev_get(dev);
-		if (idev) {
-			read_lock_bh(&idev->lock);
-			for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
-				if (ifp->scope == scope) {
-					if (ifp->flags&IFA_F_TENTATIVE)
-						continue;
-#ifdef CONFIG_IPV6_PRIVACY
-					score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
-#else
-					score = ipv6_saddr_pref(ifp, 0);
-#endif
-					if (score <= hiscore)
-						continue;
+		if (!idev)
+			continue;
 
-					if (match)
-						in6_ifa_put(match);
-					match = ifp;
-					hiscore = score;
-					in6_ifa_hold(ifp);
+		read_lock_bh(&idev->lock);
+		for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) {
+			struct ipv6_saddr_score score;
 
-					if (IPV6_GET_SADDR_MAXSCORE(score)) {
-						read_unlock_bh(&idev->lock);
-						goto out_unlock_base;
-					}
+			score.addr_type = __ipv6_addr_type(&ifa->addr);
+
+			/* Rule 0: Candidate Source Address (section 4)
+			 *  - In any case, anycast addresses, multicast
+			 *    addresses, and the unspecified address MUST
+			 *    NOT be included in a candidate set.
+			 */
+			if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
+				     score.addr_type & IPV6_ADDR_MULTICAST)) {
+				LIMIT_NETDEBUG(KERN_DEBUG
+					       "ADDRCONF: unspecified / multicast address"
+					       "assigned as unicast address on %s",
+					       dev->name);
+				continue;
+			}
+
+			score.attrs = 0;
+			score.matchlen = 0;
+			score.scope = 0;
+			score.rule = 0;
+
+			if (ifa_result == NULL) {
+				/* record it if the first available entry */
+				goto record_it;
+			}
+
+			/* Rule 1: Prefer same address */
+			if (hiscore.rule < 1) {
+				if (ipv6_addr_equal(&ifa_result->addr, daddr))
+					hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL;
+				hiscore.rule++;
+			}
+			if (ipv6_addr_equal(&ifa->addr, daddr)) {
+				score.attrs |= IPV6_SADDR_SCORE_LOCAL;
+				if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) {
+					score.rule = 1;
+					goto record_it;
+				}
+			} else {
+				if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)
+					continue;
+			}
+
+			/* Rule 2: Prefer appropriate scope */
+			if (hiscore.rule < 2) {
+				hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type);
+				hiscore.rule++;
+			}
+			score.scope = __ipv6_addr_src_scope(score.addr_type);
+			if (hiscore.scope < score.scope) {
+				if (hiscore.scope < daddr_scope) {
+					score.rule = 2;
+					goto record_it;
+				} else
+					continue;
+			} else if (score.scope < hiscore.scope) {
+				if (score.scope < daddr_scope)
+					continue;
+				else {
+					score.rule = 2;
+					goto record_it;
 				}
 			}
-			read_unlock_bh(&idev->lock);
-		}
-	}
 
-out_unlock_base:
+			/* Rule 3: Avoid deprecated address */
+			if (hiscore.rule < 3) {
+				if (ipv6_saddr_preferred(hiscore.addr_type) ||
+				    !(ifa_result->flags & IFA_F_DEPRECATED))
+					hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;
+				hiscore.rule++;
+			}
+			if (ipv6_saddr_preferred(score.addr_type) ||
+			    !(ifa->flags & IFA_F_DEPRECATED)) {
+				score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
+				if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
+					score.rule = 3;
+					goto record_it;
+				}
+			} else {
+				if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)
+					continue;
+			}
+
+			/* Rule 4: Prefer home address -- not implemented yet */
+
+			/* Rule 5: Prefer outgoing interface */
+			if (hiscore.rule < 5) {
+				if (daddr_dev == NULL ||
+				    daddr_dev == ifa_result->idev->dev)
+					hiscore.attrs |= IPV6_SADDR_SCORE_OIF;
+				hiscore.rule++;
+			}
+			if (daddr_dev == NULL ||
+			    daddr_dev == ifa->idev->dev) {
+				score.attrs |= IPV6_SADDR_SCORE_OIF;
+				if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) {
+					score.rule = 5;
+					goto record_it;
+				}
+			} else {
+				if (hiscore.attrs & IPV6_SADDR_SCORE_OIF)
+					continue;
+			}
+
+			/* Rule 6: Prefer matching label */
+			if (hiscore.rule < 6) {
+				if (ipv6_saddr_label(&ifa_result->addr, hiscore.addr_type) == daddr_label)
+					hiscore.attrs |= IPV6_SADDR_SCORE_LABEL;
+				hiscore.rule++;
+			}
+			if (ipv6_saddr_label(&ifa->addr, score.addr_type) == daddr_label) {
+				score.attrs |= IPV6_SADDR_SCORE_LABEL;
+				if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) {
+					score.rule = 6;
+					goto record_it;
+				}
+			} else {
+				if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL)
+					continue;
+			}
+
+#ifdef CONFIG_IPV6_PRIVACY
+			/* Rule 7: Prefer public address
+			 * Note: prefer temprary address if use_tempaddr >= 2
+			 */
+			if (hiscore.rule < 7) {
+				if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^
+				    (ifa_result->idev->cnf.use_tempaddr >= 2))
+					hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY;
+				hiscore.rule++;
+			}
+			if ((!(ifa->flags & IFA_F_TEMPORARY)) ^
+			    (ifa->idev->cnf.use_tempaddr >= 2)) {
+				score.attrs |= IPV6_SADDR_SCORE_PRIVACY;
+				if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) {
+					score.rule = 7;
+					goto record_it;
+				}
+			} else {
+				if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)
+					continue;
+			}
+#endif
+			/* Rule 8: Use longest matching prefix */
+			if (hiscore.rule < 8)
+				hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr);
+			score.rule++;
+			score.matchlen = ipv6_addr_diff(&ifa->addr, daddr);
+			if (score.matchlen > hiscore.matchlen) {
+				score.rule = 8;
+				goto record_it;
+			}
+#if 0
+			else if (score.matchlen < hiscore.matchlen)
+				continue;
+#endif
+
+			/* Final Rule: choose first available one */
+			continue;
+record_it:
+			if (ifa_result)
+				in6_ifa_put(ifa_result);
+			in6_ifa_hold(ifa);
+			ifa_result = ifa;
+			hiscore = score;
+		}
+		read_unlock_bh(&idev->lock);
+	}
 	read_unlock(&addrconf_lock);
 	read_unlock(&dev_base_lock);
 
-out:
-	err = -EADDRNOTAVAIL;
-	if (match) {
-		ipv6_addr_copy(saddr, &match->addr);
-		err = 0;
-		in6_ifa_put(match);
-	}
-
-	return err;
+	if (!ifa_result)
+		return -EADDRNOTAVAIL;
+	
+	ipv6_addr_copy(saddr, &ifa_result->addr);
+	in6_ifa_put(ifa_result);
+	return 0;
 }
 
 
@@ -2950,8 +3091,7 @@
 
 nlmsg_failure:
 rtattr_failure:
-	if (array)
-		kfree(array);
+	kfree(array);
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 23e5403..1bdf0fb 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -585,17 +585,16 @@
 	daddr = &skb->nh.ipv6h->daddr;
 
 	/* Perform checksum. */
-	if (skb->ip_summed == CHECKSUM_HW) {
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
-				    skb->csum)) {
-			LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 hw checksum failed\n");
-			skb->ip_summed = CHECKSUM_NONE;
-		}
-	}
-	if (skb->ip_summed == CHECKSUM_NONE) {
-		if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
-				    skb_checksum(skb, 0, skb->len, 0))) {
+	switch (skb->ip_summed) {
+	case CHECKSUM_HW:
+		if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
+				     skb->csum))
+			break;
+		/* fall through */
+	case CHECKSUM_NONE:
+		skb->csum = ~csum_ipv6_magic(saddr, daddr, skb->len,
+					     IPPROTO_ICMPV6, 0);
+		if (__skb_checksum_complete(skb)) {
 			LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
 				       NIP6(*saddr), NIP6(*daddr));
 			goto discard_it;
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 4fcc5a7..1bf6d9a 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -127,56 +127,6 @@
 	return htonl(1 << ((~fn_bit)&0x1F)) & addr[fn_bit>>5];
 }
 
-/*
- *	find the first different bit between two addresses
- *	length of address must be a multiple of 32bits
- */
-
-static __inline__ int addr_diff(void *token1, void *token2, int addrlen)
-{
-	__u32 *a1 = token1;
-	__u32 *a2 = token2;
-	int i;
-
-	addrlen >>= 2;
-
-	for (i = 0; i < addrlen; i++) {
-		__u32 xb;
-
-		xb = a1[i] ^ a2[i];
-
-		if (xb) {
-			int j = 31;
-
-			xb = ntohl(xb);
-
-			while ((xb & (1 << j)) == 0)
-				j--;
-
-			return (i * 32 + 31 - j);
-		}
-	}
-
-	/*
-	 *	we should *never* get to this point since that 
-	 *	would mean the addrs are equal
-	 *
-	 *	However, we do get to it 8) And exacly, when
-	 *	addresses are equal 8)
-	 *
-	 *	ip route add 1111::/128 via ...
-	 *	ip route add 1111::/64 via ...
-	 *	and we are here.
-	 *
-	 *	Ideally, this function should stop comparison
-	 *	at prefix length. It does not, but it is still OK,
-	 *	if returned value is greater than prefix length.
-	 *					--ANK (980803)
-	 */
-
-	return addrlen<<5;
-}
-
 static __inline__ struct fib6_node * node_alloc(void)
 {
 	struct fib6_node *fn;
@@ -296,11 +246,11 @@
 
 	/* find 1st bit in difference between the 2 addrs.
 
-	   See comment in addr_diff: bit may be an invalid value,
+	   See comment in __ipv6_addr_diff: bit may be an invalid value,
 	   but if it is >= plen, the value is ignored in any case.
 	 */
 	
-	bit = addr_diff(addr, &key->addr, addrlen);
+	bit = __ipv6_addr_diff(addr, &key->addr, addrlen);
 
 	/* 
 	 *		(intermediate)[in]	
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 6e34804..a6026d2 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -176,6 +176,11 @@
 		if (ipprot->flags & INET6_PROTO_FINAL) {
 			struct ipv6hdr *hdr;	
 
+			/* Free reference early: we don't need it any more,
+			   and it may hold ip_conntrack module loaded
+			   indefinitely. */
+			nf_reset(skb);
+
 			skb_postpull_rcsum(skb, skb->nh.raw,
 					   skb->h.raw - skb->nh.raw);
 			hdr = skb->nh.ipv6h;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 614296a..c1fa693 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -441,9 +441,15 @@
 #ifdef CONFIG_NETFILTER
 	to->nfmark = from->nfmark;
 	/* Connection association is same as pre-frag packet */
+	nf_conntrack_put(to->nfct);
 	to->nfct = from->nfct;
 	nf_conntrack_get(to->nfct);
 	to->nfctinfo = from->nfctinfo;
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	nf_conntrack_put_reasm(to->nfct_reasm);
+	to->nfct_reasm = from->nfct_reasm;
+	nf_conntrack_get_reasm(to->nfct_reasm);
+#endif
 #ifdef CONFIG_BRIDGE_NETFILTER
 	nf_bridge_put(to->nf_bridge);
 	to->nf_bridge = from->nf_bridge;
@@ -587,8 +593,7 @@
 			skb->next = NULL;
 		}
 
-		if (tmp_hdr)
-			kfree(tmp_hdr);
+		kfree(tmp_hdr);
 
 		if (err == 0) {
 			IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
@@ -1186,10 +1191,8 @@
 
 out:
 	inet->cork.flags &= ~IPCORK_OPT;
-	if (np->cork.opt) {
-		kfree(np->cork.opt);
-		np->cork.opt = NULL;
-	}
+	kfree(np->cork.opt);
+	np->cork.opt = NULL;
 	if (np->cork.rt) {
 		dst_release(&np->cork.rt->u.dst);
 		np->cork.rt = NULL;
@@ -1214,10 +1217,8 @@
 
 	inet->cork.flags &= ~IPCORK_OPT;
 
-	if (np->cork.opt) {
-		kfree(np->cork.opt);
-		np->cork.opt = NULL;
-	}
+	kfree(np->cork.opt);
+	np->cork.opt = NULL;
 	if (np->cork.rt) {
 		dst_release(&np->cork.rt->u.dst);
 		np->cork.rt = NULL;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index cf94372..e315d0f 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -525,6 +525,7 @@
 
 	if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
 		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+			read_unlock(&ip6ip6_lock);
 			kfree_skb(skb);
 			return 0;
 		}
@@ -756,8 +757,7 @@
 	}
 	ip6_tnl_dst_store(t, dst);
 
-	if (opt)
-		kfree(opt);
+	kfree(opt);
 
 	t->recursion--;
 	return 0;
@@ -766,8 +766,7 @@
 	dst_link_failure(skb);
 tx_err_dst_release:
 	dst_release(dst);
-	if (opt)
-		kfree(opt);
+	kfree(opt);
 tx_err:
 	stats->tx_errors++;
 	stats->tx_dropped++;
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 85bfbc6..55917fb 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -130,8 +130,7 @@
 out_put_cpu:
 	put_cpu();
 out:
-	if (tmp_hdr)
-		kfree(tmp_hdr);
+	kfree(tmp_hdr);
 	if (err)
 		goto error_out;
 	return nexthdr;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 8567873..003fd99 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -80,8 +80,7 @@
 		if (ra->sk == sk) {
 			if (sel>=0) {
 				write_unlock_bh(&ip6_ra_lock);
-				if (new_ra)
-					kfree(new_ra);
+				kfree(new_ra);
 				return -EADDRINUSE;
 			}
 
diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c
index 37a4a99..1648278 100644
--- a/net/ipv6/ipv6_syms.c
+++ b/net/ipv6/ipv6_syms.c
@@ -7,7 +7,7 @@
 #include <net/ip6_route.h>
 #include <net/xfrm.h>
 
-EXPORT_SYMBOL(ipv6_addr_type);
+EXPORT_SYMBOL(__ipv6_addr_type);
 EXPORT_SYMBOL(icmpv6_send);
 EXPORT_SYMBOL(icmpv6_statistics);
 EXPORT_SYMBOL(icmpv6_err_convert);
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index bb7ccfe..971ba60 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -278,5 +278,19 @@
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+config NF_CONNTRACK_IPV6
+	tristate "IPv6 support for new connection tracking (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && NF_CONNTRACK
+	---help---
+	  Connection tracking keeps a record of what packets have passed
+	  through your machine, in order to figure out how they are related
+	  into connections.
+
+	  This is IPv6 support on Layer 3 independent connection tracking.
+	  Layer 3 independent connection tracking is experimental scheme
+	  which generalize ip_conntrack to support other layer 3 protocols.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 endmenu
 
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 2b2c370..9ab5b2c 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -27,3 +27,9 @@
 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
+
+# objects for l3 independent conntrack
+nf_conntrack_ipv6-objs  :=  nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
+
+# l3 independent conntrack
+obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o
diff --git a/net/ipv6/netfilter/ip6t_MARK.c b/net/ipv6/netfilter/ip6t_MARK.c
index 0c7584f..eab8fb8 100644
--- a/net/ipv6/netfilter/ip6t_MARK.c
+++ b/net/ipv6/netfilter/ip6t_MARK.c
@@ -56,9 +56,9 @@
 	return 1;
 }
 
-static struct ip6t_target ip6t_mark_reg = {
-	.name 		= "MARK",
-	.target 	= target,
+static struct ip6t_target ip6t_mark_reg = { 
+	.name		= "MARK",
+	.target		= target,
 	.checkentry	= checkentry,
 	.me		= THIS_MODULE
 };
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
new file mode 100644
index 0000000..e2c90b3
--- /dev/null
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (C)2004 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:
+ *	Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- support Layer 3 protocol independent connection tracking.
+ *	  Based on the original ip_conntrack code which	had the following
+ *	  copyright information:
+ *		(C) 1999-2001 Paul `Rusty' Russell
+ *		(C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- add get_features() to support various size of conntrack
+ *	  structures.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/ipv6.h>
+#include <linux/in6.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/icmp.h>
+#include <linux/sysctl.h>
+#include <net/ipv6.h>
+
+#include <linux/netfilter_ipv6.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+#include <net/netfilter/nf_conntrack_l3proto.h>
+#include <net/netfilter/nf_conntrack_core.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+DECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);
+
+static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
+			     struct nf_conntrack_tuple *tuple)
+{
+	u_int32_t _addrs[8], *ap;
+
+	ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr),
+				sizeof(_addrs), _addrs);
+	if (ap == NULL)
+		return 0;
+
+	memcpy(tuple->src.u3.ip6, ap, sizeof(tuple->src.u3.ip6));
+	memcpy(tuple->dst.u3.ip6, ap + 4, sizeof(tuple->dst.u3.ip6));
+
+	return 1;
+}
+
+static int ipv6_invert_tuple(struct nf_conntrack_tuple *tuple,
+			     const struct nf_conntrack_tuple *orig)
+{
+	memcpy(tuple->src.u3.ip6, orig->dst.u3.ip6, sizeof(tuple->src.u3.ip6));
+	memcpy(tuple->dst.u3.ip6, orig->src.u3.ip6, sizeof(tuple->dst.u3.ip6));
+
+	return 1;
+}
+
+static int ipv6_print_tuple(struct seq_file *s,
+			    const struct nf_conntrack_tuple *tuple)
+{
+	return seq_printf(s, "src=%x:%x:%x:%x:%x:%x:%x:%x dst=%x:%x:%x:%x:%x:%x:%x:%x ",
+			  NIP6(*((struct in6_addr *)tuple->src.u3.ip6)),
+			  NIP6(*((struct in6_addr *)tuple->dst.u3.ip6)));
+}
+
+static int ipv6_print_conntrack(struct seq_file *s,
+				const struct nf_conn *conntrack)
+{
+	return 0;
+}
+
+/*
+ * Based on ipv6_skip_exthdr() in net/ipv6/exthdr.c
+ *
+ * This function parses (probably truncated) exthdr set "hdr"
+ * of length "len". "nexthdrp" initially points to some place,
+ * where type of the first header can be found.
+ *
+ * It skips all well-known exthdrs, and returns pointer to the start
+ * of unparsable area i.e. the first header with unknown type.
+ * if success, *nexthdr is updated by type/protocol of this header.
+ *
+ * NOTES: - it may return pointer pointing beyond end of packet,
+ *          if the last recognized header is truncated in the middle.
+ *        - if packet is truncated, so that all parsed headers are skipped,
+ *          it returns -1.
+ *        - if packet is fragmented, return pointer of the fragment header.
+ *        - ESP is unparsable for now and considered like
+ *          normal payload protocol.
+ *        - Note also special handling of AUTH header. Thanks to IPsec wizards.
+ */
+
+int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp,
+			   int len)
+{
+	u8 nexthdr = *nexthdrp;
+
+	while (ipv6_ext_hdr(nexthdr)) {
+		struct ipv6_opt_hdr hdr;
+		int hdrlen;
+
+		if (len < (int)sizeof(struct ipv6_opt_hdr))
+			return -1;
+		if (nexthdr == NEXTHDR_NONE)
+			break;
+		if (nexthdr == NEXTHDR_FRAGMENT)
+			break;
+		if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
+			BUG();
+		if (nexthdr == NEXTHDR_AUTH)
+			hdrlen = (hdr.hdrlen+2)<<2;
+		else
+			hdrlen = ipv6_optlen(&hdr);
+
+		nexthdr = hdr.nexthdr;
+		len -= hdrlen;
+		start += hdrlen;
+	}
+
+	*nexthdrp = nexthdr;
+	return start;
+}
+
+static int
+ipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
+	     u_int8_t *protonum)
+{
+	unsigned int extoff;
+	unsigned char pnum;
+	int protoff;
+
+	extoff = (u8*)((*pskb)->nh.ipv6h + 1) - (*pskb)->data;
+	pnum = (*pskb)->nh.ipv6h->nexthdr;
+
+	protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
+					 (*pskb)->len - extoff);
+
+	/*
+	 * (protoff == (*pskb)->len) mean that the packet doesn't have no data
+	 * except of IPv6 & ext headers. but it's tracked anyway. - YK
+	 */
+	if ((protoff < 0) || (protoff > (*pskb)->len)) {
+		DEBUGP("ip6_conntrack_core: can't find proto in pkt\n");
+		NF_CT_STAT_INC(error);
+		NF_CT_STAT_INC(invalid);
+		return -NF_ACCEPT;
+	}
+
+	*dataoff = protoff;
+	*protonum = pnum;
+	return NF_ACCEPT;
+}
+
+static u_int32_t ipv6_get_features(const struct nf_conntrack_tuple *tuple)
+{
+	return NF_CT_F_BASIC;
+}
+
+static unsigned int ipv6_confirm(unsigned int hooknum,
+				 struct sk_buff **pskb,
+				 const struct net_device *in,
+				 const struct net_device *out,
+				 int (*okfn)(struct sk_buff *))
+{
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+
+	/* This is where we call the helper: as the packet goes out. */
+	ct = nf_ct_get(*pskb, &ctinfo);
+	if (ct && ct->helper) {
+		unsigned int ret, protoff;
+		unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
+				      - (*pskb)->data;
+		unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
+
+		protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
+						 (*pskb)->len - extoff);
+		if (protoff < 0 || protoff > (*pskb)->len ||
+		    pnum == NEXTHDR_FRAGMENT) {
+			DEBUGP("proto header not found\n");
+			return NF_ACCEPT;
+		}
+
+		ret = ct->helper->help(pskb, protoff, ct, ctinfo);
+		if (ret != NF_ACCEPT)
+			return ret;
+	}
+
+	/* We've seen it coming out the other side: confirm it */
+
+	return nf_conntrack_confirm(pskb);
+}
+
+extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb);
+extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
+			       struct net_device *in,
+			       struct net_device *out,
+			       int (*okfn)(struct sk_buff *));
+static unsigned int ipv6_defrag(unsigned int hooknum,
+				struct sk_buff **pskb,
+				const struct net_device *in,
+				const struct net_device *out,
+				int (*okfn)(struct sk_buff *))
+{
+	struct sk_buff *reasm;
+
+	/* Previously seen (loopback)?  */
+	if ((*pskb)->nfct)
+		return NF_ACCEPT;
+
+	reasm = nf_ct_frag6_gather(*pskb);
+
+	/* queued */
+	if (reasm == NULL)
+		return NF_STOLEN;
+
+	/* error occured or not fragmented */
+	if (reasm == *pskb)
+		return NF_ACCEPT;
+
+	nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in,
+			   (struct net_device *)out, okfn);
+
+	return NF_STOLEN;
+}
+
+static unsigned int ipv6_conntrack_in(unsigned int hooknum,
+				      struct sk_buff **pskb,
+				      const struct net_device *in,
+				      const struct net_device *out,
+				      int (*okfn)(struct sk_buff *))
+{
+	struct sk_buff *reasm = (*pskb)->nfct_reasm;
+
+	/* This packet is fragmented and has reassembled packet. */
+	if (reasm) {
+		/* Reassembled packet isn't parsed yet ? */
+		if (!reasm->nfct) {
+			unsigned int ret;
+
+			ret = nf_conntrack_in(PF_INET6, hooknum, &reasm);
+			if (ret != NF_ACCEPT)
+				return ret;
+		}
+		nf_conntrack_get(reasm->nfct);
+		(*pskb)->nfct = reasm->nfct;
+		return NF_ACCEPT;
+	}
+
+	return nf_conntrack_in(PF_INET6, hooknum, pskb);
+}
+
+static unsigned int ipv6_conntrack_local(unsigned int hooknum,
+					 struct sk_buff **pskb,
+					 const struct net_device *in,
+					 const struct net_device *out,
+					 int (*okfn)(struct sk_buff *))
+{
+	/* root is playing with raw sockets. */
+	if ((*pskb)->len < sizeof(struct ipv6hdr)) {
+		if (net_ratelimit())
+			printk("ipv6_conntrack_local: packet too short\n");
+		return NF_ACCEPT;
+	}
+	return ipv6_conntrack_in(hooknum, pskb, in, out, okfn);
+}
+
+/* Connection tracking may drop packets, but never alters them, so
+   make it the first hook. */
+static struct nf_hook_ops ipv6_conntrack_defrag_ops = {
+	.hook		= ipv6_defrag,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET6,
+	.hooknum	= NF_IP6_PRE_ROUTING,
+	.priority	= NF_IP6_PRI_CONNTRACK_DEFRAG,
+};
+
+static struct nf_hook_ops ipv6_conntrack_in_ops = {
+	.hook		= ipv6_conntrack_in,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET6,
+	.hooknum	= NF_IP6_PRE_ROUTING,
+	.priority	= NF_IP6_PRI_CONNTRACK,
+};
+
+static struct nf_hook_ops ipv6_conntrack_local_out_ops = {
+	.hook		= ipv6_conntrack_local,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET6,
+	.hooknum	= NF_IP6_LOCAL_OUT,
+	.priority	= NF_IP6_PRI_CONNTRACK,
+};
+
+static struct nf_hook_ops ipv6_conntrack_defrag_local_out_ops = {
+	.hook		= ipv6_defrag,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET6,
+	.hooknum	= NF_IP6_LOCAL_OUT,
+	.priority	= NF_IP6_PRI_CONNTRACK_DEFRAG,
+};
+
+/* Refragmenter; last chance. */
+static struct nf_hook_ops ipv6_conntrack_out_ops = {
+	.hook		= ipv6_confirm,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET6,
+	.hooknum	= NF_IP6_POST_ROUTING,
+	.priority	= NF_IP6_PRI_LAST,
+};
+
+static struct nf_hook_ops ipv6_conntrack_local_in_ops = {
+	.hook		= ipv6_confirm,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET6,
+	.hooknum	= NF_IP6_LOCAL_IN,
+	.priority	= NF_IP6_PRI_LAST-1,
+};
+
+#ifdef CONFIG_SYSCTL
+
+/* From nf_conntrack_proto_icmpv6.c */
+extern unsigned long nf_ct_icmpv6_timeout;
+
+/* From nf_conntrack_frag6.c */
+extern unsigned long nf_ct_frag6_timeout;
+extern unsigned long nf_ct_frag6_low_thresh;
+extern unsigned long nf_ct_frag6_high_thresh;
+
+static struct ctl_table_header *nf_ct_ipv6_sysctl_header;
+
+static ctl_table nf_ct_sysctl_table[] = {
+	{
+		.ctl_name	= NET_NF_CONNTRACK_ICMPV6_TIMEOUT,
+		.procname	= "nf_conntrack_icmpv6_timeout",
+		.data		= &nf_ct_icmpv6_timeout,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_FRAG6_TIMEOUT,
+		.procname	= "nf_conntrack_frag6_timeout",
+		.data		= &nf_ct_frag6_timeout,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_FRAG6_LOW_THRESH,
+		.procname	= "nf_conntrack_frag6_low_thresh",
+		.data		= &nf_ct_frag6_low_thresh,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_FRAG6_HIGH_THRESH,
+		.procname	= "nf_conntrack_frag6_high_thresh",
+		.data		= &nf_ct_frag6_high_thresh,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+        { .ctl_name = 0 }
+};
+
+static ctl_table nf_ct_netfilter_table[] = {
+	{
+		.ctl_name	= NET_NETFILTER,
+		.procname	= "netfilter",
+		.mode		= 0555,
+		.child		= nf_ct_sysctl_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table nf_ct_net_table[] = {
+	{
+		.ctl_name	= CTL_NET,
+		.procname	= "net",
+		.mode		= 0555,
+		.child		= nf_ct_netfilter_table,
+	},
+	{ .ctl_name = 0 }
+};
+#endif
+
+struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
+	.l3proto		= PF_INET6,
+	.name			= "ipv6",
+	.pkt_to_tuple		= ipv6_pkt_to_tuple,
+	.invert_tuple		= ipv6_invert_tuple,
+	.print_tuple		= ipv6_print_tuple,
+	.print_conntrack	= ipv6_print_conntrack,
+	.prepare		= ipv6_prepare,
+	.get_features		= ipv6_get_features,
+	.me			= THIS_MODULE,
+};
+
+extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp6;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6;
+extern int nf_ct_frag6_init(void);
+extern void nf_ct_frag6_cleanup(void);
+static int init_or_cleanup(int init)
+{
+	int ret = 0;
+
+	if (!init) goto cleanup;
+
+	ret = nf_ct_frag6_init();
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't initialize frag6.\n");
+		goto cleanup_nothing;
+	}
+	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp6);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register tcp.\n");
+		goto cleanup_frag6;
+	}
+
+	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp6);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register udp.\n");
+		goto cleanup_tcp;
+	}
+
+	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmpv6);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register icmpv6.\n");
+		goto cleanup_udp;
+	}
+
+	ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register ipv6\n");
+		goto cleanup_icmpv6;
+	}
+
+	ret = nf_register_hook(&ipv6_conntrack_defrag_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register pre-routing defrag "
+		       "hook.\n");
+		goto cleanup_ipv6;
+	}
+
+	ret = nf_register_hook(&ipv6_conntrack_defrag_local_out_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register local_out defrag "
+		       "hook.\n");
+		goto cleanup_defragops;
+	}
+
+	ret = nf_register_hook(&ipv6_conntrack_in_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register pre-routing hook.\n");
+		goto cleanup_defraglocalops;
+	}
+
+	ret = nf_register_hook(&ipv6_conntrack_local_out_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register local out hook.\n");
+		goto cleanup_inops;
+	}
+
+	ret = nf_register_hook(&ipv6_conntrack_out_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register post-routing hook.\n");
+		goto cleanup_inandlocalops;
+	}
+
+	ret = nf_register_hook(&ipv6_conntrack_local_in_ops);
+	if (ret < 0) {
+		printk("nf_conntrack_ipv6: can't register local in hook.\n");
+		goto cleanup_inoutandlocalops;
+	}
+
+#ifdef CONFIG_SYSCTL
+	nf_ct_ipv6_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
+	if (nf_ct_ipv6_sysctl_header == NULL) {
+		printk("nf_conntrack: can't register to sysctl.\n");
+		ret = -ENOMEM;
+		goto cleanup_localinops;
+	}
+#endif
+	return ret;
+
+ cleanup:
+	synchronize_net();
+#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(nf_ct_ipv6_sysctl_header);
+ cleanup_localinops:
+#endif
+	nf_unregister_hook(&ipv6_conntrack_local_in_ops);
+ cleanup_inoutandlocalops:
+	nf_unregister_hook(&ipv6_conntrack_out_ops);
+ cleanup_inandlocalops:
+	nf_unregister_hook(&ipv6_conntrack_local_out_ops);
+ cleanup_inops:
+	nf_unregister_hook(&ipv6_conntrack_in_ops);
+ cleanup_defraglocalops:
+	nf_unregister_hook(&ipv6_conntrack_defrag_local_out_ops);
+ cleanup_defragops:
+	nf_unregister_hook(&ipv6_conntrack_defrag_ops);
+ cleanup_ipv6:
+	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
+ cleanup_icmpv6:
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmpv6);
+ cleanup_udp:
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp6);
+ cleanup_tcp:
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6);
+ cleanup_frag6:
+	nf_ct_frag6_cleanup();
+ cleanup_nothing:
+	return ret;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
+
+static int __init init(void)
+{
+	need_nf_conntrack();
+	return init_or_cleanup(1);
+}
+
+static void __exit fini(void)
+{
+	init_or_cleanup(0);
+}
+
+module_init(init);
+module_exit(fini);
+
+void need_ip6_conntrack(void)
+{
+}
+
+EXPORT_SYMBOL(need_ip6_conntrack);
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
new file mode 100644
index 0000000..c0f1da5
--- /dev/null
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C)2003,2004 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:
+ *	Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- ICMPv6 tracking support. Derived from the original ip_conntrack code
+ *	  net/ipv4/netfilter/ip_conntrack_proto_icmp.c which had the following
+ *	  copyright information:
+ *		(C) 1999-2001 Paul `Rusty' Russell
+ *		(C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/ip6_checksum.h>
+#include <linux/seq_file.h>
+#include <linux/netfilter_ipv6.h>
+#include <net/netfilter/nf_conntrack_tuple.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/ipv6/nf_conntrack_icmpv6.h>
+
+unsigned long nf_ct_icmpv6_timeout = 30*HZ;
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
+			       unsigned int dataoff,
+			       struct nf_conntrack_tuple *tuple)
+{
+	struct icmp6hdr _hdr, *hp;
+
+	hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+	if (hp == NULL)
+		return 0;
+	tuple->dst.u.icmp.type = hp->icmp6_type;
+	tuple->src.u.icmp.id = hp->icmp6_identifier;
+	tuple->dst.u.icmp.code = hp->icmp6_code;
+
+	return 1;
+}
+
+static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple,
+			       const struct nf_conntrack_tuple *orig)
+{
+	/* Add 1; spaces filled with 0. */
+	static u_int8_t invmap[] = {
+		[ICMPV6_ECHO_REQUEST - 128]	= ICMPV6_ECHO_REPLY + 1,
+		[ICMPV6_ECHO_REPLY - 128]	= ICMPV6_ECHO_REQUEST + 1,
+		[ICMPV6_NI_QUERY - 128]		= ICMPV6_NI_QUERY + 1,
+		[ICMPV6_NI_REPLY - 128]		= ICMPV6_NI_REPLY +1
+	};
+
+	__u8 type = orig->dst.u.icmp.type - 128;
+	if (type >= sizeof(invmap) || !invmap[type])
+		return 0;
+
+	tuple->src.u.icmp.id   = orig->src.u.icmp.id;
+	tuple->dst.u.icmp.type = invmap[type] - 1;
+	tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
+	return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static int icmpv6_print_tuple(struct seq_file *s,
+			      const struct nf_conntrack_tuple *tuple)
+{
+	return seq_printf(s, "type=%u code=%u id=%u ",
+			  tuple->dst.u.icmp.type,
+			  tuple->dst.u.icmp.code,
+			  ntohs(tuple->src.u.icmp.id));
+}
+
+/* Print out the private part of the conntrack. */
+static int icmpv6_print_conntrack(struct seq_file *s,
+				  const struct nf_conn *conntrack)
+{
+	return 0;
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int icmpv6_packet(struct nf_conn *ct,
+		       const struct sk_buff *skb,
+		       unsigned int dataoff,
+		       enum ip_conntrack_info ctinfo,
+		       int pf,
+		       unsigned int hooknum)
+{
+	/* Try to delete connection immediately after all replies:
+           won't actually vanish as we still have skb, and del_timer
+           means this will only run once even if count hits zero twice
+           (theoretically possible with SMP) */
+	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
+		if (atomic_dec_and_test(&ct->proto.icmp.count)
+		    && del_timer(&ct->timeout))
+			ct->timeout.function((unsigned long)ct);
+	} else {
+		atomic_inc(&ct->proto.icmp.count);
+		nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout);
+	}
+
+	return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int icmpv6_new(struct nf_conn *conntrack,
+		      const struct sk_buff *skb,
+		      unsigned int dataoff)
+{
+	static u_int8_t valid_new[] = {
+		[ICMPV6_ECHO_REQUEST - 128] = 1,
+		[ICMPV6_NI_QUERY - 128] = 1
+	};
+
+	if (conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128 >= sizeof(valid_new)
+	    || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128]) {
+		/* Can't create a new ICMPv6 `conn' with this. */
+		DEBUGP("icmp: can't create new conn with type %u\n",
+		       conntrack->tuplehash[0].tuple.dst.u.icmp.type);
+		NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
+		return 0;
+	}
+	atomic_set(&conntrack->proto.icmp.count, 0);
+	return 1;
+}
+
+extern int
+nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len);
+extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
+static int
+icmpv6_error_message(struct sk_buff *skb,
+		     unsigned int icmp6off,
+		     enum ip_conntrack_info *ctinfo,
+		     unsigned int hooknum)
+{
+	struct nf_conntrack_tuple intuple, origtuple;
+	struct nf_conntrack_tuple_hash *h;
+	struct icmp6hdr _hdr, *hp;
+	unsigned int inip6off;
+	struct nf_conntrack_protocol *inproto;
+	u_int8_t inprotonum;
+	unsigned int inprotoff;
+
+	NF_CT_ASSERT(skb->nfct == NULL);
+
+	hp = skb_header_pointer(skb, icmp6off, sizeof(_hdr), &_hdr);
+	if (hp == NULL) {
+		DEBUGP("icmpv6_error: Can't get ICMPv6 hdr.\n");
+		return -NF_ACCEPT;
+	}
+
+	inip6off = icmp6off + sizeof(_hdr);
+	if (skb_copy_bits(skb, inip6off+offsetof(struct ipv6hdr, nexthdr),
+			  &inprotonum, sizeof(inprotonum)) != 0) {
+		DEBUGP("icmpv6_error: Can't get nexthdr in inner IPv6 header.\n");
+		return -NF_ACCEPT;
+	}
+	inprotoff = nf_ct_ipv6_skip_exthdr(skb,
+					   inip6off + sizeof(struct ipv6hdr),
+					   &inprotonum,
+					   skb->len - inip6off
+						    - sizeof(struct ipv6hdr));
+
+	if ((inprotoff < 0) || (inprotoff > skb->len) ||
+	    (inprotonum == NEXTHDR_FRAGMENT)) {
+		DEBUGP("icmpv6_error: Can't get protocol header in ICMPv6 payload.\n");
+		return -NF_ACCEPT;
+	}
+
+	inproto = nf_ct_find_proto(PF_INET6, inprotonum);
+
+	/* Are they talking about one of our connections? */
+	if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum,
+			     &origtuple, &nf_conntrack_l3proto_ipv6, inproto)) {
+		DEBUGP("icmpv6_error: Can't get tuple\n");
+		return -NF_ACCEPT;
+	}
+
+	/* Ordinarily, we'd expect the inverted tupleproto, but it's
+	   been preserved inside the ICMP. */
+	if (!nf_ct_invert_tuple(&intuple, &origtuple,
+				&nf_conntrack_l3proto_ipv6, inproto)) {
+		DEBUGP("icmpv6_error: Can't invert tuple\n");
+		return -NF_ACCEPT;
+	}
+
+	*ctinfo = IP_CT_RELATED;
+
+	h = nf_conntrack_find_get(&intuple, NULL);
+	if (!h) {
+		DEBUGP("icmpv6_error: no match\n");
+		return -NF_ACCEPT;
+	} else {
+		if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
+			*ctinfo += IP_CT_IS_REPLY;
+	}
+
+	/* Update skb to refer to this connection */
+	skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
+	skb->nfctinfo = *ctinfo;
+	return -NF_ACCEPT;
+}
+
+static int
+icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
+	     enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
+{
+	struct icmp6hdr _ih, *icmp6h;
+
+	icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
+	if (icmp6h == NULL) {
+		if (LOG_INVALID(IPPROTO_ICMPV6))
+		nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
+			      "nf_ct_icmpv6: short packet ");
+		return -NF_ACCEPT;
+	}
+
+	if (hooknum != NF_IP6_PRE_ROUTING)
+		goto skipped;
+
+	/* Ignore it if the checksum's bogus. */
+	if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
+			    skb->len - dataoff, IPPROTO_ICMPV6,
+			    skb_checksum(skb, dataoff,
+					 skb->len - dataoff, 0))) {
+		nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
+			      "nf_ct_icmpv6: ICMPv6 checksum failed\n");
+		return -NF_ACCEPT;
+	}
+
+skipped:
+
+	/* is not error message ? */
+	if (icmp6h->icmp6_type >= 128)
+		return NF_ACCEPT;
+
+	return icmpv6_error_message(skb, dataoff, ctinfo, hooknum);
+}
+
+struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 =
+{
+	.l3proto		= PF_INET6,
+	.proto			= IPPROTO_ICMPV6,
+	.name			= "icmpv6",
+	.pkt_to_tuple		= icmpv6_pkt_to_tuple,
+	.invert_tuple		= icmpv6_invert_tuple,
+	.print_tuple		= icmpv6_print_tuple,
+	.print_conntrack	= icmpv6_print_conntrack,
+	.packet			= icmpv6_packet,
+	.new			= icmpv6_new,
+	.error			= icmpv6_error,
+};
+
+EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6);
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
new file mode 100644
index 0000000..7640b9b
--- /dev/null
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -0,0 +1,885 @@
+/*
+ * IPv6 fragment reassembly for connection tracking
+ *
+ * Copyright (C)2004 USAGI/WIDE Project
+ *
+ * Author:
+ *	Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * Based on: net/ipv6/reassembly.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/jiffies.h>
+#include <linux/net.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/rawv6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <linux/sysctl.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define NF_CT_FRAG6_HIGH_THRESH 262144 /* == 256*1024 */
+#define NF_CT_FRAG6_LOW_THRESH 196608  /* == 192*1024 */
+#define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT
+
+int nf_ct_frag6_high_thresh = 256*1024;
+int nf_ct_frag6_low_thresh = 192*1024;
+int nf_ct_frag6_timeout = IPV6_FRAG_TIMEOUT;
+
+struct nf_ct_frag6_skb_cb
+{
+	struct inet6_skb_parm	h;
+	int			offset;
+	struct sk_buff		*orig;
+};
+
+#define NFCT_FRAG6_CB(skb)	((struct nf_ct_frag6_skb_cb*)((skb)->cb))
+
+struct nf_ct_frag6_queue
+{
+	struct nf_ct_frag6_queue	*next;
+	struct list_head lru_list;		/* lru list member	*/
+
+	__u32			id;		/* fragment id		*/
+	struct in6_addr		saddr;
+	struct in6_addr		daddr;
+
+	spinlock_t		lock;
+	atomic_t		refcnt;
+	struct timer_list	timer;		/* expire timer		*/
+	struct sk_buff		*fragments;
+	int			len;
+	int			meat;
+	struct timeval		stamp;
+	unsigned int		csum;
+	__u8			last_in;	/* has first/last segment arrived? */
+#define COMPLETE		4
+#define FIRST_IN		2
+#define LAST_IN			1
+	__u16			nhoffset;
+	struct nf_ct_frag6_queue	**pprev;
+};
+
+/* Hash table. */
+
+#define FRAG6Q_HASHSZ	64
+
+static struct nf_ct_frag6_queue *nf_ct_frag6_hash[FRAG6Q_HASHSZ];
+static rwlock_t nf_ct_frag6_lock = RW_LOCK_UNLOCKED;
+static u32 nf_ct_frag6_hash_rnd;
+static LIST_HEAD(nf_ct_frag6_lru_list);
+int nf_ct_frag6_nqueues = 0;
+
+static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq)
+{
+	if (fq->next)
+		fq->next->pprev = fq->pprev;
+	*fq->pprev = fq->next;
+	list_del(&fq->lru_list);
+	nf_ct_frag6_nqueues--;
+}
+
+static __inline__ void fq_unlink(struct nf_ct_frag6_queue *fq)
+{
+	write_lock(&nf_ct_frag6_lock);
+	__fq_unlink(fq);
+	write_unlock(&nf_ct_frag6_lock);
+}
+
+static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr,
+			       struct in6_addr *daddr)
+{
+	u32 a, b, c;
+
+	a = saddr->s6_addr32[0];
+	b = saddr->s6_addr32[1];
+	c = saddr->s6_addr32[2];
+
+	a += JHASH_GOLDEN_RATIO;
+	b += JHASH_GOLDEN_RATIO;
+	c += nf_ct_frag6_hash_rnd;
+	__jhash_mix(a, b, c);
+
+	a += saddr->s6_addr32[3];
+	b += daddr->s6_addr32[0];
+	c += daddr->s6_addr32[1];
+	__jhash_mix(a, b, c);
+
+	a += daddr->s6_addr32[2];
+	b += daddr->s6_addr32[3];
+	c += id;
+	__jhash_mix(a, b, c);
+
+	return c & (FRAG6Q_HASHSZ - 1);
+}
+
+static struct timer_list nf_ct_frag6_secret_timer;
+int nf_ct_frag6_secret_interval = 10 * 60 * HZ;
+
+static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
+{
+	unsigned long now = jiffies;
+	int i;
+
+	write_lock(&nf_ct_frag6_lock);
+	get_random_bytes(&nf_ct_frag6_hash_rnd, sizeof(u32));
+	for (i = 0; i < FRAG6Q_HASHSZ; i++) {
+		struct nf_ct_frag6_queue *q;
+
+		q = nf_ct_frag6_hash[i];
+		while (q) {
+			struct nf_ct_frag6_queue *next = q->next;
+			unsigned int hval = ip6qhashfn(q->id,
+						       &q->saddr,
+						       &q->daddr);
+
+			if (hval != i) {
+				/* Unlink. */
+				if (q->next)
+					q->next->pprev = q->pprev;
+				*q->pprev = q->next;
+
+				/* Relink to new hash chain. */
+				if ((q->next = nf_ct_frag6_hash[hval]) != NULL)
+					q->next->pprev = &q->next;
+				nf_ct_frag6_hash[hval] = q;
+				q->pprev = &nf_ct_frag6_hash[hval];
+			}
+
+			q = next;
+		}
+	}
+	write_unlock(&nf_ct_frag6_lock);
+
+	mod_timer(&nf_ct_frag6_secret_timer, now + nf_ct_frag6_secret_interval);
+}
+
+atomic_t nf_ct_frag6_mem = ATOMIC_INIT(0);
+
+/* Memory Tracking Functions. */
+static inline void frag_kfree_skb(struct sk_buff *skb)
+{
+	atomic_sub(skb->truesize, &nf_ct_frag6_mem);
+	if (NFCT_FRAG6_CB(skb)->orig)
+		kfree_skb(NFCT_FRAG6_CB(skb)->orig);
+
+	kfree_skb(skb);
+}
+
+static inline void frag_free_queue(struct nf_ct_frag6_queue *fq)
+{
+	atomic_sub(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem);
+	kfree(fq);
+}
+
+static inline struct nf_ct_frag6_queue *frag_alloc_queue(void)
+{
+	struct nf_ct_frag6_queue *fq = kmalloc(sizeof(struct nf_ct_frag6_queue), GFP_ATOMIC);
+
+	if (!fq)
+		return NULL;
+	atomic_add(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem);
+	return fq;
+}
+
+/* Destruction primitives. */
+
+/* Complete destruction of fq. */
+static void nf_ct_frag6_destroy(struct nf_ct_frag6_queue *fq)
+{
+	struct sk_buff *fp;
+
+	BUG_TRAP(fq->last_in&COMPLETE);
+	BUG_TRAP(del_timer(&fq->timer) == 0);
+
+	/* Release all fragment data. */
+	fp = fq->fragments;
+	while (fp) {
+		struct sk_buff *xp = fp->next;
+
+		frag_kfree_skb(fp);
+		fp = xp;
+	}
+
+	frag_free_queue(fq);
+}
+
+static __inline__ void fq_put(struct nf_ct_frag6_queue *fq)
+{
+	if (atomic_dec_and_test(&fq->refcnt))
+		nf_ct_frag6_destroy(fq);
+}
+
+/* Kill fq entry. It is not destroyed immediately,
+ * because caller (and someone more) holds reference count.
+ */
+static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
+{
+	if (del_timer(&fq->timer))
+		atomic_dec(&fq->refcnt);
+
+	if (!(fq->last_in & COMPLETE)) {
+		fq_unlink(fq);
+		atomic_dec(&fq->refcnt);
+		fq->last_in |= COMPLETE;
+	}
+}
+
+static void nf_ct_frag6_evictor(void)
+{
+	struct nf_ct_frag6_queue *fq;
+	struct list_head *tmp;
+
+	for (;;) {
+		if (atomic_read(&nf_ct_frag6_mem) <= nf_ct_frag6_low_thresh)
+			return;
+		read_lock(&nf_ct_frag6_lock);
+		if (list_empty(&nf_ct_frag6_lru_list)) {
+			read_unlock(&nf_ct_frag6_lock);
+			return;
+		}
+		tmp = nf_ct_frag6_lru_list.next;
+		fq = list_entry(tmp, struct nf_ct_frag6_queue, lru_list);
+		atomic_inc(&fq->refcnt);
+		read_unlock(&nf_ct_frag6_lock);
+
+		spin_lock(&fq->lock);
+		if (!(fq->last_in&COMPLETE))
+			fq_kill(fq);
+		spin_unlock(&fq->lock);
+
+		fq_put(fq);
+	}
+}
+
+static void nf_ct_frag6_expire(unsigned long data)
+{
+	struct nf_ct_frag6_queue *fq = (struct nf_ct_frag6_queue *) data;
+
+	spin_lock(&fq->lock);
+
+	if (fq->last_in & COMPLETE)
+		goto out;
+
+	fq_kill(fq);
+
+out:
+	spin_unlock(&fq->lock);
+	fq_put(fq);
+}
+
+/* Creation primitives. */
+
+
+static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
+					  struct nf_ct_frag6_queue *fq_in)
+{
+	struct nf_ct_frag6_queue *fq;
+
+	write_lock(&nf_ct_frag6_lock);
+#ifdef CONFIG_SMP
+	for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) {
+		if (fq->id == fq_in->id && 
+		    !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) &&
+		    !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) {
+			atomic_inc(&fq->refcnt);
+			write_unlock(&nf_ct_frag6_lock);
+			fq_in->last_in |= COMPLETE;
+			fq_put(fq_in);
+			return fq;
+		}
+	}
+#endif
+	fq = fq_in;
+
+	if (!mod_timer(&fq->timer, jiffies + nf_ct_frag6_timeout))
+		atomic_inc(&fq->refcnt);
+
+	atomic_inc(&fq->refcnt);
+	if ((fq->next = nf_ct_frag6_hash[hash]) != NULL)
+		fq->next->pprev = &fq->next;
+	nf_ct_frag6_hash[hash] = fq;
+	fq->pprev = &nf_ct_frag6_hash[hash];
+	INIT_LIST_HEAD(&fq->lru_list);
+	list_add_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
+	nf_ct_frag6_nqueues++;
+	write_unlock(&nf_ct_frag6_lock);
+	return fq;
+}
+
+
+static struct nf_ct_frag6_queue *
+nf_ct_frag6_create(unsigned int hash, u32 id, struct in6_addr *src,				   struct in6_addr *dst)
+{
+	struct nf_ct_frag6_queue *fq;
+
+	if ((fq = frag_alloc_queue()) == NULL) {
+		DEBUGP("Can't alloc new queue\n");
+		goto oom;
+	}
+
+	memset(fq, 0, sizeof(struct nf_ct_frag6_queue));
+
+	fq->id = id;
+	ipv6_addr_copy(&fq->saddr, src);
+	ipv6_addr_copy(&fq->daddr, dst);
+
+	init_timer(&fq->timer);
+	fq->timer.function = nf_ct_frag6_expire;
+	fq->timer.data = (long) fq;
+	fq->lock = SPIN_LOCK_UNLOCKED;
+	atomic_set(&fq->refcnt, 1);
+
+	return nf_ct_frag6_intern(hash, fq);
+
+oom:
+	return NULL;
+}
+
+static __inline__ struct nf_ct_frag6_queue *
+fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
+{
+	struct nf_ct_frag6_queue *fq;
+	unsigned int hash = ip6qhashfn(id, src, dst);
+
+	read_lock(&nf_ct_frag6_lock);
+	for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) {
+		if (fq->id == id && 
+		    !ipv6_addr_cmp(src, &fq->saddr) &&
+		    !ipv6_addr_cmp(dst, &fq->daddr)) {
+			atomic_inc(&fq->refcnt);
+			read_unlock(&nf_ct_frag6_lock);
+			return fq;
+		}
+	}
+	read_unlock(&nf_ct_frag6_lock);
+
+	return nf_ct_frag6_create(hash, id, src, dst);
+}
+
+
+static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, 
+			     struct frag_hdr *fhdr, int nhoff)
+{
+	struct sk_buff *prev, *next;
+	int offset, end;
+
+	if (fq->last_in & COMPLETE) {
+		DEBUGP("Allready completed\n");
+		goto err;
+	}
+
+	offset = ntohs(fhdr->frag_off) & ~0x7;
+	end = offset + (ntohs(skb->nh.ipv6h->payload_len) -
+			((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
+
+	if ((unsigned int)end > IPV6_MAXPLEN) {
+		DEBUGP("offset is too large.\n");
+ 		return -1;
+	}
+
+ 	if (skb->ip_summed == CHECKSUM_HW)
+ 		skb->csum = csum_sub(skb->csum,
+ 				     csum_partial(skb->nh.raw,
+						  (u8*)(fhdr + 1) - skb->nh.raw,
+						  0));
+
+	/* Is this the final fragment? */
+	if (!(fhdr->frag_off & htons(IP6_MF))) {
+		/* If we already have some bits beyond end
+		 * or have different end, the segment is corrupted.
+		 */
+		if (end < fq->len ||
+		    ((fq->last_in & LAST_IN) && end != fq->len)) {
+			DEBUGP("already received last fragment\n");
+			goto err;
+		}
+		fq->last_in |= LAST_IN;
+		fq->len = end;
+	} else {
+		/* Check if the fragment is rounded to 8 bytes.
+		 * Required by the RFC.
+		 */
+		if (end & 0x7) {
+			/* RFC2460 says always send parameter problem in
+			 * this case. -DaveM
+			 */
+			DEBUGP("the end of this fragment is not rounded to 8 bytes.\n");
+			return -1;
+		}
+		if (end > fq->len) {
+			/* Some bits beyond end -> corruption. */
+			if (fq->last_in & LAST_IN) {
+				DEBUGP("last packet already reached.\n");
+				goto err;
+			}
+			fq->len = end;
+		}
+	}
+
+	if (end == offset)
+		goto err;
+
+	/* Point into the IP datagram 'data' part. */
+	if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) {
+		DEBUGP("queue: message is too short.\n");
+		goto err;
+	}
+	if (end-offset < skb->len) {
+		if (pskb_trim(skb, end - offset)) {
+			DEBUGP("Can't trim\n");
+			goto err;
+		}
+		if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+			skb->ip_summed = CHECKSUM_NONE;
+	}
+
+	/* Find out which fragments are in front and at the back of us
+	 * in the chain of fragments so far.  We must know where to put
+	 * this fragment, right?
+	 */
+	prev = NULL;
+	for (next = fq->fragments; next != NULL; next = next->next) {
+		if (NFCT_FRAG6_CB(next)->offset >= offset)
+			break;	/* bingo! */
+		prev = next;
+	}
+
+	/* We found where to put this one.  Check for overlap with
+	 * preceding fragment, and, if needed, align things so that
+	 * any overlaps are eliminated.
+	 */
+	if (prev) {
+		int i = (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset;
+
+		if (i > 0) {
+			offset += i;
+			if (end <= offset) {
+				DEBUGP("overlap\n");
+				goto err;
+			}
+			if (!pskb_pull(skb, i)) {
+				DEBUGP("Can't pull\n");
+				goto err;
+			}
+			if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+				skb->ip_summed = CHECKSUM_NONE;
+		}
+	}
+
+	/* Look for overlap with succeeding segments.
+	 * If we can merge fragments, do it.
+	 */
+	while (next && NFCT_FRAG6_CB(next)->offset < end) {
+		/* overlap is 'i' bytes */
+		int i = end - NFCT_FRAG6_CB(next)->offset;
+
+		if (i < next->len) {
+			/* Eat head of the next overlapped fragment
+			 * and leave the loop. The next ones cannot overlap.
+			 */
+			DEBUGP("Eat head of the overlapped parts.: %d", i);
+			if (!pskb_pull(next, i))
+				goto err;
+
+			/* next fragment */
+			NFCT_FRAG6_CB(next)->offset += i;
+			fq->meat -= i;
+			if (next->ip_summed != CHECKSUM_UNNECESSARY)
+				next->ip_summed = CHECKSUM_NONE;
+			break;
+		} else {
+			struct sk_buff *free_it = next;
+
+			/* Old fragmnet is completely overridden with
+			 * new one drop it.
+			 */
+			next = next->next;
+
+			if (prev)
+				prev->next = next;
+			else
+				fq->fragments = next;
+
+			fq->meat -= free_it->len;
+			frag_kfree_skb(free_it);
+		}
+	}
+
+	NFCT_FRAG6_CB(skb)->offset = offset;
+
+	/* Insert this fragment in the chain of fragments. */
+	skb->next = next;
+	if (prev)
+		prev->next = skb;
+	else
+		fq->fragments = skb;
+
+	skb->dev = NULL;
+	skb_get_timestamp(skb, &fq->stamp);
+	fq->meat += skb->len;
+	atomic_add(skb->truesize, &nf_ct_frag6_mem);
+
+	/* The first fragment.
+	 * nhoffset is obtained from the first fragment, of course.
+	 */
+	if (offset == 0) {
+		fq->nhoffset = nhoff;
+		fq->last_in |= FIRST_IN;
+	}
+	write_lock(&nf_ct_frag6_lock);
+	list_move_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
+	write_unlock(&nf_ct_frag6_lock);
+	return 0;
+
+err:
+	return -1;
+}
+
+/*
+ *	Check if this packet is complete.
+ *	Returns NULL on failure by any reason, and pointer
+ *	to current nexthdr field in reassembled frame.
+ *
+ *	It is called with locked fq, and caller must check that
+ *	queue is eligible for reassembly i.e. it is not COMPLETE,
+ *	the last and the first frames arrived and all the bits are here.
+ */
+static struct sk_buff *
+nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
+{
+	struct sk_buff *fp, *op, *head = fq->fragments;
+	int    payload_len;
+
+	fq_kill(fq);
+
+	BUG_TRAP(head != NULL);
+	BUG_TRAP(NFCT_FRAG6_CB(head)->offset == 0);
+
+	/* Unfragmented part is taken from the first segment. */
+	payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len - sizeof(struct frag_hdr);
+	if (payload_len > IPV6_MAXPLEN) {
+		DEBUGP("payload len is too large.\n");
+		goto out_oversize;
+	}
+
+	/* Head of list must not be cloned. */
+	if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) {
+		DEBUGP("skb is cloned but can't expand head");
+		goto out_oom;
+	}
+
+	/* If the first fragment is fragmented itself, we split
+	 * it to two chunks: the first with data and paged part
+	 * and the second, holding only fragments. */
+	if (skb_shinfo(head)->frag_list) {
+		struct sk_buff *clone;
+		int i, plen = 0;
+
+		if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) {
+			DEBUGP("Can't alloc skb\n");
+			goto out_oom;
+		}
+		clone->next = head->next;
+		head->next = clone;
+		skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
+		skb_shinfo(head)->frag_list = NULL;
+		for (i=0; i<skb_shinfo(head)->nr_frags; i++)
+			plen += skb_shinfo(head)->frags[i].size;
+		clone->len = clone->data_len = head->data_len - plen;
+		head->data_len -= clone->len;
+		head->len -= clone->len;
+		clone->csum = 0;
+		clone->ip_summed = head->ip_summed;
+
+		NFCT_FRAG6_CB(clone)->orig = NULL;
+		atomic_add(clone->truesize, &nf_ct_frag6_mem);
+	}
+
+	/* We have to remove fragment header from datagram and to relocate
+	 * header in order to calculate ICV correctly. */
+	head->nh.raw[fq->nhoffset] = head->h.raw[0];
+	memmove(head->head + sizeof(struct frag_hdr), head->head, 
+		(head->data - head->head) - sizeof(struct frag_hdr));
+	head->mac.raw += sizeof(struct frag_hdr);
+	head->nh.raw += sizeof(struct frag_hdr);
+
+	skb_shinfo(head)->frag_list = head->next;
+	head->h.raw = head->data;
+	skb_push(head, head->data - head->nh.raw);
+	atomic_sub(head->truesize, &nf_ct_frag6_mem);
+
+	for (fp=head->next; fp; fp = fp->next) {
+		head->data_len += fp->len;
+		head->len += fp->len;
+		if (head->ip_summed != fp->ip_summed)
+			head->ip_summed = CHECKSUM_NONE;
+		else if (head->ip_summed == CHECKSUM_HW)
+			head->csum = csum_add(head->csum, fp->csum);
+		head->truesize += fp->truesize;
+		atomic_sub(fp->truesize, &nf_ct_frag6_mem);
+	}
+
+	head->next = NULL;
+	head->dev = dev;
+	skb_set_timestamp(head, &fq->stamp);
+	head->nh.ipv6h->payload_len = htons(payload_len);
+
+	/* Yes, and fold redundant checksum back. 8) */
+	if (head->ip_summed == CHECKSUM_HW)
+		head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
+
+	fq->fragments = NULL;
+
+	/* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */
+	fp = skb_shinfo(head)->frag_list;
+	if (NFCT_FRAG6_CB(fp)->orig == NULL)
+		/* at above code, head skb is divided into two skbs. */
+		fp = fp->next;
+
+	op = NFCT_FRAG6_CB(head)->orig;
+	for (; fp; fp = fp->next) {
+		struct sk_buff *orig = NFCT_FRAG6_CB(fp)->orig;
+
+		op->next = orig;
+		op = orig;
+		NFCT_FRAG6_CB(fp)->orig = NULL;
+	}
+
+	return head;
+
+out_oversize:
+	if (net_ratelimit())
+		printk(KERN_DEBUG "nf_ct_frag6_reasm: payload len = %d\n", payload_len);
+	goto out_fail;
+out_oom:
+	if (net_ratelimit())
+		printk(KERN_DEBUG "nf_ct_frag6_reasm: no memory for reassembly\n");
+out_fail:
+	return NULL;
+}
+
+/*
+ * find the header just before Fragment Header.
+ *
+ * if success return 0 and set ...
+ * (*prevhdrp): the value of "Next Header Field" in the header
+ *		just before Fragment Header.
+ * (*prevhoff): the offset of "Next Header Field" in the header
+ *		just before Fragment Header.
+ * (*fhoff)   : the offset of Fragment Header.
+ *
+ * Based on ipv6_skip_hdr() in net/ipv6/exthdr.c
+ *
+ */
+static int
+find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
+{
+        u8 nexthdr = skb->nh.ipv6h->nexthdr;
+	u8 prev_nhoff = (u8 *)&skb->nh.ipv6h->nexthdr - skb->data;
+	int start = (u8 *)(skb->nh.ipv6h+1) - skb->data;
+	int len = skb->len - start;
+	u8 prevhdr = NEXTHDR_IPV6;
+
+        while (nexthdr != NEXTHDR_FRAGMENT) {
+                struct ipv6_opt_hdr hdr;
+                int hdrlen;
+
+		if (!ipv6_ext_hdr(nexthdr)) {
+			return -1;
+		}
+                if (len < (int)sizeof(struct ipv6_opt_hdr)) {
+			DEBUGP("too short\n");
+			return -1;
+		}
+                if (nexthdr == NEXTHDR_NONE) {
+			DEBUGP("next header is none\n");
+			return -1;
+		}
+                if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
+                        BUG();
+                if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr.hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(&hdr);
+
+		prevhdr = nexthdr;
+		prev_nhoff = start;
+
+                nexthdr = hdr.nexthdr;
+                len -= hdrlen;
+                start += hdrlen;
+        }
+
+	if (len < 0)
+		return -1;
+
+	*prevhdrp = prevhdr;
+	*prevhoff = prev_nhoff;
+	*fhoff = start;
+
+	return 0;
+}
+
+struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
+{
+	struct sk_buff *clone; 
+	struct net_device *dev = skb->dev;
+	struct frag_hdr *fhdr;
+	struct nf_ct_frag6_queue *fq;
+	struct ipv6hdr *hdr;
+	int fhoff, nhoff;
+	u8 prevhdr;
+	struct sk_buff *ret_skb = NULL;
+
+	/* Jumbo payload inhibits frag. header */
+	if (skb->nh.ipv6h->payload_len == 0) {
+		DEBUGP("payload len = 0\n");
+		return skb;
+	}
+
+	if (find_prev_fhdr(skb, &prevhdr, &nhoff, &fhoff) < 0)
+		return skb;
+
+	clone = skb_clone(skb, GFP_ATOMIC);
+	if (clone == NULL) {
+		DEBUGP("Can't clone skb\n");
+		return skb;
+	}
+
+	NFCT_FRAG6_CB(clone)->orig = skb;
+
+	if (!pskb_may_pull(clone, fhoff + sizeof(*fhdr))) {
+		DEBUGP("message is too short.\n");
+		goto ret_orig;
+	}
+
+	clone->h.raw = clone->data + fhoff;
+	hdr = clone->nh.ipv6h;
+	fhdr = (struct frag_hdr *)clone->h.raw;
+
+	if (!(fhdr->frag_off & htons(0xFFF9))) {
+		DEBUGP("Invalid fragment offset\n");
+		/* It is not a fragmented frame */
+		goto ret_orig;
+	}
+
+	if (atomic_read(&nf_ct_frag6_mem) > nf_ct_frag6_high_thresh)
+		nf_ct_frag6_evictor();
+
+	fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);
+	if (fq == NULL) {
+		DEBUGP("Can't find and can't create new queue\n");
+		goto ret_orig;
+	}
+
+	spin_lock(&fq->lock);
+
+	if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {
+		spin_unlock(&fq->lock);
+		DEBUGP("Can't insert skb to queue\n");
+		fq_put(fq);
+		goto ret_orig;
+	}
+
+	if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) {
+		ret_skb = nf_ct_frag6_reasm(fq, dev);
+		if (ret_skb == NULL)
+			DEBUGP("Can't reassemble fragmented packets\n");
+	}
+	spin_unlock(&fq->lock);
+
+	fq_put(fq);
+	return ret_skb;
+
+ret_orig:
+	kfree_skb(clone);
+	return skb;
+}
+
+void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
+			struct net_device *in, struct net_device *out,
+			int (*okfn)(struct sk_buff *))
+{
+	struct sk_buff *s, *s2;
+
+	for (s = NFCT_FRAG6_CB(skb)->orig; s;) {
+		nf_conntrack_put_reasm(s->nfct_reasm);
+		nf_conntrack_get_reasm(skb);
+		s->nfct_reasm = skb;
+
+		s2 = s->next;
+		NF_HOOK_THRESH(PF_INET6, hooknum, s, in, out, okfn,
+			       NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
+		s = s2;
+	}
+	nf_conntrack_put_reasm(skb);
+}
+
+int nf_ct_frag6_kfree_frags(struct sk_buff *skb)
+{
+	struct sk_buff *s, *s2;
+
+	for (s = NFCT_FRAG6_CB(skb)->orig; s; s = s2) {
+
+		s2 = s->next;
+		kfree_skb(s);
+	}
+
+	kfree_skb(skb);
+
+	return 0;
+}
+
+int nf_ct_frag6_init(void)
+{
+	nf_ct_frag6_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
+				   (jiffies ^ (jiffies >> 6)));
+
+	init_timer(&nf_ct_frag6_secret_timer);
+	nf_ct_frag6_secret_timer.function = nf_ct_frag6_secret_rebuild;
+	nf_ct_frag6_secret_timer.expires = jiffies
+					   + nf_ct_frag6_secret_interval;
+	add_timer(&nf_ct_frag6_secret_timer);
+
+	return 0;
+}
+
+void nf_ct_frag6_cleanup(void)
+{
+	del_timer(&nf_ct_frag6_secret_timer);
+	nf_ct_frag6_evictor();
+}
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index a1265a3..8e9628f 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -174,8 +174,10 @@
 			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
 			/* Not releasing hash table! */
-			if (clone)
+			if (clone) {
+				nf_reset(clone);
 				rawv6_rcv(sk, clone);
+			}
 		}
 		sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr,
 				     IP6CB(skb)->iif);
@@ -296,13 +298,10 @@
 static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
 {
 	if ((raw6_sk(sk)->checksum || sk->sk_filter) && 
-	    skb->ip_summed != CHECKSUM_UNNECESSARY) {
-		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
-			/* FIXME: increment a raw6 drops counter here */
-			kfree_skb(skb);
-			return 0;
-		}
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	    skb_checksum_complete(skb)) {
+		/* FIXME: increment a raw6 drops counter here */
+		kfree_skb(skb);
+		return 0;
 	}
 
 	/* Charge it to the socket. */
@@ -335,32 +334,25 @@
 	if (!rp->checksum)
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-	if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
-		if (skb->ip_summed == CHECKSUM_HW) {
-			skb_postpull_rcsum(skb, skb->nh.raw,
-			                   skb->h.raw - skb->nh.raw);
+	if (skb->ip_summed == CHECKSUM_HW) {
+		skb_postpull_rcsum(skb, skb->nh.raw,
+		                   skb->h.raw - skb->nh.raw);
+		if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr,
+				     &skb->nh.ipv6h->daddr,
+				     skb->len, inet->num, skb->csum))
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
-			if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-					    &skb->nh.ipv6h->daddr,
-					    skb->len, inet->num, skb->csum)) {
-				LIMIT_NETDEBUG(KERN_DEBUG "raw v6 hw csum failure.\n");
-				skb->ip_summed = CHECKSUM_NONE;
-			}
-		}
-		if (skb->ip_summed == CHECKSUM_NONE)
-			skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-						     &skb->nh.ipv6h->daddr,
-						     skb->len, inet->num, 0);
 	}
+	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+		skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr,
+					     &skb->nh.ipv6h->daddr,
+					     skb->len, inet->num, 0);
 
 	if (inet->hdrincl) {
-		if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
-		    (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
+		if (skb_checksum_complete(skb)) {
 			/* FIXME: increment a raw6 drops counter here */
 			kfree_skb(skb);
 			return 0;
 		}
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
 
 	rawv6_rcv_skb(sk, skb);
@@ -405,7 +397,7 @@
 	if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
 		err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	} else if (msg->msg_flags&MSG_TRUNC) {
-		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)))
+		if (__skb_checksum_complete(skb))
 			goto csum_copy_err;
 		err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	} else {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 227e99e..f7f42c3 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1710,7 +1710,7 @@
 static int fib6_dump_done(struct netlink_callback *cb)
 {
 	fib6_dump_end(cb);
-	return cb->done(cb);
+	return cb->done ? cb->done(cb) : 0;
 }
 
 int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index d746d3b..62c0e5b 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1401,20 +1401,18 @@
 static int tcp_v6_checksum_init(struct sk_buff *skb)
 {
 	if (skb->ip_summed == CHECKSUM_HW) {
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
 		if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-				  &skb->nh.ipv6h->daddr,skb->csum))
+				  &skb->nh.ipv6h->daddr,skb->csum)) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			return 0;
-		LIMIT_NETDEBUG(KERN_DEBUG "hw tcp v6 csum failed\n");
+		}
 	}
+
+	skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
+				  &skb->nh.ipv6h->daddr, 0);
+
 	if (skb->len <= 76) {
-		if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-				 &skb->nh.ipv6h->daddr,skb_checksum(skb, 0, skb->len, 0)))
-			return -1;
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	} else {
-		skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-					  &skb->nh.ipv6h->daddr,0);
+		return __skb_checksum_complete(skb);
 	}
 	return 0;
 }
@@ -1575,7 +1573,7 @@
 		goto discard_it;
 
 	if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
-	     tcp_v6_checksum_init(skb) < 0))
+	     tcp_v6_checksum_init(skb)))
 		goto bad_packet;
 
 	th = skb->h.th;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index bf95193..e671153 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -248,7 +248,7 @@
 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
 					      copied);
 	} else if (msg->msg_flags&MSG_TRUNC) {
-		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)))
+		if (__skb_checksum_complete(skb))
 			goto csum_copy_err;
 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
 					      copied);
@@ -363,13 +363,10 @@
 		return -1;
 	}
 
-	if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
-		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
-			UDP6_INC_STATS_BH(UDP_MIB_INERRORS);
-			kfree_skb(skb);
-			return 0;
-		}
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	if (skb_checksum_complete(skb)) {
+		UDP6_INC_STATS_BH(UDP_MIB_INERRORS);
+		kfree_skb(skb);
+		return 0;
 	}
 
 	if (sock_queue_rcv_skb(sk,skb)<0) {
@@ -491,13 +488,10 @@
 		uh = skb->h.uh;
 	}
 
-	if (skb->ip_summed==CHECKSUM_HW) {
+	if (skb->ip_summed == CHECKSUM_HW &&
+	    !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum))
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) {
-			LIMIT_NETDEBUG(KERN_DEBUG "udp v6 hw csum failure.\n");
-			skb->ip_summed = CHECKSUM_NONE;
-		}
-	}
+
 	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
 		skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0);
 
@@ -521,8 +515,7 @@
 		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
 			goto discard;
 
-		if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
-		    (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)))
+		if (skb_checksum_complete(skb))
 			goto discard;
 		UDP6_INC_STATS_BH(UDP_MIB_NOPORTS);
 
diff --git a/net/irda/discovery.c b/net/irda/discovery.c
index c4ba5fa..3fefc82 100644
--- a/net/irda/discovery.c
+++ b/net/irda/discovery.c
@@ -194,8 +194,7 @@
 
 			/* Remove it from the log */
 			curr = hashbin_remove_this(log, (irda_queue_t *) curr);
-			if (curr)
-				kfree(curr);
+			kfree(curr);
 		}
 	}
 
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index 6fec428..75f2666 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -122,8 +122,7 @@
 	IRDA_ASSERT(attrib != NULL, return;);
 	IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
 
-	if (attrib->name)
-		kfree(attrib->name);
+	kfree(attrib->name);
 
 	irias_delete_value(attrib->value);
 	attrib->magic = ~IAS_ATTRIB_MAGIC;
@@ -136,8 +135,7 @@
 	IRDA_ASSERT(obj != NULL, return;);
 	IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 
-	if (obj->name)
-		kfree(obj->name);
+	kfree(obj->name);
 
 	hashbin_delete(obj->attribs, (FREE_FUNC) __irias_delete_attrib);
 
@@ -562,14 +560,12 @@
 		/* No need to deallocate */
 		break;
 	case IAS_STRING:
-		/* If string, deallocate string */
-		if (value->t.string != NULL)
-			kfree(value->t.string);
+		/* Deallocate string */
+		kfree(value->t.string);
 		break;
 	case IAS_OCT_SEQ:
-		/* If byte stream, deallocate byte stream */
-		 if (value->t.oct_seq != NULL)
-			 kfree(value->t.oct_seq);
+		/* Deallocate byte stream */
+		 kfree(value->t.oct_seq);
 		 break;
 	default:
 		IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 8296b38..a84f922 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -1,3 +1,6 @@
+menu "Core Netfilter Configuration"
+	depends on NET && NETFILTER
+
 config NETFILTER_NETLINK
        tristate "Netfilter netlink interface"
        help
@@ -22,3 +25,74 @@
 	  and is also scheduled to replace the old syslog-based ipt_LOG
 	  and ip6t_LOG modules.
 
+config NF_CONNTRACK
+	tristate "Layer 3 Independent Connection tracking (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && IP_NF_CONNTRACK=n
+	default n
+	---help---
+	  Connection tracking keeps a record of what packets have passed
+	  through your machine, in order to figure out how they are related
+	  into connections.
+
+	  Layer 3 independent connection tracking is experimental scheme
+	  which generalize ip_conntrack to support other layer 3 protocols.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NF_CT_ACCT
+	bool "Connection tracking flow accounting"
+	depends on NF_CONNTRACK
+	help
+	  If this option is enabled, the connection tracking code will
+	  keep per-flow packet and byte counters.
+
+	  Those counters can be used for flow-based accounting or the
+	  `connbytes' match.
+
+	  If unsure, say `N'.
+
+config NF_CONNTRACK_MARK
+	bool  'Connection mark tracking support'
+	depends on NF_CONNTRACK
+	help
+	  This option enables support for connection marks, used by the
+	  `CONNMARK' target and `connmark' match. Similar to the mark value
+	  of packets, but this mark value is kept in the conntrack session
+	  instead of the individual packets.
+
+config NF_CONNTRACK_EVENTS
+	bool "Connection tracking events"
+	depends on NF_CONNTRACK
+	help
+	  If this option is enabled, the connection tracking code will
+	  provide a notifier chain that can be used by other kernel code
+	  to get notified aboutchanges in the connection tracking state.
+
+	  If unsure, say `N'.
+
+config NF_CT_PROTO_SCTP
+	tristate 'SCTP protocol on new connection tracking support (EXPERIMENTAL)'
+	depends on EXPERIMENTAL && NF_CONNTRACK
+	default n
+	help
+	  With this option enabled, the layer 3 independent connection
+	  tracking code will be able to do state tracking on SCTP connections.
+
+	  If you want to compile it as a module, say M here and read
+	  Documentation/modules.txt.  If unsure, say `N'.
+
+config NF_CONNTRACK_FTP
+	tristate "FTP support on new connection tracking (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && NF_CONNTRACK
+	help
+	  Tracking FTP connections is problematic: special helpers are
+	  required for tracking them, and doing masquerading and other forms
+	  of Network Address Translation on them.
+
+	  This is FTP support on Layer 3 independent connection tracking.
+	  Layer 3 independent connection tracking is experimental scheme
+	  which generalize ip_conntrack to support other layer 3 protocols.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+endmenu
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index b3b44f8..55f019a 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -5,3 +5,11 @@
 obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
 obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
 obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
+
+nf_conntrack-objs	:= nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
+
+obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
+obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
+
+# SCTP protocol connection tracking
+obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
new file mode 100644
index 0000000..9a67c79
--- /dev/null
+++ b/net/netfilter/nf_conntrack_core.c
@@ -0,0 +1,1538 @@
+/* Connection state tracking for netfilter.  This is separated from,
+   but required by, the NAT layer; it can also be used by an iptables
+   extension. */
+
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ *
+ * 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.
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ *	- new API and handling of conntrack/nat helpers
+ *	- now capable of multiple expectations for one master
+ * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
+ *	- add usage/reference counts to ip_conntrack_expect
+ *	- export ip_conntrack[_expect]_{find_get,put} functions
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- generalize L3 protocol denendent part.
+ * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- add support various size of conntrack structures.
+ *
+ * Derived from net/ipv4/netfilter/ip_conntrack_core.c
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+#include <linux/err.h>
+#include <linux/percpu.h>
+#include <linux/moduleparam.h>
+#include <linux/notifier.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/socket.h>
+
+/* This rwlock protects the main hash table, protocol/helper/expected
+   registrations, conntrack timers*/
+#define ASSERT_READ_LOCK(x)
+#define ASSERT_WRITE_LOCK(x)
+
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_l3proto.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <linux/netfilter_ipv4/listhelp.h>
+
+#define NF_CONNTRACK_VERSION	"0.4.1"
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+DEFINE_RWLOCK(nf_conntrack_lock);
+
+/* nf_conntrack_standalone needs this */
+atomic_t nf_conntrack_count = ATOMIC_INIT(0);
+
+void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL;
+LIST_HEAD(nf_conntrack_expect_list);
+struct nf_conntrack_protocol **nf_ct_protos[PF_MAX];
+struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX];
+static LIST_HEAD(helpers);
+unsigned int nf_conntrack_htable_size = 0;
+int nf_conntrack_max;
+struct list_head *nf_conntrack_hash;
+static kmem_cache_t *nf_conntrack_expect_cachep;
+struct nf_conn nf_conntrack_untracked;
+unsigned int nf_ct_log_invalid;
+static LIST_HEAD(unconfirmed);
+static int nf_conntrack_vmalloc;
+
+#ifdef CONFIG_NF_CONNTRACK_EVENTS
+struct notifier_block *nf_conntrack_chain;
+struct notifier_block *nf_conntrack_expect_chain;
+
+DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache);
+
+/* deliver cached events and clear cache entry - must be called with locally
+ * disabled softirqs */
+static inline void
+__nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache)
+{
+	DEBUGP("ecache: delivering events for %p\n", ecache->ct);
+	if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct)
+	    && ecache->events)
+		notifier_call_chain(&nf_conntrack_chain, ecache->events,
+				    ecache->ct);
+
+	ecache->events = 0;
+	nf_ct_put(ecache->ct);
+	ecache->ct = NULL;
+}
+
+/* Deliver all cached events for a particular conntrack. This is called
+ * by code prior to async packet handling for freeing the skb */
+void nf_ct_deliver_cached_events(const struct nf_conn *ct)
+{
+	struct nf_conntrack_ecache *ecache;
+
+	local_bh_disable();
+	ecache = &__get_cpu_var(nf_conntrack_ecache);
+	if (ecache->ct == ct)
+		__nf_ct_deliver_cached_events(ecache);
+	local_bh_enable();
+}
+
+/* Deliver cached events for old pending events, if current conntrack != old */
+void __nf_ct_event_cache_init(struct nf_conn *ct)
+{
+	struct nf_conntrack_ecache *ecache;
+	
+	/* take care of delivering potentially old events */
+	ecache = &__get_cpu_var(nf_conntrack_ecache);
+	BUG_ON(ecache->ct == ct);
+	if (ecache->ct)
+		__nf_ct_deliver_cached_events(ecache);
+	/* initialize for this conntrack/packet */
+	ecache->ct = ct;
+	nf_conntrack_get(&ct->ct_general);
+}
+
+/* flush the event cache - touches other CPU's data and must not be called
+ * while packets are still passing through the code */
+static void nf_ct_event_cache_flush(void)
+{
+	struct nf_conntrack_ecache *ecache;
+	int cpu;
+
+	for_each_cpu(cpu) {
+		ecache = &per_cpu(nf_conntrack_ecache, cpu);
+		if (ecache->ct)
+			nf_ct_put(ecache->ct);
+	}
+}
+#else
+static inline void nf_ct_event_cache_flush(void) {}
+#endif /* CONFIG_NF_CONNTRACK_EVENTS */
+
+DEFINE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);
+EXPORT_PER_CPU_SYMBOL(nf_conntrack_stat);
+
+/*
+ * This scheme offers various size of "struct nf_conn" dependent on
+ * features(helper, nat, ...)
+ */
+
+#define NF_CT_FEATURES_NAMELEN	256
+static struct {
+	/* name of slab cache. printed in /proc/slabinfo */
+	char *name;
+
+	/* size of slab cache */
+	size_t size;
+
+	/* slab cache pointer */
+	kmem_cache_t *cachep;
+
+	/* allocated slab cache + modules which uses this slab cache */
+	int use;
+
+	/* Initialization */
+	int (*init_conntrack)(struct nf_conn *, u_int32_t);
+
+} nf_ct_cache[NF_CT_F_NUM];
+
+/* protect members of nf_ct_cache except of "use" */
+DEFINE_RWLOCK(nf_ct_cache_lock);
+
+/* This avoids calling kmem_cache_create() with same name simultaneously */
+DECLARE_MUTEX(nf_ct_cache_mutex);
+
+extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
+struct nf_conntrack_protocol *
+nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol)
+{
+	if (unlikely(nf_ct_protos[l3proto] == NULL))
+		return &nf_conntrack_generic_protocol;
+
+	return nf_ct_protos[l3proto][protocol];
+}
+
+static int nf_conntrack_hash_rnd_initted;
+static unsigned int nf_conntrack_hash_rnd;
+
+static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
+				  unsigned int size, unsigned int rnd)
+{
+	unsigned int a, b;
+	a = jhash((void *)tuple->src.u3.all, sizeof(tuple->src.u3.all),
+		  ((tuple->src.l3num) << 16) | tuple->dst.protonum);
+	b = jhash((void *)tuple->dst.u3.all, sizeof(tuple->dst.u3.all),
+			(tuple->src.u.all << 16) | tuple->dst.u.all);
+
+	return jhash_2words(a, b, rnd) % size;
+}
+
+static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple)
+{
+	return __hash_conntrack(tuple, nf_conntrack_htable_size,
+				nf_conntrack_hash_rnd);
+}
+
+/* Initialize "struct nf_conn" which has spaces for helper */
+static int
+init_conntrack_for_helper(struct nf_conn *conntrack, u_int32_t features)
+{
+
+	conntrack->help = (union nf_conntrack_help *)
+		(((unsigned long)conntrack->data
+		  + (__alignof__(union nf_conntrack_help) - 1))
+		 & (~((unsigned long)(__alignof__(union nf_conntrack_help) -1))));
+	return 0;
+}
+
+int nf_conntrack_register_cache(u_int32_t features, const char *name,
+				size_t size,
+				int (*init)(struct nf_conn *, u_int32_t))
+{
+	int ret = 0;
+	char *cache_name;
+	kmem_cache_t *cachep;
+
+	DEBUGP("nf_conntrack_register_cache: features=0x%x, name=%s, size=%d\n",
+	       features, name, size);
+
+	if (features < NF_CT_F_BASIC || features >= NF_CT_F_NUM) {
+		DEBUGP("nf_conntrack_register_cache: invalid features.: 0x%x\n",
+			features);
+		return -EINVAL;
+	}
+
+	down(&nf_ct_cache_mutex);
+
+	write_lock_bh(&nf_ct_cache_lock);
+	/* e.g: multiple helpers are loaded */
+	if (nf_ct_cache[features].use > 0) {
+		DEBUGP("nf_conntrack_register_cache: already resisterd.\n");
+		if ((!strncmp(nf_ct_cache[features].name, name,
+			      NF_CT_FEATURES_NAMELEN))
+		    && nf_ct_cache[features].size == size
+		    && nf_ct_cache[features].init_conntrack == init) {
+			DEBUGP("nf_conntrack_register_cache: reusing.\n");
+			nf_ct_cache[features].use++;
+			ret = 0;
+		} else
+			ret = -EBUSY;
+
+		write_unlock_bh(&nf_ct_cache_lock);
+		up(&nf_ct_cache_mutex);
+		return ret;
+	}
+	write_unlock_bh(&nf_ct_cache_lock);
+
+	/*
+	 * The memory space for name of slab cache must be alive until
+	 * cache is destroyed.
+	 */
+	cache_name = kmalloc(sizeof(char)*NF_CT_FEATURES_NAMELEN, GFP_ATOMIC);
+	if (cache_name == NULL) {
+		DEBUGP("nf_conntrack_register_cache: can't alloc cache_name\n");
+		ret = -ENOMEM;
+		goto out_up_mutex;
+	}
+
+	if (strlcpy(cache_name, name, NF_CT_FEATURES_NAMELEN)
+						>= NF_CT_FEATURES_NAMELEN) {
+		printk("nf_conntrack_register_cache: name too long\n");
+		ret = -EINVAL;
+		goto out_free_name;
+	}
+
+	cachep = kmem_cache_create(cache_name, size, 0, 0,
+				   NULL, NULL);
+	if (!cachep) {
+		printk("nf_conntrack_register_cache: Can't create slab cache "
+		       "for the features = 0x%x\n", features);
+		ret = -ENOMEM;
+		goto out_free_name;
+	}
+
+	write_lock_bh(&nf_ct_cache_lock);
+	nf_ct_cache[features].use = 1;
+	nf_ct_cache[features].size = size;
+	nf_ct_cache[features].init_conntrack = init;
+	nf_ct_cache[features].cachep = cachep;
+	nf_ct_cache[features].name = cache_name;
+	write_unlock_bh(&nf_ct_cache_lock);
+
+	goto out_up_mutex;
+
+out_free_name:
+	kfree(cache_name);
+out_up_mutex:
+	up(&nf_ct_cache_mutex);
+	return ret;
+}
+
+/* FIXME: In the current, only nf_conntrack_cleanup() can call this function. */
+void nf_conntrack_unregister_cache(u_int32_t features)
+{
+	kmem_cache_t *cachep;
+	char *name;
+
+	/*
+	 * This assures that kmem_cache_create() isn't called before destroying
+	 * slab cache.
+	 */
+	DEBUGP("nf_conntrack_unregister_cache: 0x%04x\n", features);
+	down(&nf_ct_cache_mutex);
+
+	write_lock_bh(&nf_ct_cache_lock);
+	if (--nf_ct_cache[features].use > 0) {
+		write_unlock_bh(&nf_ct_cache_lock);
+		up(&nf_ct_cache_mutex);
+		return;
+	}
+	cachep = nf_ct_cache[features].cachep;
+	name = nf_ct_cache[features].name;
+	nf_ct_cache[features].cachep = NULL;
+	nf_ct_cache[features].name = NULL;
+	nf_ct_cache[features].init_conntrack = NULL;
+	nf_ct_cache[features].size = 0;
+	write_unlock_bh(&nf_ct_cache_lock);
+
+	synchronize_net();
+
+	kmem_cache_destroy(cachep);
+	kfree(name);
+
+	up(&nf_ct_cache_mutex);
+}
+
+int
+nf_ct_get_tuple(const struct sk_buff *skb,
+		unsigned int nhoff,
+		unsigned int dataoff,
+		u_int16_t l3num,
+		u_int8_t protonum,
+		struct nf_conntrack_tuple *tuple,
+		const struct nf_conntrack_l3proto *l3proto,
+		const struct nf_conntrack_protocol *protocol)
+{
+	NF_CT_TUPLE_U_BLANK(tuple);
+
+	tuple->src.l3num = l3num;
+	if (l3proto->pkt_to_tuple(skb, nhoff, tuple) == 0)
+		return 0;
+
+	tuple->dst.protonum = protonum;
+	tuple->dst.dir = IP_CT_DIR_ORIGINAL;
+
+	return protocol->pkt_to_tuple(skb, dataoff, tuple);
+}
+
+int
+nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
+		   const struct nf_conntrack_tuple *orig,
+		   const struct nf_conntrack_l3proto *l3proto,
+		   const struct nf_conntrack_protocol *protocol)
+{
+	NF_CT_TUPLE_U_BLANK(inverse);
+
+	inverse->src.l3num = orig->src.l3num;
+	if (l3proto->invert_tuple(inverse, orig) == 0)
+		return 0;
+
+	inverse->dst.dir = !orig->dst.dir;
+
+	inverse->dst.protonum = orig->dst.protonum;
+	return protocol->invert_tuple(inverse, orig);
+}
+
+/* nf_conntrack_expect helper functions */
+static void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
+{
+	ASSERT_WRITE_LOCK(&nf_conntrack_lock);
+	NF_CT_ASSERT(!timer_pending(&exp_timeout));
+	list_del(&exp->list);
+	NF_CT_STAT_INC(expect_delete);
+	exp->master->expecting--;
+	nf_conntrack_expect_put(exp);
+}
+
+static void expectation_timed_out(unsigned long ul_expect)
+{
+	struct nf_conntrack_expect *exp = (void *)ul_expect;
+
+	write_lock_bh(&nf_conntrack_lock);
+	nf_ct_unlink_expect(exp);
+	write_unlock_bh(&nf_conntrack_lock);
+	nf_conntrack_expect_put(exp);
+}
+
+/* If an expectation for this connection is found, it gets delete from
+ * global list then returned. */
+static struct nf_conntrack_expect *
+find_expectation(const struct nf_conntrack_tuple *tuple)
+{
+	struct nf_conntrack_expect *i;
+
+	list_for_each_entry(i, &nf_conntrack_expect_list, list) {
+	/* If master is not in hash table yet (ie. packet hasn't left
+	   this machine yet), how can other end know about expected?
+	   Hence these are not the droids you are looking for (if
+	   master ct never got confirmed, we'd hold a reference to it
+	   and weird things would happen to future packets). */
+		if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)
+		    && nf_ct_is_confirmed(i->master)) {
+			if (i->flags & NF_CT_EXPECT_PERMANENT) {
+				atomic_inc(&i->use);
+				return i;
+			} else if (del_timer(&i->timeout)) {
+				nf_ct_unlink_expect(i);
+				return i;
+			}
+		}
+	}
+	return NULL;
+}
+
+/* delete all expectations for this conntrack */
+static void remove_expectations(struct nf_conn *ct)
+{
+	struct nf_conntrack_expect *i, *tmp;
+
+	/* Optimization: most connection never expect any others. */
+	if (ct->expecting == 0)
+		return;
+
+	list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) {
+		if (i->master == ct && del_timer(&i->timeout)) {
+			nf_ct_unlink_expect(i);
+			nf_conntrack_expect_put(i);
+ 		}
+	}
+}
+
+static void
+clean_from_lists(struct nf_conn *ct)
+{
+	unsigned int ho, hr;
+	
+	DEBUGP("clean_from_lists(%p)\n", ct);
+	ASSERT_WRITE_LOCK(&nf_conntrack_lock);
+
+	ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+	hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+	LIST_DELETE(&nf_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
+	LIST_DELETE(&nf_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
+
+	/* Destroy all pending expectations */
+	remove_expectations(ct);
+}
+
+static void
+destroy_conntrack(struct nf_conntrack *nfct)
+{
+	struct nf_conn *ct = (struct nf_conn *)nfct;
+	struct nf_conntrack_l3proto *l3proto;
+	struct nf_conntrack_protocol *proto;
+
+	DEBUGP("destroy_conntrack(%p)\n", ct);
+	NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
+	NF_CT_ASSERT(!timer_pending(&ct->timeout));
+
+	nf_conntrack_event(IPCT_DESTROY, ct);
+	set_bit(IPS_DYING_BIT, &ct->status);
+
+	/* To make sure we don't get any weird locking issues here:
+	 * destroy_conntrack() MUST NOT be called with a write lock
+	 * to nf_conntrack_lock!!! -HW */
+	l3proto = nf_ct_find_l3proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num);
+	if (l3proto && l3proto->destroy)
+		l3proto->destroy(ct);
+
+	proto = nf_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num,
+				 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
+	if (proto && proto->destroy)
+		proto->destroy(ct);
+
+	if (nf_conntrack_destroyed)
+		nf_conntrack_destroyed(ct);
+
+	write_lock_bh(&nf_conntrack_lock);
+	/* Expectations will have been removed in clean_from_lists,
+	 * except TFTP can create an expectation on the first packet,
+	 * before connection is in the list, so we need to clean here,
+	 * too. */
+	remove_expectations(ct);
+
+	/* We overload first tuple to link into unconfirmed list. */
+	if (!nf_ct_is_confirmed(ct)) {
+		BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list));
+		list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
+	}
+
+	NF_CT_STAT_INC(delete);
+	write_unlock_bh(&nf_conntrack_lock);
+
+	if (ct->master)
+		nf_ct_put(ct->master);
+
+	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
+	nf_conntrack_free(ct);
+}
+
+static void death_by_timeout(unsigned long ul_conntrack)
+{
+	struct nf_conn *ct = (void *)ul_conntrack;
+
+	write_lock_bh(&nf_conntrack_lock);
+	/* Inside lock so preempt is disabled on module removal path.
+	 * Otherwise we can get spurious warnings. */
+	NF_CT_STAT_INC(delete_list);
+	clean_from_lists(ct);
+	write_unlock_bh(&nf_conntrack_lock);
+	nf_ct_put(ct);
+}
+
+static inline int
+conntrack_tuple_cmp(const struct nf_conntrack_tuple_hash *i,
+		    const struct nf_conntrack_tuple *tuple,
+		    const struct nf_conn *ignored_conntrack)
+{
+	ASSERT_READ_LOCK(&nf_conntrack_lock);
+	return nf_ct_tuplehash_to_ctrack(i) != ignored_conntrack
+		&& nf_ct_tuple_equal(tuple, &i->tuple);
+}
+
+static struct nf_conntrack_tuple_hash *
+__nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
+		    const struct nf_conn *ignored_conntrack)
+{
+	struct nf_conntrack_tuple_hash *h;
+	unsigned int hash = hash_conntrack(tuple);
+
+	ASSERT_READ_LOCK(&nf_conntrack_lock);
+	list_for_each_entry(h, &nf_conntrack_hash[hash], list) {
+		if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) {
+			NF_CT_STAT_INC(found);
+			return h;
+		}
+		NF_CT_STAT_INC(searched);
+	}
+
+	return NULL;
+}
+
+/* Find a connection corresponding to a tuple. */
+struct nf_conntrack_tuple_hash *
+nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple,
+		      const struct nf_conn *ignored_conntrack)
+{
+	struct nf_conntrack_tuple_hash *h;
+
+	read_lock_bh(&nf_conntrack_lock);
+	h = __nf_conntrack_find(tuple, ignored_conntrack);
+	if (h)
+		atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use);
+	read_unlock_bh(&nf_conntrack_lock);
+
+	return h;
+}
+
+/* Confirm a connection given skb; places it in hash table */
+int
+__nf_conntrack_confirm(struct sk_buff **pskb)
+{
+	unsigned int hash, repl_hash;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+
+	ct = nf_ct_get(*pskb, &ctinfo);
+
+	/* ipt_REJECT uses nf_conntrack_attach to attach related
+	   ICMP/TCP RST packets in other direction.  Actual packet
+	   which created connection will be IP_CT_NEW or for an
+	   expected connection, IP_CT_RELATED. */
+	if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
+		return NF_ACCEPT;
+
+	hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+	repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+
+	/* We're not in hash table, and we refuse to set up related
+	   connections for unconfirmed conns.  But packet copies and
+	   REJECT will give spurious warnings here. */
+	/* NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
+
+	/* No external references means noone else could have
+	   confirmed us. */
+	NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
+	DEBUGP("Confirming conntrack %p\n", ct);
+
+	write_lock_bh(&nf_conntrack_lock);
+
+	/* See if there's one in the list already, including reverse:
+	   NAT could have grabbed it without realizing, since we're
+	   not in the hash.  If there is, we lost race. */
+	if (!LIST_FIND(&nf_conntrack_hash[hash],
+		       conntrack_tuple_cmp,
+		       struct nf_conntrack_tuple_hash *,
+		       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
+	    && !LIST_FIND(&nf_conntrack_hash[repl_hash],
+			  conntrack_tuple_cmp,
+			  struct nf_conntrack_tuple_hash *,
+			  &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
+		/* Remove from unconfirmed list */
+		list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
+
+		list_prepend(&nf_conntrack_hash[hash],
+			     &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
+		list_prepend(&nf_conntrack_hash[repl_hash],
+			     &ct->tuplehash[IP_CT_DIR_REPLY]);
+		/* Timer relative to confirmation time, not original
+		   setting time, otherwise we'd get timer wrap in
+		   weird delay cases. */
+		ct->timeout.expires += jiffies;
+		add_timer(&ct->timeout);
+		atomic_inc(&ct->ct_general.use);
+		set_bit(IPS_CONFIRMED_BIT, &ct->status);
+		NF_CT_STAT_INC(insert);
+		write_unlock_bh(&nf_conntrack_lock);
+		if (ct->helper)
+			nf_conntrack_event_cache(IPCT_HELPER, *pskb);
+#ifdef CONFIG_NF_NAT_NEEDED
+		if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
+		    test_bit(IPS_DST_NAT_DONE_BIT, &ct->status))
+			nf_conntrack_event_cache(IPCT_NATINFO, *pskb);
+#endif
+		nf_conntrack_event_cache(master_ct(ct) ?
+					 IPCT_RELATED : IPCT_NEW, *pskb);
+		return NF_ACCEPT;
+	}
+
+	NF_CT_STAT_INC(insert_failed);
+	write_unlock_bh(&nf_conntrack_lock);
+	return NF_DROP;
+}
+
+/* Returns true if a connection correspondings to the tuple (required
+   for NAT). */
+int
+nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
+			 const struct nf_conn *ignored_conntrack)
+{
+	struct nf_conntrack_tuple_hash *h;
+
+	read_lock_bh(&nf_conntrack_lock);
+	h = __nf_conntrack_find(tuple, ignored_conntrack);
+	read_unlock_bh(&nf_conntrack_lock);
+
+	return h != NULL;
+}
+
+/* There's a small race here where we may free a just-assured
+   connection.  Too bad: we're in trouble anyway. */
+static inline int unreplied(const struct nf_conntrack_tuple_hash *i)
+{
+	return !(test_bit(IPS_ASSURED_BIT,
+			  &nf_ct_tuplehash_to_ctrack(i)->status));
+}
+
+static int early_drop(struct list_head *chain)
+{
+	/* Traverse backwards: gives us oldest, which is roughly LRU */
+	struct nf_conntrack_tuple_hash *h;
+	struct nf_conn *ct = NULL;
+	int dropped = 0;
+
+	read_lock_bh(&nf_conntrack_lock);
+	h = LIST_FIND_B(chain, unreplied, struct nf_conntrack_tuple_hash *);
+	if (h) {
+		ct = nf_ct_tuplehash_to_ctrack(h);
+		atomic_inc(&ct->ct_general.use);
+	}
+	read_unlock_bh(&nf_conntrack_lock);
+
+	if (!ct)
+		return dropped;
+
+	if (del_timer(&ct->timeout)) {
+		death_by_timeout((unsigned long)ct);
+		dropped = 1;
+		NF_CT_STAT_INC(early_drop);
+	}
+	nf_ct_put(ct);
+	return dropped;
+}
+
+static inline int helper_cmp(const struct nf_conntrack_helper *i,
+			     const struct nf_conntrack_tuple *rtuple)
+{
+	return nf_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
+}
+
+static struct nf_conntrack_helper *
+nf_ct_find_helper(const struct nf_conntrack_tuple *tuple)
+{
+	return LIST_FIND(&helpers, helper_cmp,
+			 struct nf_conntrack_helper *,
+			 tuple);
+}
+
+static struct nf_conn *
+__nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+		     const struct nf_conntrack_tuple *repl,
+		     const struct nf_conntrack_l3proto *l3proto)
+{
+	struct nf_conn *conntrack = NULL;
+	u_int32_t features = 0;
+
+	if (!nf_conntrack_hash_rnd_initted) {
+		get_random_bytes(&nf_conntrack_hash_rnd, 4);
+		nf_conntrack_hash_rnd_initted = 1;
+	}
+
+	if (nf_conntrack_max
+	    && atomic_read(&nf_conntrack_count) >= nf_conntrack_max) {
+		unsigned int hash = hash_conntrack(orig);
+		/* Try dropping from this hash chain. */
+		if (!early_drop(&nf_conntrack_hash[hash])) {
+			if (net_ratelimit())
+				printk(KERN_WARNING
+				       "nf_conntrack: table full, dropping"
+				       " packet.\n");
+			return ERR_PTR(-ENOMEM);
+		}
+	}
+
+	/*  find features needed by this conntrack. */
+	features = l3proto->get_features(orig);
+	read_lock_bh(&nf_conntrack_lock);
+	if (nf_ct_find_helper(repl) != NULL)
+		features |= NF_CT_F_HELP;
+	read_unlock_bh(&nf_conntrack_lock);
+
+	DEBUGP("nf_conntrack_alloc: features=0x%x\n", features);
+
+	read_lock_bh(&nf_ct_cache_lock);
+
+	if (!nf_ct_cache[features].use) {
+		DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n",
+			features);
+		goto out;
+	}
+
+	conntrack = kmem_cache_alloc(nf_ct_cache[features].cachep, GFP_ATOMIC);
+	if (conntrack == NULL) {
+		DEBUGP("nf_conntrack_alloc: Can't alloc conntrack from cache\n");
+		goto out;
+	}
+
+	memset(conntrack, 0, nf_ct_cache[features].size);
+	conntrack->features = features;
+	if (nf_ct_cache[features].init_conntrack &&
+	    nf_ct_cache[features].init_conntrack(conntrack, features) < 0) {
+		DEBUGP("nf_conntrack_alloc: failed to init\n");
+		kmem_cache_free(nf_ct_cache[features].cachep, conntrack);
+		conntrack = NULL;
+		goto out;
+	}
+
+	atomic_set(&conntrack->ct_general.use, 1);
+	conntrack->ct_general.destroy = destroy_conntrack;
+	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
+	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
+	/* Don't set timer yet: wait for confirmation */
+	init_timer(&conntrack->timeout);
+	conntrack->timeout.data = (unsigned long)conntrack;
+	conntrack->timeout.function = death_by_timeout;
+
+	atomic_inc(&nf_conntrack_count);
+out:
+	read_unlock_bh(&nf_ct_cache_lock);
+	return conntrack;
+}
+
+struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+				   const struct nf_conntrack_tuple *repl)
+{
+	struct nf_conntrack_l3proto *l3proto;
+
+	l3proto = nf_ct_find_l3proto(orig->src.l3num);
+	return __nf_conntrack_alloc(orig, repl, l3proto);
+}
+
+void nf_conntrack_free(struct nf_conn *conntrack)
+{
+	u_int32_t features = conntrack->features;
+	NF_CT_ASSERT(features >= NF_CT_F_BASIC && features < NF_CT_F_NUM);
+	DEBUGP("nf_conntrack_free: features = 0x%x, conntrack=%p\n", features,
+	       conntrack);
+	kmem_cache_free(nf_ct_cache[features].cachep, conntrack);
+	atomic_dec(&nf_conntrack_count);
+}
+
+/* Allocate a new conntrack: we return -ENOMEM if classification
+   failed due to stress.  Otherwise it really is unclassifiable. */
+static struct nf_conntrack_tuple_hash *
+init_conntrack(const struct nf_conntrack_tuple *tuple,
+	       struct nf_conntrack_l3proto *l3proto,
+	       struct nf_conntrack_protocol *protocol,
+	       struct sk_buff *skb,
+	       unsigned int dataoff)
+{
+	struct nf_conn *conntrack;
+	struct nf_conntrack_tuple repl_tuple;
+	struct nf_conntrack_expect *exp;
+
+	if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, protocol)) {
+		DEBUGP("Can't invert tuple.\n");
+		return NULL;
+	}
+
+	conntrack = __nf_conntrack_alloc(tuple, &repl_tuple, l3proto);
+	if (conntrack == NULL || IS_ERR(conntrack)) {
+		DEBUGP("Can't allocate conntrack.\n");
+		return (struct nf_conntrack_tuple_hash *)conntrack;
+	}
+
+	if (!protocol->new(conntrack, skb, dataoff)) {
+		nf_conntrack_free(conntrack);
+		DEBUGP("init conntrack: can't track with proto module\n");
+		return NULL;
+	}
+
+	write_lock_bh(&nf_conntrack_lock);
+	exp = find_expectation(tuple);
+
+	if (exp) {
+		DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
+			conntrack, exp);
+		/* Welcome, Mr. Bond.  We've been expecting you... */
+		__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
+		conntrack->master = exp->master;
+#ifdef CONFIG_NF_CONNTRACK_MARK
+		conntrack->mark = exp->master->mark;
+#endif
+		nf_conntrack_get(&conntrack->master->ct_general);
+		NF_CT_STAT_INC(expect_new);
+	} else {
+		conntrack->helper = nf_ct_find_helper(&repl_tuple);
+
+		NF_CT_STAT_INC(new);
+        }
+
+	/* Overload tuple linked list to put us in unconfirmed list. */
+	list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed);
+
+	write_unlock_bh(&nf_conntrack_lock);
+
+	if (exp) {
+		if (exp->expectfn)
+			exp->expectfn(conntrack, exp);
+		nf_conntrack_expect_put(exp);
+	}
+
+	return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
+}
+
+/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
+static inline struct nf_conn *
+resolve_normal_ct(struct sk_buff *skb,
+		  unsigned int dataoff,
+		  u_int16_t l3num,
+		  u_int8_t protonum,
+		  struct nf_conntrack_l3proto *l3proto,
+		  struct nf_conntrack_protocol *proto,
+		  int *set_reply,
+		  enum ip_conntrack_info *ctinfo)
+{
+	struct nf_conntrack_tuple tuple;
+	struct nf_conntrack_tuple_hash *h;
+	struct nf_conn *ct;
+
+	if (!nf_ct_get_tuple(skb, (unsigned int)(skb->nh.raw - skb->data),
+			     dataoff, l3num, protonum, &tuple, l3proto,
+			     proto)) {
+		DEBUGP("resolve_normal_ct: Can't get tuple\n");
+		return NULL;
+	}
+
+	/* look for tuple match */
+	h = nf_conntrack_find_get(&tuple, NULL);
+	if (!h) {
+		h = init_conntrack(&tuple, l3proto, proto, skb, dataoff);
+		if (!h)
+			return NULL;
+		if (IS_ERR(h))
+			return (void *)h;
+	}
+	ct = nf_ct_tuplehash_to_ctrack(h);
+
+	/* It exists; we have (non-exclusive) reference. */
+	if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) {
+		*ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
+		/* Please set reply bit if this packet OK */
+		*set_reply = 1;
+	} else {
+		/* Once we've had two way comms, always ESTABLISHED. */
+		if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+			DEBUGP("nf_conntrack_in: normal packet for %p\n", ct);
+			*ctinfo = IP_CT_ESTABLISHED;
+		} else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
+			DEBUGP("nf_conntrack_in: related packet for %p\n", ct);
+			*ctinfo = IP_CT_RELATED;
+		} else {
+			DEBUGP("nf_conntrack_in: new packet for %p\n", ct);
+			*ctinfo = IP_CT_NEW;
+		}
+		*set_reply = 0;
+	}
+	skb->nfct = &ct->ct_general;
+	skb->nfctinfo = *ctinfo;
+	return ct;
+}
+
+unsigned int
+nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
+{
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+	struct nf_conntrack_l3proto *l3proto;
+	struct nf_conntrack_protocol *proto;
+	unsigned int dataoff;
+	u_int8_t protonum;
+	int set_reply = 0;
+	int ret;
+
+	/* Previously seen (loopback or untracked)?  Ignore. */
+	if ((*pskb)->nfct) {
+		NF_CT_STAT_INC(ignore);
+		return NF_ACCEPT;
+	}
+
+	l3proto = nf_ct_find_l3proto((u_int16_t)pf);
+	if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) {
+		DEBUGP("not prepared to track yet or error occured\n");
+		return -ret;
+	}
+
+	proto = nf_ct_find_proto((u_int16_t)pf, protonum);
+
+	/* It may be an special packet, error, unclean...
+	 * inverse of the return code tells to the netfilter
+	 * core what to do with the packet. */
+	if (proto->error != NULL &&
+	    (ret = proto->error(*pskb, dataoff, &ctinfo, pf, hooknum)) <= 0) {
+		NF_CT_STAT_INC(error);
+		NF_CT_STAT_INC(invalid);
+		return -ret;
+	}
+
+	ct = resolve_normal_ct(*pskb, dataoff, pf, protonum, l3proto, proto,
+			       &set_reply, &ctinfo);
+	if (!ct) {
+		/* Not valid part of a connection */
+		NF_CT_STAT_INC(invalid);
+		return NF_ACCEPT;
+	}
+
+	if (IS_ERR(ct)) {
+		/* Too stressed to deal. */
+		NF_CT_STAT_INC(drop);
+		return NF_DROP;
+	}
+
+	NF_CT_ASSERT((*pskb)->nfct);
+
+	ret = proto->packet(ct, *pskb, dataoff, ctinfo, pf, hooknum);
+	if (ret < 0) {
+		/* Invalid: inverse of the return code tells
+		 * the netfilter core what to do */
+		DEBUGP("nf_conntrack_in: Can't track with proto module\n");
+		nf_conntrack_put((*pskb)->nfct);
+		(*pskb)->nfct = NULL;
+		NF_CT_STAT_INC(invalid);
+		return -ret;
+	}
+
+	if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
+		nf_conntrack_event_cache(IPCT_STATUS, *pskb);
+
+	return ret;
+}
+
+int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
+			 const struct nf_conntrack_tuple *orig)
+{
+	return nf_ct_invert_tuple(inverse, orig,
+				  nf_ct_find_l3proto(orig->src.l3num),
+				  nf_ct_find_proto(orig->src.l3num,
+						   orig->dst.protonum));
+}
+
+/* Would two expected things clash? */
+static inline int expect_clash(const struct nf_conntrack_expect *a,
+			       const struct nf_conntrack_expect *b)
+{
+	/* Part covered by intersection of masks must be unequal,
+	   otherwise they clash */
+	struct nf_conntrack_tuple intersect_mask;
+	int count;
+
+	intersect_mask.src.l3num = a->mask.src.l3num & b->mask.src.l3num;
+	intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all;
+	intersect_mask.dst.u.all = a->mask.dst.u.all & b->mask.dst.u.all;
+	intersect_mask.dst.protonum = a->mask.dst.protonum
+					& b->mask.dst.protonum;
+
+	for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
+		intersect_mask.src.u3.all[count] =
+			a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
+	}
+
+	for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
+		intersect_mask.dst.u3.all[count] =
+			a->mask.dst.u3.all[count] & b->mask.dst.u3.all[count];
+	}
+
+	return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
+}
+
+static inline int expect_matches(const struct nf_conntrack_expect *a,
+				 const struct nf_conntrack_expect *b)
+{
+	return a->master == b->master
+		&& nf_ct_tuple_equal(&a->tuple, &b->tuple)
+		&& nf_ct_tuple_equal(&a->mask, &b->mask);
+}
+
+/* Generally a bad idea to call this: could have matched already. */
+void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp)
+{
+	struct nf_conntrack_expect *i;
+
+	write_lock_bh(&nf_conntrack_lock);
+	/* choose the the oldest expectation to evict */
+	list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
+		if (expect_matches(i, exp) && del_timer(&i->timeout)) {
+			nf_ct_unlink_expect(i);
+			write_unlock_bh(&nf_conntrack_lock);
+			nf_conntrack_expect_put(i);
+			return;
+		}
+	}
+	write_unlock_bh(&nf_conntrack_lock);
+}
+
+/* We don't increase the master conntrack refcount for non-fulfilled
+ * conntracks. During the conntrack destruction, the expectations are
+ * always killed before the conntrack itself */
+struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me)
+{
+	struct nf_conntrack_expect *new;
+
+	new = kmem_cache_alloc(nf_conntrack_expect_cachep, GFP_ATOMIC);
+	if (!new) {
+		DEBUGP("expect_related: OOM allocating expect\n");
+		return NULL;
+	}
+	new->master = me;
+	atomic_set(&new->use, 1);
+	return new;
+}
+
+void nf_conntrack_expect_put(struct nf_conntrack_expect *exp)
+{
+	if (atomic_dec_and_test(&exp->use))
+		kmem_cache_free(nf_conntrack_expect_cachep, exp);
+}
+
+static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp)
+{
+	atomic_inc(&exp->use);
+	exp->master->expecting++;
+	list_add(&exp->list, &nf_conntrack_expect_list);
+
+	init_timer(&exp->timeout);
+	exp->timeout.data = (unsigned long)exp;
+	exp->timeout.function = expectation_timed_out;
+	exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ;
+	add_timer(&exp->timeout);
+
+	atomic_inc(&exp->use);
+	NF_CT_STAT_INC(expect_create);
+}
+
+/* Race with expectations being used means we could have none to find; OK. */
+static void evict_oldest_expect(struct nf_conn *master)
+{
+	struct nf_conntrack_expect *i;
+
+	list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
+		if (i->master == master) {
+			if (del_timer(&i->timeout)) {
+				nf_ct_unlink_expect(i);
+				nf_conntrack_expect_put(i);
+			}
+			break;
+		}
+	}
+}
+
+static inline int refresh_timer(struct nf_conntrack_expect *i)
+{
+	if (!del_timer(&i->timeout))
+		return 0;
+
+	i->timeout.expires = jiffies + i->master->helper->timeout*HZ;
+	add_timer(&i->timeout);
+	return 1;
+}
+
+int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
+{
+	struct nf_conntrack_expect *i;
+	int ret;
+
+	DEBUGP("nf_conntrack_expect_related %p\n", related_to);
+	DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple);
+	DEBUGP("mask:  "); NF_CT_DUMP_TUPLE(&expect->mask);
+
+	write_lock_bh(&nf_conntrack_lock);
+	list_for_each_entry(i, &nf_conntrack_expect_list, list) {
+		if (expect_matches(i, expect)) {
+			/* Refresh timer: if it's dying, ignore.. */
+			if (refresh_timer(i)) {
+				ret = 0;
+				goto out;
+			}
+		} else if (expect_clash(i, expect)) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+	/* Will be over limit? */
+	if (expect->master->helper->max_expected && 
+	    expect->master->expecting >= expect->master->helper->max_expected)
+		evict_oldest_expect(expect->master);
+
+	nf_conntrack_expect_insert(expect);
+	nf_conntrack_expect_event(IPEXP_NEW, expect);
+	ret = 0;
+out:
+	write_unlock_bh(&nf_conntrack_lock);
+	return ret;
+}
+
+/* Alter reply tuple (maybe alter helper).  This is for NAT, and is
+   implicitly racy: see __nf_conntrack_confirm */
+void nf_conntrack_alter_reply(struct nf_conn *conntrack,
+			      const struct nf_conntrack_tuple *newreply)
+{
+	write_lock_bh(&nf_conntrack_lock);
+	/* Should be unconfirmed, so not in hash table yet */
+	NF_CT_ASSERT(!nf_ct_is_confirmed(conntrack));
+
+	DEBUGP("Altering reply tuple of %p to ", conntrack);
+	NF_CT_DUMP_TUPLE(newreply);
+
+	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
+	if (!conntrack->master && conntrack->expecting == 0)
+		conntrack->helper = nf_ct_find_helper(newreply);
+	write_unlock_bh(&nf_conntrack_lock);
+}
+
+int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
+{
+	int ret;
+	BUG_ON(me->timeout == 0);
+
+	ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help",
+					  sizeof(struct nf_conn)
+					  + sizeof(union nf_conntrack_help)
+					  + __alignof__(union nf_conntrack_help),
+					  init_conntrack_for_helper);
+	if (ret < 0) {
+		printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n");
+		return ret;
+	}
+	write_lock_bh(&nf_conntrack_lock);
+	list_prepend(&helpers, me);
+	write_unlock_bh(&nf_conntrack_lock);
+
+	return 0;
+}
+
+static inline int unhelp(struct nf_conntrack_tuple_hash *i,
+			 const struct nf_conntrack_helper *me)
+{
+	if (nf_ct_tuplehash_to_ctrack(i)->helper == me) {
+		nf_conntrack_event(IPCT_HELPER, nf_ct_tuplehash_to_ctrack(i));
+		nf_ct_tuplehash_to_ctrack(i)->helper = NULL;
+	}
+	return 0;
+}
+
+void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+{
+	unsigned int i;
+	struct nf_conntrack_expect *exp, *tmp;
+
+	/* Need write lock here, to delete helper. */
+	write_lock_bh(&nf_conntrack_lock);
+	LIST_DELETE(&helpers, me);
+
+	/* Get rid of expectations */
+	list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) {
+		if (exp->master->helper == me && del_timer(&exp->timeout)) {
+			nf_ct_unlink_expect(exp);
+			nf_conntrack_expect_put(exp);
+		}
+	}
+
+	/* Get rid of expecteds, set helpers to NULL. */
+	LIST_FIND_W(&unconfirmed, unhelp, struct nf_conntrack_tuple_hash*, me);
+	for (i = 0; i < nf_conntrack_htable_size; i++)
+		LIST_FIND_W(&nf_conntrack_hash[i], unhelp,
+			    struct nf_conntrack_tuple_hash *, me);
+	write_unlock_bh(&nf_conntrack_lock);
+
+	/* Someone could be still looking at the helper in a bh. */
+	synchronize_net();
+}
+
+/* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */
+void __nf_ct_refresh_acct(struct nf_conn *ct,
+			  enum ip_conntrack_info ctinfo,
+			  const struct sk_buff *skb,
+			  unsigned long extra_jiffies,
+			  int do_acct)
+{
+	int event = 0;
+
+	NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
+	NF_CT_ASSERT(skb);
+
+	write_lock_bh(&nf_conntrack_lock);
+
+	/* If not in hash table, timer will not be active yet */
+	if (!nf_ct_is_confirmed(ct)) {
+		ct->timeout.expires = extra_jiffies;
+		event = IPCT_REFRESH;
+	} else {
+		/* Need del_timer for race avoidance (may already be dying). */
+		if (del_timer(&ct->timeout)) {
+			ct->timeout.expires = jiffies + extra_jiffies;
+			add_timer(&ct->timeout);
+			event = IPCT_REFRESH;
+		}
+	}
+
+#ifdef CONFIG_NF_CT_ACCT
+	if (do_acct) {
+		ct->counters[CTINFO2DIR(ctinfo)].packets++;
+		ct->counters[CTINFO2DIR(ctinfo)].bytes +=
+			skb->len - (unsigned int)(skb->nh.raw - skb->data);
+	if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x80000000)
+	    || (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x80000000))
+		event |= IPCT_COUNTER_FILLING;
+	}
+#endif
+
+	write_unlock_bh(&nf_conntrack_lock);
+
+	/* must be unlocked when calling event cache */
+	if (event)
+		nf_conntrack_event_cache(event, skb);
+}
+
+/* Used by ipt_REJECT and ip6t_REJECT. */
+void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
+{
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+
+	/* This ICMP is in reverse direction to the packet which caused it */
+	ct = nf_ct_get(skb, &ctinfo);
+	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
+		ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
+	else
+		ctinfo = IP_CT_RELATED;
+
+	/* Attach to new skbuff, and increment count */
+	nskb->nfct = &ct->ct_general;
+	nskb->nfctinfo = ctinfo;
+	nf_conntrack_get(nskb->nfct);
+}
+
+static inline int
+do_iter(const struct nf_conntrack_tuple_hash *i,
+	int (*iter)(struct nf_conn *i, void *data),
+	void *data)
+{
+	return iter(nf_ct_tuplehash_to_ctrack(i), data);
+}
+
+/* Bring out ya dead! */
+static struct nf_conntrack_tuple_hash *
+get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
+		void *data, unsigned int *bucket)
+{
+	struct nf_conntrack_tuple_hash *h = NULL;
+
+	write_lock_bh(&nf_conntrack_lock);
+	for (; *bucket < nf_conntrack_htable_size; (*bucket)++) {
+		h = LIST_FIND_W(&nf_conntrack_hash[*bucket], do_iter,
+				struct nf_conntrack_tuple_hash *, iter, data);
+		if (h)
+			break;
+ 	}
+	if (!h)
+		h = LIST_FIND_W(&unconfirmed, do_iter,
+				struct nf_conntrack_tuple_hash *, iter, data);
+	if (h)
+		atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use);
+	write_unlock_bh(&nf_conntrack_lock);
+
+	return h;
+}
+
+void
+nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data)
+{
+	struct nf_conntrack_tuple_hash *h;
+	unsigned int bucket = 0;
+
+	while ((h = get_next_corpse(iter, data, &bucket)) != NULL) {
+		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
+		/* Time to push up daises... */
+		if (del_timer(&ct->timeout))
+			death_by_timeout((unsigned long)ct);
+		/* ... else the timer will get him soon. */
+
+		nf_ct_put(ct);
+	}
+}
+
+static int kill_all(struct nf_conn *i, void *data)
+{
+	return 1;
+}
+
+static void free_conntrack_hash(struct list_head *hash, int vmalloced, int size)
+{
+	if (vmalloced)
+		vfree(hash);
+	else
+		free_pages((unsigned long)hash, 
+			   get_order(sizeof(struct list_head) * size));
+}
+
+/* Mishearing the voices in his head, our hero wonders how he's
+   supposed to kill the mall. */
+void nf_conntrack_cleanup(void)
+{
+	int i;
+
+	/* This makes sure all current packets have passed through
+	   netfilter framework.  Roll on, two-stage module
+	   delete... */
+	synchronize_net();
+
+	nf_ct_event_cache_flush();
+ i_see_dead_people:
+	nf_ct_iterate_cleanup(kill_all, NULL);
+	if (atomic_read(&nf_conntrack_count) != 0) {
+		schedule();
+		goto i_see_dead_people;
+	}
+
+	for (i = 0; i < NF_CT_F_NUM; i++) {
+		if (nf_ct_cache[i].use == 0)
+			continue;
+
+		NF_CT_ASSERT(nf_ct_cache[i].use == 1);
+		nf_ct_cache[i].use = 1;
+		nf_conntrack_unregister_cache(i);
+	}
+	kmem_cache_destroy(nf_conntrack_expect_cachep);
+	free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc,
+			    nf_conntrack_htable_size);
+}
+
+static struct list_head *alloc_hashtable(int size, int *vmalloced)
+{
+	struct list_head *hash;
+	unsigned int i;
+
+	*vmalloced = 0; 
+	hash = (void*)__get_free_pages(GFP_KERNEL, 
+				       get_order(sizeof(struct list_head)
+						 * size));
+	if (!hash) { 
+		*vmalloced = 1;
+		printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
+		hash = vmalloc(sizeof(struct list_head) * size);
+	}
+
+	if (hash)
+		for (i = 0; i < size; i++) 
+			INIT_LIST_HEAD(&hash[i]);
+
+	return hash;
+}
+
+int set_hashsize(const char *val, struct kernel_param *kp)
+{
+	int i, bucket, hashsize, vmalloced;
+	int old_vmalloced, old_size;
+	int rnd;
+	struct list_head *hash, *old_hash;
+	struct nf_conntrack_tuple_hash *h;
+
+	/* On boot, we can set this without any fancy locking. */
+	if (!nf_conntrack_htable_size)
+		return param_set_uint(val, kp);
+
+	hashsize = simple_strtol(val, NULL, 0);
+	if (!hashsize)
+		return -EINVAL;
+
+	hash = alloc_hashtable(hashsize, &vmalloced);
+	if (!hash)
+		return -ENOMEM;
+
+	/* We have to rehahs for the new table anyway, so we also can
+	 * use a newrandom seed */
+	get_random_bytes(&rnd, 4);
+
+	write_lock_bh(&nf_conntrack_lock);
+	for (i = 0; i < nf_conntrack_htable_size; i++) {
+		while (!list_empty(&nf_conntrack_hash[i])) {
+			h = list_entry(nf_conntrack_hash[i].next,
+				       struct nf_conntrack_tuple_hash, list);
+			list_del(&h->list);
+			bucket = __hash_conntrack(&h->tuple, hashsize, rnd);
+			list_add_tail(&h->list, &hash[bucket]);
+		}
+	}
+	old_size = nf_conntrack_htable_size;
+	old_vmalloced = nf_conntrack_vmalloc;
+	old_hash = nf_conntrack_hash;
+
+	nf_conntrack_htable_size = hashsize;
+	nf_conntrack_vmalloc = vmalloced;
+	nf_conntrack_hash = hash;
+	nf_conntrack_hash_rnd = rnd;
+	write_unlock_bh(&nf_conntrack_lock);
+
+	free_conntrack_hash(old_hash, old_vmalloced, old_size);
+	return 0;
+}
+
+module_param_call(hashsize, set_hashsize, param_get_uint,
+		  &nf_conntrack_htable_size, 0600);
+
+int __init nf_conntrack_init(void)
+{
+	unsigned int i;
+	int ret;
+
+	/* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
+	 * machine has 256 buckets.  >= 1GB machines have 8192 buckets. */
+	if (!nf_conntrack_htable_size) {
+		nf_conntrack_htable_size
+			= (((num_physpages << PAGE_SHIFT) / 16384)
+			   / sizeof(struct list_head));
+		if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
+			nf_conntrack_htable_size = 8192;
+		if (nf_conntrack_htable_size < 16)
+			nf_conntrack_htable_size = 16;
+	}
+	nf_conntrack_max = 8 * nf_conntrack_htable_size;
+
+	printk("nf_conntrack version %s (%u buckets, %d max)\n",
+	       NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
+	       nf_conntrack_max);
+
+	nf_conntrack_hash = alloc_hashtable(nf_conntrack_htable_size,
+					    &nf_conntrack_vmalloc);
+	if (!nf_conntrack_hash) {
+		printk(KERN_ERR "Unable to create nf_conntrack_hash\n");
+		goto err_out;
+	}
+
+	ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic",
+					  sizeof(struct nf_conn), NULL);
+	if (ret < 0) {
+		printk(KERN_ERR "Unable to create nf_conn slab cache\n");
+		goto err_free_hash;
+	}
+
+	nf_conntrack_expect_cachep = kmem_cache_create("nf_conntrack_expect",
+					sizeof(struct nf_conntrack_expect),
+					0, 0, NULL, NULL);
+	if (!nf_conntrack_expect_cachep) {
+		printk(KERN_ERR "Unable to create nf_expect slab cache\n");
+		goto err_free_conntrack_slab;
+	}
+
+	/* Don't NEED lock here, but good form anyway. */
+	write_lock_bh(&nf_conntrack_lock);
+        for (i = 0; i < PF_MAX; i++)
+		nf_ct_l3protos[i] = &nf_conntrack_generic_l3proto;
+        write_unlock_bh(&nf_conntrack_lock);
+
+	/* Set up fake conntrack:
+	    - to never be deleted, not in any hashes */
+	atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
+	/*  - and look it like as a confirmed connection */
+	set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);
+
+	return ret;
+
+err_free_conntrack_slab:
+	nf_conntrack_unregister_cache(NF_CT_F_BASIC);
+err_free_hash:
+	free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc,
+			    nf_conntrack_htable_size);
+err_out:
+	return -ENOMEM;
+}
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
new file mode 100644
index 0000000..65080e2
--- /dev/null
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -0,0 +1,698 @@
+/* FTP extension for connection tracking. */
+
+/* (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>
+ *
+ * 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.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- enable working with Layer 3 protocol independent connection tracking.
+ *	- track EPRT and EPSV commands with IPv6 address.
+ *
+ * Derived from net/ipv4/netfilter/ip_conntrack_ftp.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/ctype.h>
+#include <net/checksum.h>
+#include <net/tcp.h>
+
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <linux/netfilter/nf_conntrack_ftp.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
+MODULE_DESCRIPTION("ftp connection tracking helper");
+
+/* This is slow, but it's simple. --RR */
+static char *ftp_buffer;
+
+static DEFINE_SPINLOCK(nf_ftp_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);
+
+static int loose;
+module_param(loose, int, 0600);
+
+unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb,
+				enum ip_conntrack_info ctinfo,
+				enum ip_ct_ftp_type type,
+				unsigned int matchoff,
+				unsigned int matchlen,
+				struct nf_conntrack_expect *exp,
+				u32 *seq);
+EXPORT_SYMBOL_GPL(nf_nat_ftp_hook);
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static int try_rfc959(const char *, size_t, struct nf_conntrack_man *, char);
+static int try_eprt(const char *, size_t, struct nf_conntrack_man *, char);
+static int try_epsv_response(const char *, size_t, struct nf_conntrack_man *,
+			     char);
+
+static struct ftp_search {
+	enum ip_conntrack_dir dir;
+	const char *pattern;
+	size_t plen;
+	char skip;
+	char term;
+	enum ip_ct_ftp_type ftptype;
+	int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char);
+} search[] = {
+	{
+		IP_CT_DIR_ORIGINAL,
+		"PORT", sizeof("PORT") - 1, ' ', '\r',
+		IP_CT_FTP_PORT,
+		try_rfc959,
+	},
+	{
+		IP_CT_DIR_REPLY,
+		"227 ", sizeof("227 ") - 1, '(', ')',
+		IP_CT_FTP_PASV,
+		try_rfc959,
+	},
+	{
+		IP_CT_DIR_ORIGINAL,
+		"EPRT", sizeof("EPRT") - 1, ' ', '\r',
+		IP_CT_FTP_EPRT,
+		try_eprt,
+	},
+	{
+		IP_CT_DIR_REPLY,
+		"229 ", sizeof("229 ") - 1, '(', ')',
+		IP_CT_FTP_EPSV,
+		try_epsv_response,
+	},
+};
+
+/* This code is based on inet_pton() in glibc-2.2.4 */
+static int
+get_ipv6_addr(const char *src, size_t dlen, struct in6_addr *dst, u_int8_t term)
+{
+	static const char xdigits[] = "0123456789abcdef";
+	u_int8_t tmp[16], *tp, *endp, *colonp;
+	int ch, saw_xdigit;
+	u_int32_t val;
+	size_t clen = 0;
+
+	tp = memset(tmp, '\0', sizeof(tmp));
+	endp = tp + sizeof(tmp);
+	colonp = NULL;
+
+	/* Leading :: requires some special handling. */
+	if (*src == ':'){
+		if (*++src != ':') {
+			DEBUGP("invalid \":\" at the head of addr\n");
+			return 0;
+		}
+		clen++;
+	}
+
+	saw_xdigit = 0;
+	val = 0;
+	while ((clen < dlen) && (*src != term)) {
+		const char *pch;
+
+		ch = tolower(*src++);
+		clen++;
+
+                pch = strchr(xdigits, ch);
+                if (pch != NULL) {
+                        val <<= 4;
+                        val |= (pch - xdigits);
+                        if (val > 0xffff)
+                                return 0;
+
+			saw_xdigit = 1;
+                        continue;
+                }
+		if (ch != ':') {
+			DEBUGP("get_ipv6_addr: invalid char. \'%c\'\n", ch);
+			return 0;
+		}
+
+		if (!saw_xdigit) {
+			if (colonp) {
+				DEBUGP("invalid location of \"::\".\n");
+				return 0;
+			}
+			colonp = tp;
+			continue;
+		} else if (*src == term) {
+			DEBUGP("trancated IPv6 addr\n");
+			return 0;
+		}
+
+		if (tp + 2 > endp)
+			return 0;
+		*tp++ = (u_int8_t) (val >> 8) & 0xff;
+		*tp++ = (u_int8_t) val & 0xff;
+
+		saw_xdigit = 0;
+		val = 0;
+		continue;
+        }
+        if (saw_xdigit) {
+                if (tp + 2 > endp)
+                        return 0;
+                *tp++ = (u_int8_t) (val >> 8) & 0xff;
+                *tp++ = (u_int8_t) val & 0xff;
+        }
+        if (colonp != NULL) {
+                /*
+                 * Since some memmove()'s erroneously fail to handle
+                 * overlapping regions, we'll do the shift by hand.
+                 */
+                const int n = tp - colonp;
+                int i;
+
+                if (tp == endp)
+                        return 0;
+
+                for (i = 1; i <= n; i++) {
+                        endp[- i] = colonp[n - i];
+                        colonp[n - i] = 0;
+                }
+                tp = endp;
+        }
+        if (tp != endp || (*src != term))
+                return 0;
+
+        memcpy(dst->s6_addr, tmp, sizeof(dst->s6_addr));
+        return clen;
+}
+
+static int try_number(const char *data, size_t dlen, u_int32_t array[],
+                      int array_size, char sep, char term)
+{
+	u_int32_t i, len;
+
+	memset(array, 0, sizeof(array[0])*array_size);
+
+	/* Keep data pointing at next char. */
+	for (i = 0, len = 0; len < dlen && i < array_size; len++, data++) {
+		if (*data >= '0' && *data <= '9') {
+			array[i] = array[i]*10 + *data - '0';
+		}
+		else if (*data == sep)
+			i++;
+		else {
+			/* Unexpected character; true if it's the
+			   terminator and we're finished. */
+			if (*data == term && i == array_size - 1)
+				return len;
+
+			DEBUGP("Char %u (got %u nums) `%u' unexpected\n",
+			       len, i, *data);
+			return 0;
+		}
+	}
+	DEBUGP("Failed to fill %u numbers separated by %c\n", array_size, sep);
+
+	return 0;
+}
+
+/* Returns 0, or length of numbers: 192,168,1,1,5,6 */
+static int try_rfc959(const char *data, size_t dlen,
+		      struct nf_conntrack_man *cmd, char term)
+{
+	int length;
+	u_int32_t array[6];
+
+	length = try_number(data, dlen, array, 6, ',', term);
+	if (length == 0)
+		return 0;
+
+	cmd->u3.ip =  htonl((array[0] << 24) | (array[1] << 16) |
+				    (array[2] << 8) | array[3]);
+	cmd->u.tcp.port = htons((array[4] << 8) | array[5]);
+	return length;
+}
+
+/* Grab port: number up to delimiter */
+static int get_port(const char *data, int start, size_t dlen, char delim,
+		    u_int16_t *port)
+{
+	u_int16_t tmp_port = 0;
+	int i;
+
+	for (i = start; i < dlen; i++) {
+		/* Finished? */
+		if (data[i] == delim) {
+			if (tmp_port == 0)
+				break;
+			*port = htons(tmp_port);
+			DEBUGP("get_port: return %d\n", tmp_port);
+			return i + 1;
+		}
+		else if (data[i] >= '0' && data[i] <= '9')
+			tmp_port = tmp_port*10 + data[i] - '0';
+		else { /* Some other crap */
+			DEBUGP("get_port: invalid char.\n");
+			break;
+		}
+	}
+	return 0;
+}
+
+/* Returns 0, or length of numbers: |1|132.235.1.2|6275| or |2|3ffe::1|6275| */
+static int try_eprt(const char *data, size_t dlen, struct nf_conntrack_man *cmd,
+		    char term)
+{
+	char delim;
+	int length;
+
+	/* First character is delimiter, then "1" for IPv4 or "2" for IPv6,
+	   then delimiter again. */
+	if (dlen <= 3) {
+		DEBUGP("EPRT: too short\n");
+		return 0;
+	}
+	delim = data[0];
+	if (isdigit(delim) || delim < 33 || delim > 126 || data[2] != delim) {
+		DEBUGP("try_eprt: invalid delimitter.\n");
+		return 0;
+	}
+
+	if ((cmd->l3num == PF_INET && data[1] != '1') ||
+	    (cmd->l3num == PF_INET6 && data[1] != '2')) {
+		DEBUGP("EPRT: invalid protocol number.\n");
+		return 0;
+	}
+
+	DEBUGP("EPRT: Got %c%c%c\n", delim, data[1], delim);
+
+	if (data[1] == '1') {
+		u_int32_t array[4];
+
+		/* Now we have IP address. */
+		length = try_number(data + 3, dlen - 3, array, 4, '.', delim);
+		if (length != 0)
+			cmd->u3.ip = htonl((array[0] << 24) | (array[1] << 16)
+					   | (array[2] << 8) | array[3]);
+	} else {
+		/* Now we have IPv6 address. */
+		length = get_ipv6_addr(data + 3, dlen - 3,
+				       (struct in6_addr *)cmd->u3.ip6, delim);
+	}
+
+	if (length == 0)
+		return 0;
+	DEBUGP("EPRT: Got IP address!\n");
+	/* Start offset includes initial "|1|", and trailing delimiter */
+	return get_port(data, 3 + length + 1, dlen, delim, &cmd->u.tcp.port);
+}
+
+/* Returns 0, or length of numbers: |||6446| */
+static int try_epsv_response(const char *data, size_t dlen,
+			     struct nf_conntrack_man *cmd, char term)
+{
+	char delim;
+
+	/* Three delimiters. */
+	if (dlen <= 3) return 0;
+	delim = data[0];
+	if (isdigit(delim) || delim < 33 || delim > 126
+	    || data[1] != delim || data[2] != delim)
+		return 0;
+
+	return get_port(data, 3, dlen, delim, &cmd->u.tcp.port);
+}
+
+/* Return 1 for match, 0 for accept, -1 for partial. */
+static int find_pattern(const char *data, size_t dlen,
+			const char *pattern, size_t plen,
+			char skip, char term,
+			unsigned int *numoff,
+			unsigned int *numlen,
+			struct nf_conntrack_man *cmd,
+			int (*getnum)(const char *, size_t,
+				      struct nf_conntrack_man *, char))
+{
+	size_t i;
+
+	DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
+	if (dlen == 0)
+		return 0;
+
+	if (dlen <= plen) {
+		/* Short packet: try for partial? */
+		if (strnicmp(data, pattern, dlen) == 0)
+			return -1;
+		else return 0;
+	}
+
+	if (strnicmp(data, pattern, plen) != 0) {
+#if 0
+		size_t i;
+
+		DEBUGP("ftp: string mismatch\n");
+		for (i = 0; i < plen; i++) {
+			DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
+				i, data[i], data[i],
+				pattern[i], pattern[i]);
+		}
+#endif
+		return 0;
+	}
+
+	DEBUGP("Pattern matches!\n");
+	/* Now we've found the constant string, try to skip
+	   to the 'skip' character */
+	for (i = plen; data[i] != skip; i++)
+		if (i == dlen - 1) return -1;
+
+	/* Skip over the last character */
+	i++;
+
+	DEBUGP("Skipped up to `%c'!\n", skip);
+
+	*numoff = i;
+	*numlen = getnum(data + i, dlen - i, cmd, term);
+	if (!*numlen)
+		return -1;
+
+	DEBUGP("Match succeeded!\n");
+	return 1;
+}
+
+/* Look up to see if we're just after a \n. */
+static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir)
+{
+	unsigned int i;
+
+	for (i = 0; i < info->seq_aft_nl_num[dir]; i++)
+		if (info->seq_aft_nl[dir][i] == seq)
+			return 1;
+	return 0;
+}
+
+/* We don't update if it's older than what we have. */
+static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir,
+			  struct sk_buff *skb)
+{
+	unsigned int i, oldest = NUM_SEQ_TO_REMEMBER;
+
+	/* Look for oldest: if we find exact match, we're done. */
+	for (i = 0; i < info->seq_aft_nl_num[dir]; i++) {
+		if (info->seq_aft_nl[dir][i] == nl_seq)
+			return;
+
+		if (oldest == info->seq_aft_nl_num[dir]
+		    || before(info->seq_aft_nl[dir][i], oldest))
+			oldest = i;
+	}
+
+	if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) {
+		info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq;
+		nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
+	} else if (oldest != NUM_SEQ_TO_REMEMBER) {
+		info->seq_aft_nl[dir][oldest] = nl_seq;
+		nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
+	}
+}
+
+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 *fb_ptr;
+	int ret;
+	u32 seq;
+	int dir = CTINFO2DIR(ctinfo);
+	unsigned int matchlen, matchoff;
+	struct ip_ct_ftp_master *ct_ftp_info = &ct->help->ct_ftp_info;
+	struct nf_conntrack_expect *exp;
+	struct nf_conntrack_man cmd = {};
+
+	unsigned int i;
+	int found = 0, ends_in_nl;
+
+	/* 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) {
+		DEBUGP("ftp: Conntrackinfo = %u\n", ctinfo);
+		return NF_ACCEPT;
+	}
+
+	th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph);
+	if (th == NULL)
+		return NF_ACCEPT;
+
+	dataoff = protoff + th->doff * 4;
+	/* No data? */
+	if (dataoff >= (*pskb)->len) {
+		DEBUGP("ftp: dataoff(%u) >= skblen(%u)\n", dataoff,
+			(*pskb)->len);
+		return NF_ACCEPT;
+	}
+	datalen = (*pskb)->len - dataoff;
+
+	spin_lock_bh(&nf_ftp_lock);
+	fb_ptr = skb_header_pointer(*pskb, dataoff, datalen, ftp_buffer);
+	BUG_ON(fb_ptr == NULL);
+
+	ends_in_nl = (fb_ptr[datalen - 1] == '\n');
+	seq = ntohl(th->seq) + datalen;
+
+	/* Look up to see if we're just after a \n. */
+	if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) {
+		/* Now if this ends in \n, update ftp info. */
+		DEBUGP("nf_conntrack_ftp_help: wrong seq pos %s(%u) or %s(%u)\n",
+		       ct_ftp_info->seq_aft_nl_num[dir] > 0 ? "" : "(UNSET)",
+		       ct_ftp_info->seq_aft_nl[dir][0],
+		       ct_ftp_info->seq_aft_nl_num[dir] > 1 ? "" : "(UNSET)",
+		       ct_ftp_info->seq_aft_nl[dir][1]);
+		ret = NF_ACCEPT;
+		goto out_update_nl;
+	}
+
+        /* Initialize IP/IPv6 addr to expected address (it's not mentioned
+           in EPSV responses) */
+	cmd.l3num = ct->tuplehash[dir].tuple.src.l3num;
+	memcpy(cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all,
+	       sizeof(cmd.u3.all));
+
+	for (i = 0; i < ARRAY_SIZE(search); i++) {
+		if (search[i].dir != dir) continue;
+
+		found = find_pattern(fb_ptr, datalen,
+				     search[i].pattern,
+				     search[i].plen,
+				     search[i].skip,
+				     search[i].term,
+				     &matchoff, &matchlen,
+				     &cmd,
+				     search[i].getnum);
+		if (found) break;
+	}
+	if (found == -1) {
+		/* We don't usually drop packets.  After all, this is
+		   connection tracking, not packet filtering.
+		   However, it is necessary for accurate tracking in
+		   this case. */
+		if (net_ratelimit())
+			printk("conntrack_ftp: partial %s %u+%u\n",
+			       search[i].pattern,
+			       ntohl(th->seq), datalen);
+		ret = NF_DROP;
+		goto out;
+	} else if (found == 0) { /* No match */
+		ret = NF_ACCEPT;
+		goto out_update_nl;
+	}
+
+	DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
+	       (int)matchlen, fb_ptr + matchoff,
+	       matchlen, ntohl(th->seq) + matchoff);
+
+	exp = nf_conntrack_expect_alloc(ct);
+	if (exp == NULL) {
+		ret = NF_DROP;
+		goto out;
+	}
+
+	/* We refer to the reverse direction ("!dir") tuples here,
+	 * because we're expecting something in the other direction.
+	 * Doesn't matter unless NAT is happening.  */
+	exp->tuple.dst.u3 = ct->tuplehash[!dir].tuple.dst.u3;
+
+	/* Update the ftp info */
+	if ((cmd.l3num == ct->tuplehash[dir].tuple.src.l3num) &&
+	    memcmp(&cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all,
+		     sizeof(cmd.u3.all))) {
+		/* Enrico Scholz's passive FTP to partially RNAT'd ftp
+                   server: it really wants us to connect to a
+                   different IP address.  Simply don't record it for
+                   NAT. */
+		if (cmd.l3num == PF_INET) {
+                	DEBUGP("conntrack_ftp: NOT RECORDING: %u,%u,%u,%u != %u.%u.%u.%u\n",
+			       NIPQUAD(cmd.u3.ip),
+			       NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip));
+		} else {
+			DEBUGP("conntrack_ftp: NOT RECORDING: %x:%x:%x:%x:%x:%x:%x:%x != %x:%x:%x:%x:%x:%x:%x:%x\n",
+			       NIP6(*((struct in6_addr *)cmd.u3.ip6)),
+			       NIP6(*((struct in6_addr *)ct->tuplehash[dir]
+							.tuple.src.u3.ip6)));
+		}
+
+		/* Thanks to Cristiano Lincoln Mattos
+		   <lincoln@cesar.org.br> for reporting this potential
+		   problem (DMZ machines opening holes to internal
+		   networks, or the packet filter itself). */
+		if (!loose) {
+			ret = NF_ACCEPT;
+			goto out_put_expect;
+		}
+		memcpy(&exp->tuple.dst.u3, &cmd.u3.all,
+		       sizeof(exp->tuple.dst.u3));
+	}
+
+	exp->tuple.src.u3 = ct->tuplehash[!dir].tuple.src.u3;
+	exp->tuple.src.l3num = cmd.l3num;
+	exp->tuple.src.u.tcp.port = 0;
+	exp->tuple.dst.u.tcp.port = cmd.u.tcp.port;
+	exp->tuple.dst.protonum = IPPROTO_TCP;
+
+	exp->mask = (struct nf_conntrack_tuple)
+		    { .src = { .l3num = 0xFFFF,
+			       .u = { .tcp = { 0 }},
+			     },
+		      .dst = { .protonum = 0xFF,
+			       .u = { .tcp = { 0xFFFF }},
+			     },
+		    };
+	if (cmd.l3num == PF_INET) {
+		exp->mask.src.u3.ip = 0xFFFFFFFF;
+		exp->mask.dst.u3.ip = 0xFFFFFFFF;
+	} else {
+		memset(exp->mask.src.u3.ip6, 0xFF,
+		       sizeof(exp->mask.src.u3.ip6));
+		memset(exp->mask.dst.u3.ip6, 0xFF,
+		       sizeof(exp->mask.src.u3.ip6));
+	}
+
+	exp->expectfn = NULL;
+	exp->flags = 0;
+
+	/* Now, NAT might want to mangle the packet, and register the
+	 * (possibly changed) expectation itself. */
+	if (nf_nat_ftp_hook)
+		ret = nf_nat_ftp_hook(pskb, ctinfo, search[i].ftptype,
+				      matchoff, matchlen, exp, &seq);
+	else {
+		/* Can't expect this?  Best to drop packet now. */
+		if (nf_conntrack_expect_related(exp) != 0)
+			ret = NF_DROP;
+		else
+			ret = NF_ACCEPT;
+	}
+
+out_put_expect:
+	nf_conntrack_expect_put(exp);
+
+out_update_nl:
+	/* Now if this ends in \n, update ftp info.  Seq may have been
+	 * adjusted by NAT code. */
+	if (ends_in_nl)
+		update_nl_seq(seq, ct_ftp_info, dir, *pskb);
+ out:
+	spin_unlock_bh(&nf_ftp_lock);
+	return ret;
+}
+
+static struct nf_conntrack_helper ftp[MAX_PORTS][2];
+static char ftp_names[MAX_PORTS][2][sizeof("ftp-65535")];
+
+/* don't make this __exit, since it's called from __init ! */
+static void fini(void)
+{
+	int i, j;
+	for (i = 0; i < ports_c; i++) {
+		for (j = 0; j < 2; j++) {
+			if (ftp[i][j].me == NULL)
+				continue;
+
+			DEBUGP("nf_ct_ftp: unregistering helper for pf: %d "
+			       "port: %d\n",
+				ftp[i][j].tuple.src.l3num, ports[i]);
+			nf_conntrack_helper_unregister(&ftp[i][j]);
+		}
+	}
+
+	kfree(ftp_buffer);
+}
+
+static int __init init(void)
+{
+	int i, j = -1, ret = 0;
+	char *tmpname;
+
+	ftp_buffer = kmalloc(65536, GFP_KERNEL);
+	if (!ftp_buffer)
+		return -ENOMEM;
+
+	if (ports_c == 0)
+		ports[ports_c++] = FTP_PORT;
+
+	/* FIXME should be configurable whether IPv4 and IPv6 FTP connections
+		 are tracked or not - YK */
+	for (i = 0; i < ports_c; i++) {
+		memset(&ftp[i], 0, sizeof(struct nf_conntrack_helper));
+
+		ftp[i][0].tuple.src.l3num = PF_INET;
+		ftp[i][1].tuple.src.l3num = PF_INET6;
+		for (j = 0; j < 2; j++) {
+			ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]);
+			ftp[i][j].tuple.dst.protonum = IPPROTO_TCP;
+			ftp[i][j].mask.src.u.tcp.port = 0xFFFF;
+			ftp[i][j].mask.dst.protonum = 0xFF;
+			ftp[i][j].max_expected = 1;
+			ftp[i][j].timeout = 5 * 60;	/* 5 Minutes */
+			ftp[i][j].me = THIS_MODULE;
+			ftp[i][j].help = help;
+			tmpname = &ftp_names[i][j][0];
+			if (ports[i] == FTP_PORT)
+				sprintf(tmpname, "ftp");
+			else
+				sprintf(tmpname, "ftp-%d", ports[i]);
+			ftp[i][j].name = tmpname;
+
+			DEBUGP("nf_ct_ftp: registering helper for pf: %d "
+			       "port: %d\n",
+				ftp[i][j].tuple.src.l3num, ports[i]);
+			ret = nf_conntrack_helper_register(&ftp[i][j]);
+			if (ret) {
+				printk("nf_ct_ftp: failed to register helper "
+				       " for pf: %d port: %d\n",
+					ftp[i][j].tuple.src.l3num, ports[i]);
+				fini();
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/nf_conntrack_l3proto_generic.c b/net/netfilter/nf_conntrack_l3proto_generic.c
new file mode 100644
index 0000000..7de4f06
--- /dev/null
+++ b/net/netfilter/nf_conntrack_l3proto_generic.c
@@ -0,0 +1,98 @@
+/*
+ * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ *
+ * Based largely upon the original ip_conntrack code which
+ * had the following copyright information:
+ *
+ * (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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:
+ *	Yasuyuki Kozakai @USAGI	<yasuyuki.kozakai@toshiba.co.jp>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/icmp.h>
+#include <linux/sysctl.h>
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+#include <net/netfilter/nf_conntrack_l3proto.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat);
+
+static int generic_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
+				struct nf_conntrack_tuple *tuple)
+{
+	memset(&tuple->src.u3, 0, sizeof(tuple->src.u3));
+	memset(&tuple->dst.u3, 0, sizeof(tuple->dst.u3));
+
+	return 1;
+}
+
+static int generic_invert_tuple(struct nf_conntrack_tuple *tuple,
+			   const struct nf_conntrack_tuple *orig)
+{
+	memset(&tuple->src.u3, 0, sizeof(tuple->src.u3));
+	memset(&tuple->dst.u3, 0, sizeof(tuple->dst.u3));
+
+	return 1;
+}
+
+static int generic_print_tuple(struct seq_file *s,
+			    const struct nf_conntrack_tuple *tuple)
+{
+	return 0;
+}
+
+static int generic_print_conntrack(struct seq_file *s,
+				const struct nf_conn *conntrack)
+{
+	return 0;
+}
+
+static int
+generic_prepare(struct sk_buff **pskb, unsigned int hooknum,
+		unsigned int *dataoff, u_int8_t *protonum)
+{
+	/* Never track !!! */
+	return -NF_ACCEPT;
+}
+
+
+static u_int32_t generic_get_features(const struct nf_conntrack_tuple *tuple)
+				
+{
+	return NF_CT_F_BASIC;
+}
+
+struct nf_conntrack_l3proto nf_conntrack_generic_l3proto = {
+	.l3proto	 = PF_UNSPEC,
+	.name		 = "unknown",
+	.pkt_to_tuple	 = generic_pkt_to_tuple,
+	.invert_tuple	 = generic_invert_tuple,
+	.print_tuple	 = generic_print_tuple,
+	.print_conntrack = generic_print_conntrack,
+	.prepare	 = generic_prepare,
+	.get_features	 = generic_get_features,
+	.me		 = THIS_MODULE,
+};
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
new file mode 100644
index 0000000..36425f6
--- /dev/null
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -0,0 +1,85 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- enable working with L3 protocol independent connection tracking.
+ *
+ * Derived from net/ipv4/netfilter/ip_conntrack_proto_generic.c
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+
+unsigned long nf_ct_generic_timeout = 600*HZ;
+
+static int generic_pkt_to_tuple(const struct sk_buff *skb,
+				unsigned int dataoff,
+				struct nf_conntrack_tuple *tuple)
+{
+	tuple->src.u.all = 0;
+	tuple->dst.u.all = 0;
+
+	return 1;
+}
+
+static int generic_invert_tuple(struct nf_conntrack_tuple *tuple,
+				const struct nf_conntrack_tuple *orig)
+{
+	tuple->src.u.all = 0;
+	tuple->dst.u.all = 0;
+
+	return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static int generic_print_tuple(struct seq_file *s,
+			       const struct nf_conntrack_tuple *tuple)
+{
+	return 0;
+}
+
+/* Print out the private part of the conntrack. */
+static int generic_print_conntrack(struct seq_file *s,
+				   const struct nf_conn *state)
+{
+	return 0;
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int packet(struct nf_conn *conntrack,
+		  const struct sk_buff *skb,
+		  unsigned int dataoff,
+		  enum ip_conntrack_info ctinfo,
+		  int pf,
+		  unsigned int hooknum)
+{
+	nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_generic_timeout);
+	return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int new(struct nf_conn *conntrack, const struct sk_buff *skb,
+	       unsigned int dataoff)
+{
+	return 1;
+}
+
+struct nf_conntrack_protocol nf_conntrack_generic_protocol =
+{
+	.l3proto		= PF_UNSPEC,
+	.proto			= 0,
+	.name			= "unknown",
+	.pkt_to_tuple		= generic_pkt_to_tuple,
+	.invert_tuple		= generic_invert_tuple,
+	.print_tuple		= generic_print_tuple,
+	.print_conntrack	= generic_print_conntrack,
+	.packet			= packet,
+	.new			= new,
+};
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
new file mode 100644
index 0000000..3a600f7
--- /dev/null
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -0,0 +1,670 @@
+/*
+ * Connection tracking protocol helper module for SCTP.
+ * 
+ * SCTP is defined in RFC 2960. References to various sections in this code 
+ * are to this RFC.
+ * 
+ * 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.
+ *
+ * 17 Oct 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- enable working with L3 protocol independent connection tracking.
+ *
+ * Derived from net/ipv4/ip_conntrack_sctp.c
+ */
+
+/*
+ * Added support for proc manipulation of timeouts.
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/sctp.h>
+#include <linux/string.h>
+#include <linux/seq_file.h>
+
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+
+#if 0
+#define DEBUGP(format, ...) printk(format, ## __VA_ARGS__)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Protects conntrack->proto.sctp */
+static DEFINE_RWLOCK(sctp_lock);
+
+/* FIXME: Examine ipfilter's timeouts and conntrack transitions more
+   closely.  They're more complex. --RR 
+
+   And so for me for SCTP :D -Kiran */
+
+static const char *sctp_conntrack_names[] = {
+	"NONE",
+	"CLOSED",
+	"COOKIE_WAIT",
+	"COOKIE_ECHOED",
+	"ESTABLISHED",
+	"SHUTDOWN_SENT",
+	"SHUTDOWN_RECD",
+	"SHUTDOWN_ACK_SENT",
+};
+
+#define SECS  * HZ
+#define MINS  * 60 SECS
+#define HOURS * 60 MINS
+#define DAYS  * 24 HOURS
+
+static unsigned long nf_ct_sctp_timeout_closed            =  10 SECS;
+static unsigned long nf_ct_sctp_timeout_cookie_wait       =   3 SECS;
+static unsigned long nf_ct_sctp_timeout_cookie_echoed     =   3 SECS;
+static unsigned long nf_ct_sctp_timeout_established       =   5 DAYS;
+static unsigned long nf_ct_sctp_timeout_shutdown_sent     = 300 SECS / 1000;
+static unsigned long nf_ct_sctp_timeout_shutdown_recd     = 300 SECS / 1000;
+static unsigned long nf_ct_sctp_timeout_shutdown_ack_sent =   3 SECS;
+
+static unsigned long * sctp_timeouts[]
+= { NULL,                                  /* SCTP_CONNTRACK_NONE  */
+    &nf_ct_sctp_timeout_closed,	           /* SCTP_CONNTRACK_CLOSED */
+    &nf_ct_sctp_timeout_cookie_wait,       /* SCTP_CONNTRACK_COOKIE_WAIT */
+    &nf_ct_sctp_timeout_cookie_echoed,     /* SCTP_CONNTRACK_COOKIE_ECHOED */
+    &nf_ct_sctp_timeout_established,       /* SCTP_CONNTRACK_ESTABLISHED */
+    &nf_ct_sctp_timeout_shutdown_sent,     /* SCTP_CONNTRACK_SHUTDOWN_SENT */
+    &nf_ct_sctp_timeout_shutdown_recd,     /* SCTP_CONNTRACK_SHUTDOWN_RECD */
+    &nf_ct_sctp_timeout_shutdown_ack_sent  /* SCTP_CONNTRACK_SHUTDOWN_ACK_SENT */
+ };
+
+#define sNO SCTP_CONNTRACK_NONE
+#define	sCL SCTP_CONNTRACK_CLOSED
+#define	sCW SCTP_CONNTRACK_COOKIE_WAIT
+#define	sCE SCTP_CONNTRACK_COOKIE_ECHOED
+#define	sES SCTP_CONNTRACK_ESTABLISHED
+#define	sSS SCTP_CONNTRACK_SHUTDOWN_SENT
+#define	sSR SCTP_CONNTRACK_SHUTDOWN_RECD
+#define	sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
+#define	sIV SCTP_CONNTRACK_MAX
+
+/* 
+	These are the descriptions of the states:
+
+NOTE: These state names are tantalizingly similar to the states of an 
+SCTP endpoint. But the interpretation of the states is a little different,
+considering that these are the states of the connection and not of an end 
+point. Please note the subtleties. -Kiran
+
+NONE              - Nothing so far.
+COOKIE WAIT       - We have seen an INIT chunk in the original direction, or also 
+                    an INIT_ACK chunk in the reply direction.
+COOKIE ECHOED     - We have seen a COOKIE_ECHO chunk in the original direction.
+ESTABLISHED       - We have seen a COOKIE_ACK in the reply direction.
+SHUTDOWN_SENT     - We have seen a SHUTDOWN chunk in the original direction.
+SHUTDOWN_RECD     - We have seen a SHUTDOWN chunk in the reply directoin.
+SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite
+                    to that of the SHUTDOWN chunk.
+CLOSED            - We have seen a SHUTDOWN_COMPLETE chunk in the direction of 
+                    the SHUTDOWN chunk. Connection is closed.
+*/
+
+/* TODO
+ - I have assumed that the first INIT is in the original direction. 
+ This messes things when an INIT comes in the reply direction in CLOSED
+ state.
+ - Check the error type in the reply dir before transitioning from 
+cookie echoed to closed.
+ - Sec 5.2.4 of RFC 2960
+ - Multi Homing support.
+*/
+
+/* SCTP conntrack state transitions */
+static enum sctp_conntrack sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = {
+	{
+/*	ORIGINAL	*/
+/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
+/* init         */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA},
+/* init_ack     */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},
+/* abort        */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
+/* shutdown     */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA},
+/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA},
+/* error        */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant have Stale cookie*/
+/* cookie_echo  */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA},/* 5.2.4 - Big TODO */
+/* cookie_ack   */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in orig dir */
+/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL}
+	},
+	{
+/*	REPLY	*/
+/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
+/* init         */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* INIT in sCL Big TODO */
+/* init_ack     */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},
+/* abort        */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
+/* shutdown     */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA},
+/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA},
+/* error        */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA},
+/* cookie_echo  */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in reply dir */
+/* cookie_ack   */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA},
+/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL}
+	}
+};
+
+static int sctp_pkt_to_tuple(const struct sk_buff *skb,
+			     unsigned int dataoff,
+			     struct nf_conntrack_tuple *tuple)
+{
+	sctp_sctphdr_t _hdr, *hp;
+
+	DEBUGP(__FUNCTION__);
+	DEBUGP("\n");
+
+	/* Actually only need first 8 bytes. */
+	hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
+	if (hp == NULL)
+		return 0;
+
+	tuple->src.u.sctp.port = hp->source;
+	tuple->dst.u.sctp.port = hp->dest;
+	return 1;
+}
+
+static int sctp_invert_tuple(struct nf_conntrack_tuple *tuple,
+			     const struct nf_conntrack_tuple *orig)
+{
+	DEBUGP(__FUNCTION__);
+	DEBUGP("\n");
+
+	tuple->src.u.sctp.port = orig->dst.u.sctp.port;
+	tuple->dst.u.sctp.port = orig->src.u.sctp.port;
+	return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static int sctp_print_tuple(struct seq_file *s,
+			    const struct nf_conntrack_tuple *tuple)
+{
+	DEBUGP(__FUNCTION__);
+	DEBUGP("\n");
+
+	return seq_printf(s, "sport=%hu dport=%hu ",
+			  ntohs(tuple->src.u.sctp.port),
+			  ntohs(tuple->dst.u.sctp.port));
+}
+
+/* Print out the private part of the conntrack. */
+static int sctp_print_conntrack(struct seq_file *s,
+				const struct nf_conn *conntrack)
+{
+	enum sctp_conntrack state;
+
+	DEBUGP(__FUNCTION__);
+	DEBUGP("\n");
+
+	read_lock_bh(&sctp_lock);
+	state = conntrack->proto.sctp.state;
+	read_unlock_bh(&sctp_lock);
+
+	return seq_printf(s, "%s ", sctp_conntrack_names[state]);
+}
+
+#define for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count)	\
+for (offset = dataoff + sizeof(sctp_sctphdr_t), count = 0;		\
+	offset < skb->len &&						\
+	(sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch));	\
+	offset += (htons(sch->length) + 3) & ~3, count++)
+
+/* Some validity checks to make sure the chunks are fine */
+static int do_basic_checks(struct nf_conn *conntrack,
+			   const struct sk_buff *skb,
+			   unsigned int dataoff,
+			   char *map)
+{
+	u_int32_t offset, count;
+	sctp_chunkhdr_t _sch, *sch;
+	int flag;
+
+	DEBUGP(__FUNCTION__);
+	DEBUGP("\n");
+
+	flag = 0;
+
+	for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) {
+		DEBUGP("Chunk Num: %d  Type: %d\n", count, sch->type);
+
+		if (sch->type == SCTP_CID_INIT 
+			|| sch->type == SCTP_CID_INIT_ACK
+			|| sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
+			flag = 1;
+		}
+
+		/* Cookie Ack/Echo chunks not the first OR 
+		   Init / Init Ack / Shutdown compl chunks not the only chunks */
+		if ((sch->type == SCTP_CID_COOKIE_ACK 
+			|| sch->type == SCTP_CID_COOKIE_ECHO
+			|| flag)
+		     && count !=0 ) {
+			DEBUGP("Basic checks failed\n");
+			return 1;
+		}
+
+		if (map) {
+			set_bit(sch->type, (void *)map);
+		}
+	}
+
+	DEBUGP("Basic checks passed\n");
+	return 0;
+}
+
+static int new_state(enum ip_conntrack_dir dir,
+		     enum sctp_conntrack cur_state,
+		     int chunk_type)
+{
+	int i;
+
+	DEBUGP(__FUNCTION__);
+	DEBUGP("\n");
+
+	DEBUGP("Chunk type: %d\n", chunk_type);
+
+	switch (chunk_type) {
+		case SCTP_CID_INIT: 
+			DEBUGP("SCTP_CID_INIT\n");
+			i = 0; break;
+		case SCTP_CID_INIT_ACK: 
+			DEBUGP("SCTP_CID_INIT_ACK\n");
+			i = 1; break;
+		case SCTP_CID_ABORT: 
+			DEBUGP("SCTP_CID_ABORT\n");
+			i = 2; break;
+		case SCTP_CID_SHUTDOWN: 
+			DEBUGP("SCTP_CID_SHUTDOWN\n");
+			i = 3; break;
+		case SCTP_CID_SHUTDOWN_ACK: 
+			DEBUGP("SCTP_CID_SHUTDOWN_ACK\n");
+			i = 4; break;
+		case SCTP_CID_ERROR: 
+			DEBUGP("SCTP_CID_ERROR\n");
+			i = 5; break;
+		case SCTP_CID_COOKIE_ECHO: 
+			DEBUGP("SCTP_CID_COOKIE_ECHO\n");
+			i = 6; break;
+		case SCTP_CID_COOKIE_ACK: 
+			DEBUGP("SCTP_CID_COOKIE_ACK\n");
+			i = 7; break;
+		case SCTP_CID_SHUTDOWN_COMPLETE: 
+			DEBUGP("SCTP_CID_SHUTDOWN_COMPLETE\n");
+			i = 8; break;
+		default:
+			/* Other chunks like DATA, SACK, HEARTBEAT and
+			its ACK do not cause a change in state */
+			DEBUGP("Unknown chunk type, Will stay in %s\n", 
+						sctp_conntrack_names[cur_state]);
+			return cur_state;
+	}
+
+	DEBUGP("dir: %d   cur_state: %s  chunk_type: %d  new_state: %s\n", 
+			dir, sctp_conntrack_names[cur_state], chunk_type,
+			sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]);
+
+	return sctp_conntracks[dir][i][cur_state];
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int sctp_packet(struct nf_conn *conntrack,
+		       const struct sk_buff *skb,
+		       unsigned int dataoff,
+		       enum ip_conntrack_info ctinfo,
+		       int pf,
+		       unsigned int hooknum)
+{
+	enum sctp_conntrack newconntrack, oldsctpstate;
+	sctp_sctphdr_t _sctph, *sh;
+	sctp_chunkhdr_t _sch, *sch;
+	u_int32_t offset, count;
+	char map[256 / sizeof (char)] = {0};
+
+	DEBUGP(__FUNCTION__);
+	DEBUGP("\n");
+
+	sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph);
+	if (sh == NULL)
+		return -1;
+
+	if (do_basic_checks(conntrack, skb, dataoff, map) != 0)
+		return -1;
+
+	/* Check the verification tag (Sec 8.5) */
+	if (!test_bit(SCTP_CID_INIT, (void *)map)
+		&& !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, (void *)map)
+		&& !test_bit(SCTP_CID_COOKIE_ECHO, (void *)map)
+		&& !test_bit(SCTP_CID_ABORT, (void *)map)
+		&& !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map)
+		&& (sh->vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
+		DEBUGP("Verification tag check failed\n");
+		return -1;
+	}
+
+	oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX;
+	for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) {
+		write_lock_bh(&sctp_lock);
+
+		/* Special cases of Verification tag check (Sec 8.5.1) */
+		if (sch->type == SCTP_CID_INIT) {
+			/* Sec 8.5.1 (A) */
+			if (sh->vtag != 0) {
+				write_unlock_bh(&sctp_lock);
+				return -1;
+			}
+		} else if (sch->type == SCTP_CID_ABORT) {
+			/* Sec 8.5.1 (B) */
+			if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
+				&& !(sh->vtag == conntrack->proto.sctp.vtag
+							[1 - CTINFO2DIR(ctinfo)])) {
+				write_unlock_bh(&sctp_lock);
+				return -1;
+			}
+		} else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
+			/* Sec 8.5.1 (C) */
+			if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
+				&& !(sh->vtag == conntrack->proto.sctp.vtag
+							[1 - CTINFO2DIR(ctinfo)] 
+					&& (sch->flags & 1))) {
+				write_unlock_bh(&sctp_lock);
+				return -1;
+			}
+		} else if (sch->type == SCTP_CID_COOKIE_ECHO) {
+			/* Sec 8.5.1 (D) */
+			if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
+				write_unlock_bh(&sctp_lock);
+				return -1;
+			}
+		}
+
+		oldsctpstate = conntrack->proto.sctp.state;
+		newconntrack = new_state(CTINFO2DIR(ctinfo), oldsctpstate, sch->type);
+
+		/* Invalid */
+		if (newconntrack == SCTP_CONNTRACK_MAX) {
+			DEBUGP("nf_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n",
+			       CTINFO2DIR(ctinfo), sch->type, oldsctpstate);
+			write_unlock_bh(&sctp_lock);
+			return -1;
+		}
+
+		/* If it is an INIT or an INIT ACK note down the vtag */
+		if (sch->type == SCTP_CID_INIT 
+			|| sch->type == SCTP_CID_INIT_ACK) {
+			sctp_inithdr_t _inithdr, *ih;
+
+			ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
+			                        sizeof(_inithdr), &_inithdr);
+			if (ih == NULL) {
+					write_unlock_bh(&sctp_lock);
+					return -1;
+			}
+			DEBUGP("Setting vtag %x for dir %d\n", 
+					ih->init_tag, !CTINFO2DIR(ctinfo));
+			conntrack->proto.sctp.vtag[!CTINFO2DIR(ctinfo)] = ih->init_tag;
+		}
+
+		conntrack->proto.sctp.state = newconntrack;
+		if (oldsctpstate != newconntrack)
+			nf_conntrack_event_cache(IPCT_PROTOINFO, skb);
+		write_unlock_bh(&sctp_lock);
+	}
+
+	nf_ct_refresh_acct(conntrack, ctinfo, skb, *sctp_timeouts[newconntrack]);
+
+	if (oldsctpstate == SCTP_CONNTRACK_COOKIE_ECHOED
+		&& CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
+		&& newconntrack == SCTP_CONNTRACK_ESTABLISHED) {
+		DEBUGP("Setting assured bit\n");
+		set_bit(IPS_ASSURED_BIT, &conntrack->status);
+		nf_conntrack_event_cache(IPCT_STATUS, skb);
+	}
+
+	return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int sctp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
+		    unsigned int dataoff)
+{
+	enum sctp_conntrack newconntrack;
+	sctp_sctphdr_t _sctph, *sh;
+	sctp_chunkhdr_t _sch, *sch;
+	u_int32_t offset, count;
+	char map[256 / sizeof (char)] = {0};
+
+	DEBUGP(__FUNCTION__);
+	DEBUGP("\n");
+
+	sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph);
+	if (sh == NULL)
+		return 0;
+
+	if (do_basic_checks(conntrack, skb, dataoff, map) != 0)
+		return 0;
+
+	/* If an OOTB packet has any of these chunks discard (Sec 8.4) */
+	if ((test_bit (SCTP_CID_ABORT, (void *)map))
+		|| (test_bit (SCTP_CID_SHUTDOWN_COMPLETE, (void *)map))
+		|| (test_bit (SCTP_CID_COOKIE_ACK, (void *)map))) {
+		return 0;
+	}
+
+	newconntrack = SCTP_CONNTRACK_MAX;
+	for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) {
+		/* Don't need lock here: this conntrack not in circulation yet */
+		newconntrack = new_state(IP_CT_DIR_ORIGINAL, 
+					 SCTP_CONNTRACK_NONE, sch->type);
+
+		/* Invalid: delete conntrack */
+		if (newconntrack == SCTP_CONNTRACK_MAX) {
+			DEBUGP("nf_conntrack_sctp: invalid new deleting.\n");
+			return 0;
+		}
+
+		/* Copy the vtag into the state info */
+		if (sch->type == SCTP_CID_INIT) {
+			if (sh->vtag == 0) {
+				sctp_inithdr_t _inithdr, *ih;
+
+				ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
+				                        sizeof(_inithdr), &_inithdr);
+				if (ih == NULL)
+					return 0;
+
+				DEBUGP("Setting vtag %x for new conn\n", 
+					ih->init_tag);
+
+				conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = 
+								ih->init_tag;
+			} else {
+				/* Sec 8.5.1 (A) */
+				return 0;
+			}
+		}
+		/* If it is a shutdown ack OOTB packet, we expect a return
+		   shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */
+		else {
+			DEBUGP("Setting vtag %x for new conn OOTB\n", 
+				sh->vtag);
+			conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag;
+		}
+
+		conntrack->proto.sctp.state = newconntrack;
+	}
+
+	return 1;
+}
+
+struct nf_conntrack_protocol nf_conntrack_protocol_sctp4 = { 
+	.l3proto	 = PF_INET,
+	.proto 		 = IPPROTO_SCTP, 
+	.name 		 = "sctp",
+	.pkt_to_tuple 	 = sctp_pkt_to_tuple, 
+	.invert_tuple 	 = sctp_invert_tuple, 
+	.print_tuple 	 = sctp_print_tuple, 
+	.print_conntrack = sctp_print_conntrack,
+	.packet 	 = sctp_packet, 
+	.new 		 = sctp_new, 
+	.destroy 	 = NULL, 
+	.me 		 = THIS_MODULE 
+};
+
+struct nf_conntrack_protocol nf_conntrack_protocol_sctp6 = { 
+	.l3proto	 = PF_INET6,
+	.proto 		 = IPPROTO_SCTP, 
+	.name 		 = "sctp",
+	.pkt_to_tuple 	 = sctp_pkt_to_tuple, 
+	.invert_tuple 	 = sctp_invert_tuple, 
+	.print_tuple 	 = sctp_print_tuple, 
+	.print_conntrack = sctp_print_conntrack,
+	.packet 	 = sctp_packet, 
+	.new 		 = sctp_new, 
+	.destroy 	 = NULL, 
+	.me 		 = THIS_MODULE 
+};
+
+#ifdef CONFIG_SYSCTL
+static ctl_table nf_ct_sysctl_table[] = {
+	{
+		.ctl_name	= NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED,
+		.procname	= "nf_conntrack_sctp_timeout_closed",
+		.data		= &nf_ct_sctp_timeout_closed,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT,
+		.procname	= "nf_conntrack_sctp_timeout_cookie_wait",
+		.data		= &nf_ct_sctp_timeout_cookie_wait,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED,
+		.procname	= "nf_conntrack_sctp_timeout_cookie_echoed",
+		.data		= &nf_ct_sctp_timeout_cookie_echoed,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED,
+		.procname	= "nf_conntrack_sctp_timeout_established",
+		.data		= &nf_ct_sctp_timeout_established,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT,
+		.procname	= "nf_conntrack_sctp_timeout_shutdown_sent",
+		.data		= &nf_ct_sctp_timeout_shutdown_sent,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD,
+		.procname	= "nf_conntrack_sctp_timeout_shutdown_recd",
+		.data		= &nf_ct_sctp_timeout_shutdown_recd,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT,
+		.procname	= "nf_conntrack_sctp_timeout_shutdown_ack_sent",
+		.data		= &nf_ct_sctp_timeout_shutdown_ack_sent,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table nf_ct_netfilter_table[] = {
+	{
+		.ctl_name	= NET_NETFILTER,
+		.procname	= "netfilter",
+		.mode		= 0555,
+		.child		= nf_ct_sysctl_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table nf_ct_net_table[] = {
+	{
+		.ctl_name	= CTL_NET,
+		.procname	= "net",
+		.mode		= 0555, 
+		.child		= nf_ct_netfilter_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static struct ctl_table_header *nf_ct_sysctl_header;
+#endif
+
+int __init init(void)
+{
+	int ret;
+
+	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_sctp4);
+	if (ret) {
+		printk("nf_conntrack_proto_sctp4: protocol register failed\n");
+		goto out;
+	}
+	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_sctp6);
+	if (ret) {
+		printk("nf_conntrack_proto_sctp6: protocol register failed\n");
+		goto cleanup_sctp4;
+	}
+
+#ifdef CONFIG_SYSCTL
+	nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
+	if (nf_ct_sysctl_header == NULL) {
+		printk("nf_conntrack_proto_sctp: can't register to sysctl.\n");
+		goto cleanup;
+	}
+#endif
+
+	return ret;
+
+#ifdef CONFIG_SYSCTL
+ cleanup:
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp6);
+#endif
+ cleanup_sctp4:
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp4);
+ out:
+	DEBUGP("SCTP conntrack module loading %s\n", 
+					ret ? "failed": "succeeded");
+	return ret;
+}
+
+void __exit fini(void)
+{
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp6);
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp4);
+#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(nf_ct_sysctl_header);
+#endif
+	DEBUGP("SCTP conntrack module unloaded\n");
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kiran Kumar Immidi");
+MODULE_DESCRIPTION("Netfilter connection tracking protocol helper for SCTP");
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
new file mode 100644
index 0000000..83d90dd
--- /dev/null
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -0,0 +1,1162 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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.
+ *
+ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>:
+ *	- Real stateful connection tracking
+ *	- Modified state transitions table
+ *	- Window scaling support added
+ *	- SACK support added
+ *
+ * Willy Tarreau:
+ *	- State table bugfixes
+ *	- More robust state changes
+ *	- Tuning timer parameters
+ *
+ * 27 Oct 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- genelized Layer 3 protocol part.
+ *
+ * Derived from net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+ *
+ * version 2.2
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+
+#include <net/tcp.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+
+#if 0
+#define DEBUGP printk
+#define DEBUGP_VARS
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Protects conntrack->proto.tcp */
+static DEFINE_RWLOCK(tcp_lock);
+
+/* "Be conservative in what you do, 
+    be liberal in what you accept from others." 
+    If it's non-zero, we mark only out of window RST segments as INVALID. */
+int nf_ct_tcp_be_liberal = 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 
+   connections. */
+int nf_ct_tcp_loose = 3;
+
+/* Max number of the retransmitted packets without receiving an (acceptable) 
+   ACK from the destination. If this number is reached, a shorter timer 
+   will be started. */
+int nf_ct_tcp_max_retrans = 3;
+
+  /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
+     closely.  They're more complex. --RR */
+
+static const char *tcp_conntrack_names[] = {
+	"NONE",
+	"SYN_SENT",
+	"SYN_RECV",
+	"ESTABLISHED",
+	"FIN_WAIT",
+	"CLOSE_WAIT",
+	"LAST_ACK",
+	"TIME_WAIT",
+	"CLOSE",
+	"LISTEN"
+};
+  
+#define SECS * HZ
+#define MINS * 60 SECS
+#define HOURS * 60 MINS
+#define DAYS * 24 HOURS
+
+unsigned long nf_ct_tcp_timeout_syn_sent =      2 MINS;
+unsigned long nf_ct_tcp_timeout_syn_recv =     60 SECS;
+unsigned long nf_ct_tcp_timeout_established =   5 DAYS;
+unsigned long nf_ct_tcp_timeout_fin_wait =      2 MINS;
+unsigned long nf_ct_tcp_timeout_close_wait =   60 SECS;
+unsigned long nf_ct_tcp_timeout_last_ack =     30 SECS;
+unsigned long nf_ct_tcp_timeout_time_wait =     2 MINS;
+unsigned long nf_ct_tcp_timeout_close =        10 SECS;
+
+/* RFC1122 says the R2 limit should be at least 100 seconds.
+   Linux uses 15 packets as limit, which corresponds 
+   to ~13-30min depending on RTO. */
+unsigned long nf_ct_tcp_timeout_max_retrans =     5 MINS;
+ 
+static unsigned long * tcp_timeouts[]
+= { NULL,                              /* TCP_CONNTRACK_NONE */
+    &nf_ct_tcp_timeout_syn_sent,       /* TCP_CONNTRACK_SYN_SENT, */
+    &nf_ct_tcp_timeout_syn_recv,       /* TCP_CONNTRACK_SYN_RECV, */
+    &nf_ct_tcp_timeout_established,    /* TCP_CONNTRACK_ESTABLISHED, */
+    &nf_ct_tcp_timeout_fin_wait,       /* TCP_CONNTRACK_FIN_WAIT, */
+    &nf_ct_tcp_timeout_close_wait,     /* TCP_CONNTRACK_CLOSE_WAIT, */
+    &nf_ct_tcp_timeout_last_ack,       /* TCP_CONNTRACK_LAST_ACK, */
+    &nf_ct_tcp_timeout_time_wait,      /* TCP_CONNTRACK_TIME_WAIT, */
+    &nf_ct_tcp_timeout_close,          /* TCP_CONNTRACK_CLOSE, */
+    NULL,                              /* TCP_CONNTRACK_LISTEN */
+ };
+ 
+#define sNO TCP_CONNTRACK_NONE
+#define sSS TCP_CONNTRACK_SYN_SENT
+#define sSR TCP_CONNTRACK_SYN_RECV
+#define sES TCP_CONNTRACK_ESTABLISHED
+#define sFW TCP_CONNTRACK_FIN_WAIT
+#define sCW TCP_CONNTRACK_CLOSE_WAIT
+#define sLA TCP_CONNTRACK_LAST_ACK
+#define sTW TCP_CONNTRACK_TIME_WAIT
+#define sCL TCP_CONNTRACK_CLOSE
+#define sLI TCP_CONNTRACK_LISTEN
+#define sIV TCP_CONNTRACK_MAX
+#define sIG TCP_CONNTRACK_IGNORE
+
+/* What TCP flags are set from RST/SYN/FIN/ACK. */
+enum tcp_bit_set {
+	TCP_SYN_SET,
+	TCP_SYNACK_SET,
+	TCP_FIN_SET,
+	TCP_ACK_SET,
+	TCP_RST_SET,
+	TCP_NONE_SET,
+};
+  
+/*
+ * The TCP state transition table needs a few words...
+ *
+ * We are the man in the middle. All the packets go through us
+ * but might get lost in transit to the destination.
+ * It is assumed that the destinations can't receive segments 
+ * we haven't seen.
+ *
+ * The checked segment is in window, but our windows are *not*
+ * equivalent with the ones of the sender/receiver. We always
+ * try to guess the state of the current sender.
+ *
+ * The meaning of the states are:
+ *
+ * NONE:	initial state
+ * SYN_SENT:	SYN-only packet seen 
+ * SYN_RECV:	SYN-ACK packet seen
+ * ESTABLISHED:	ACK packet seen
+ * FIN_WAIT:	FIN packet seen
+ * CLOSE_WAIT:	ACK seen (after FIN) 
+ * LAST_ACK:	FIN seen (after FIN)
+ * TIME_WAIT:	last ACK seen
+ * CLOSE:	closed connection
+ *
+ * LISTEN state is not used.
+ *
+ * Packets marked as IGNORED (sIG):
+ *	if they may be either invalid or valid 
+ *	and the receiver may send back a connection 
+ *	closing RST or a SYN/ACK.
+ *
+ * Packets marked as INVALID (sIV):
+ *	if they are invalid
+ *	or we do not support the request (simultaneous open)
+ */
+static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
+	{
+/* ORIGINAL */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*syn*/	   { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sIV },
+/*
+ *	sNO -> sSS	Initialize a new connection
+ *	sSS -> sSS	Retransmitted SYN
+ *	sSR -> sIG	Late retransmitted SYN?
+ *	sES -> sIG	Error: SYNs in window outside the SYN_SENT state
+ *			are errors. Receiver will reply with RST 
+ *			and close the connection.
+ *			Or we are not in sync and hold a dead connection.
+ *	sFW -> sIG
+ *	sCW -> sIG
+ *	sLA -> sIG
+ *	sTW -> sSS	Reopened connection (RFC 1122).
+ *	sCL -> sSS
+ */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },
+/*
+ * A SYN/ACK from the client is always invalid:
+ *	- either it tries to set up a simultaneous open, which is 
+ *	  not supported;
+ *	- or the firewall has just been inserted between the two hosts
+ *	  during the session set-up. The SYN will be retransmitted 
+ *	  by the true client (or it'll time out).
+ */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*fin*/    { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV },
+/*
+ *	sNO -> sIV	Too late and no reason to do anything...
+ *	sSS -> sIV	Client migth not send FIN in this state:
+ *			we enforce waiting for a SYN/ACK reply first.
+ *	sSR -> sFW	Close started.
+ *	sES -> sFW
+ *	sFW -> sLA	FIN seen in both directions, waiting for
+ *			the last ACK. 
+ *			Migth be a retransmitted FIN as well...
+ *	sCW -> sLA
+ *	sLA -> sLA	Retransmitted FIN. Remain in the same state.
+ *	sTW -> sTW
+ *	sCL -> sCL
+ */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*ack*/	   { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV },
+/*
+ *	sNO -> sES	Assumed.
+ *	sSS -> sIV	ACK is invalid: we haven't seen a SYN/ACK yet.
+ *	sSR -> sES	Established state is reached.
+ *	sES -> sES	:-)
+ *	sFW -> sCW	Normal close request answered by ACK.
+ *	sCW -> sCW
+ *	sLA -> sTW	Last ACK detected.
+ *	sTW -> sTW	Retransmitted last ACK. Remain in the same state.
+ *	sCL -> sCL
+ */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*rst*/    { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },
+/*none*/   { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
+	},
+	{
+/* REPLY */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*syn*/	   { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },
+/*
+ *	sNO -> sIV	Never reached.
+ *	sSS -> sIV	Simultaneous open, not supported
+ *	sSR -> sIV	Simultaneous open, not supported.
+ *	sES -> sIV	Server may not initiate a connection.
+ *	sFW -> sIV
+ *	sCW -> sIV
+ *	sLA -> sIV
+ *	sTW -> sIV	Reopened connection, but server may not do it.
+ *	sCL -> sIV
+ */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIV },
+/*
+ *	sSS -> sSR	Standard open.
+ *	sSR -> sSR	Retransmitted SYN/ACK.
+ *	sES -> sIG	Late retransmitted SYN/ACK?
+ *	sFW -> sIG	Might be SYN/ACK answering ignored SYN
+ *	sCW -> sIG
+ *	sLA -> sIG
+ *	sTW -> sIG
+ *	sCL -> sIG
+ */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*fin*/    { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV },
+/*
+ *	sSS -> sIV	Server might not send FIN in this state.
+ *	sSR -> sFW	Close started.
+ *	sES -> sFW
+ *	sFW -> sLA	FIN seen in both directions.
+ *	sCW -> sLA
+ *	sLA -> sLA	Retransmitted FIN.
+ *	sTW -> sTW
+ *	sCL -> sCL
+ */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*ack*/	   { sIV, sIV, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV },
+/*
+ *	sSS -> sIV	Might be a half-open connection.
+ *	sSR -> sSR	Might answer late resent SYN.
+ *	sES -> sES	:-)
+ *	sFW -> sCW	Normal close request answered by ACK.
+ *	sCW -> sCW
+ *	sLA -> sTW	Last ACK detected.
+ *	sTW -> sTW	Retransmitted last ACK.
+ *	sCL -> sCL
+ */
+/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
+/*rst*/    { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },
+/*none*/   { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
+  	}
+};
+
+static int tcp_pkt_to_tuple(const struct sk_buff *skb,
+			    unsigned int dataoff,
+			    struct nf_conntrack_tuple *tuple)
+{
+	struct tcphdr _hdr, *hp;
+
+	/* Actually only need first 8 bytes. */
+	hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
+	if (hp == NULL)
+		return 0;
+
+	tuple->src.u.tcp.port = hp->source;
+	tuple->dst.u.tcp.port = hp->dest;
+
+	return 1;
+}
+
+static int tcp_invert_tuple(struct nf_conntrack_tuple *tuple,
+			    const struct nf_conntrack_tuple *orig)
+{
+	tuple->src.u.tcp.port = orig->dst.u.tcp.port;
+	tuple->dst.u.tcp.port = orig->src.u.tcp.port;
+	return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static int tcp_print_tuple(struct seq_file *s,
+			   const struct nf_conntrack_tuple *tuple)
+{
+	return seq_printf(s, "sport=%hu dport=%hu ",
+			  ntohs(tuple->src.u.tcp.port),
+			  ntohs(tuple->dst.u.tcp.port));
+}
+
+/* Print out the private part of the conntrack. */
+static int tcp_print_conntrack(struct seq_file *s,
+			       const struct nf_conn *conntrack)
+{
+	enum tcp_conntrack state;
+
+	read_lock_bh(&tcp_lock);
+	state = conntrack->proto.tcp.state;
+	read_unlock_bh(&tcp_lock);
+
+	return seq_printf(s, "%s ", tcp_conntrack_names[state]);
+}
+
+static unsigned int get_conntrack_index(const struct tcphdr *tcph)
+{
+	if (tcph->rst) return TCP_RST_SET;
+	else if (tcph->syn) return (tcph->ack ? TCP_SYNACK_SET : TCP_SYN_SET);
+	else if (tcph->fin) return TCP_FIN_SET;
+	else if (tcph->ack) return TCP_ACK_SET;
+	else return TCP_NONE_SET;
+}
+
+/* TCP connection tracking based on 'Real Stateful TCP Packet Filtering
+   in IP Filter' by Guido van Rooij.
+   
+   http://www.nluug.nl/events/sane2000/papers.html
+   http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz
+   
+   The boundaries and the conditions are changed according to RFC793:
+   the packet must intersect the window (i.e. segments may be
+   after the right or before the left edge) and thus receivers may ACK
+   segments after the right edge of the window.
+
+   	td_maxend = max(sack + max(win,1)) seen in reply packets
+	td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets
+	td_maxwin += seq + len - sender.td_maxend
+			if seq + len > sender.td_maxend
+	td_end    = max(seq + len) seen in sent packets
+   
+   I.   Upper bound for valid data:	seq <= sender.td_maxend
+   II.  Lower bound for valid data:	seq + len >= sender.td_end - receiver.td_maxwin
+   III.	Upper bound for valid ack:      sack <= receiver.td_end
+   IV.	Lower bound for valid ack:	ack >= receiver.td_end - MAXACKWINDOW
+
+   where sack is the highest right edge of sack block found in the packet.
+
+   The upper bound limit for a valid ack is not ignored - 
+   we doesn't have to deal with fragments. 
+*/
+
+static inline __u32 segment_seq_plus_len(__u32 seq,
+					 size_t len,
+					 unsigned int dataoff,
+					 struct tcphdr *tcph)
+{
+	/* XXX Should I use payload length field in IP/IPv6 header ?
+	 * - YK */
+	return (seq + len - dataoff - tcph->doff*4
+		+ (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));
+}
+  
+/* Fixme: what about big packets? */
+#define MAXACKWINCONST			66000
+#define MAXACKWINDOW(sender)						\
+	((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin	\
+					      : MAXACKWINCONST)
+  
+/*
+ * Simplified tcp_parse_options routine from tcp_input.c
+ */
+static void tcp_options(const struct sk_buff *skb,
+			unsigned int dataoff,
+			struct tcphdr *tcph, 
+			struct ip_ct_tcp_state *state)
+{
+	unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
+	unsigned char *ptr;
+	int length = (tcph->doff*4) - sizeof(struct tcphdr);
+
+	if (!length)
+		return;
+
+	ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
+				 length, buff);
+	BUG_ON(ptr == NULL);
+
+	state->td_scale = 
+	state->flags = 0;
+
+	while (length > 0) {
+		int opcode=*ptr++;
+		int opsize;
+
+		switch (opcode) {
+		case TCPOPT_EOL:
+			return;
+		case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */
+			length--;
+			continue;
+		default:
+			opsize=*ptr++;
+			if (opsize < 2) /* "silly options" */
+				return;
+			if (opsize > length)
+				break;	/* don't parse partial options */
+
+			if (opcode == TCPOPT_SACK_PERM 
+			    && opsize == TCPOLEN_SACK_PERM)
+				state->flags |= IP_CT_TCP_FLAG_SACK_PERM;
+			else if (opcode == TCPOPT_WINDOW
+				 && opsize == TCPOLEN_WINDOW) {
+				state->td_scale = *(u_int8_t *)ptr;
+
+				if (state->td_scale > 14) {
+					/* See RFC1323 */
+					state->td_scale = 14;
+				}
+				state->flags |=
+					IP_CT_TCP_FLAG_WINDOW_SCALE;
+			}
+			ptr += opsize - 2;
+			length -= opsize;
+		}
+	}
+}
+
+static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
+		     struct tcphdr *tcph, __u32 *sack)
+{
+        unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
+	unsigned char *ptr;
+	int length = (tcph->doff*4) - sizeof(struct tcphdr);
+	__u32 tmp;
+
+	if (!length)
+		return;
+
+	ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
+				 length, buff);
+	BUG_ON(ptr == NULL);
+
+	/* Fast path for timestamp-only option */
+	if (length == TCPOLEN_TSTAMP_ALIGNED*4
+	    && *(__u32 *)ptr ==
+	        __constant_ntohl((TCPOPT_NOP << 24) 
+	        		 | (TCPOPT_NOP << 16)
+	        		 | (TCPOPT_TIMESTAMP << 8)
+	        		 | TCPOLEN_TIMESTAMP))
+		return;
+
+	while (length > 0) {
+		int opcode = *ptr++;
+		int opsize, i;
+
+		switch (opcode) {
+		case TCPOPT_EOL:
+			return;
+		case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */
+			length--;
+			continue;
+		default:
+			opsize = *ptr++;
+			if (opsize < 2) /* "silly options" */
+				return;
+			if (opsize > length)
+				break;	/* don't parse partial options */
+
+			if (opcode == TCPOPT_SACK 
+			    && opsize >= (TCPOLEN_SACK_BASE 
+			    		  + TCPOLEN_SACK_PERBLOCK)
+			    && !((opsize - TCPOLEN_SACK_BASE) 
+			    	 % TCPOLEN_SACK_PERBLOCK)) {
+			    	for (i = 0;
+			    	     i < (opsize - TCPOLEN_SACK_BASE);
+			    	     i += TCPOLEN_SACK_PERBLOCK) {
+					memcpy(&tmp, (__u32 *)(ptr + i) + 1,
+					       sizeof(__u32));
+					tmp = ntohl(tmp);
+
+					if (after(tmp, *sack))
+						*sack = tmp;
+				}
+				return;
+			}
+			ptr += opsize - 2;
+			length -= opsize;
+		}
+	}
+}
+
+static int tcp_in_window(struct ip_ct_tcp *state, 
+                         enum ip_conntrack_dir dir,
+                         unsigned int index,
+                         const struct sk_buff *skb,
+			 unsigned int dataoff,
+                         struct tcphdr *tcph,
+			 int pf)
+{
+	struct ip_ct_tcp_state *sender = &state->seen[dir];
+	struct ip_ct_tcp_state *receiver = &state->seen[!dir];
+	__u32 seq, ack, sack, end, win, swin;
+	int res;
+
+	/*
+	 * Get the required data from the packet.
+	 */
+	seq = ntohl(tcph->seq);
+	ack = sack = ntohl(tcph->ack_seq);
+	win = ntohs(tcph->window);
+	end = segment_seq_plus_len(seq, skb->len, dataoff, tcph);
+
+	if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM)
+		tcp_sack(skb, dataoff, tcph, &sack);
+
+	DEBUGP("tcp_in_window: START\n");
+	DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
+	       "seq=%u ack=%u sack=%u win=%u end=%u\n",
+		NIPQUAD(iph->saddr), ntohs(tcph->source), 
+		NIPQUAD(iph->daddr), ntohs(tcph->dest),
+		seq, ack, sack, win, end);
+	DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
+	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+		sender->td_end, sender->td_maxend, sender->td_maxwin,
+		sender->td_scale, 
+		receiver->td_end, receiver->td_maxend, receiver->td_maxwin, 
+		receiver->td_scale);
+
+	if (sender->td_end == 0) {
+		/*
+		 * Initialize sender data.
+		 */
+		if (tcph->syn && tcph->ack) {
+			/*
+			 * Outgoing SYN-ACK in reply to a SYN.
+			 */
+			sender->td_end = 
+			sender->td_maxend = end;
+			sender->td_maxwin = (win == 0 ? 1 : win);
+
+			tcp_options(skb, dataoff, tcph, sender);
+			/* 
+			 * RFC 1323:
+			 * Both sides must send the Window Scale option
+			 * to enable window scaling in either direction.
+			 */
+			if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE
+			      && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE))
+				sender->td_scale = 
+				receiver->td_scale = 0;
+		} else {
+			/*
+			 * We are in the middle of a connection,
+			 * its history is lost for us.
+			 * Let's try to use the data from the packet.
+		 	 */
+			sender->td_end = end;
+			sender->td_maxwin = (win == 0 ? 1 : win);
+			sender->td_maxend = end + sender->td_maxwin;
+		}
+	} else if (((state->state == TCP_CONNTRACK_SYN_SENT
+		     && dir == IP_CT_DIR_ORIGINAL)
+		   || (state->state == TCP_CONNTRACK_SYN_RECV
+		     && dir == IP_CT_DIR_REPLY))
+		   && after(end, sender->td_end)) {
+		/*
+		 * RFC 793: "if a TCP is reinitialized ... then it need
+		 * not wait at all; it must only be sure to use sequence 
+		 * numbers larger than those recently used."
+		 */
+		sender->td_end =
+		sender->td_maxend = end;
+		sender->td_maxwin = (win == 0 ? 1 : win);
+
+		tcp_options(skb, dataoff, tcph, sender);
+	}
+
+	if (!(tcph->ack)) {
+		/*
+		 * If there is no ACK, just pretend it was set and OK.
+		 */
+		ack = sack = receiver->td_end;
+	} else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == 
+		    (TCP_FLAG_ACK|TCP_FLAG_RST)) 
+		   && (ack == 0)) {
+		/*
+		 * Broken TCP stacks, that set ACK in RST packets as well
+		 * with zero ack value.
+		 */
+		ack = sack = receiver->td_end;
+	}
+
+	if (seq == end
+	    && (!tcph->rst
+		|| (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT)))
+		/*
+		 * Packets contains no data: we assume it is valid
+		 * and check the ack value only.
+		 * However RST segments are always validated by their
+		 * SEQ number, except when seq == 0 (reset sent answering
+		 * SYN.
+		 */
+		seq = end = sender->td_end;
+
+	DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
+	       "seq=%u ack=%u sack =%u win=%u end=%u\n",
+		NIPQUAD(iph->saddr), ntohs(tcph->source),
+		NIPQUAD(iph->daddr), ntohs(tcph->dest),
+		seq, ack, sack, win, end);
+	DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
+	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+		sender->td_end, sender->td_maxend, sender->td_maxwin,
+		sender->td_scale, 
+		receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+		receiver->td_scale);
+
+	DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
+		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 (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)))) {
+	    	/*
+		 * Take into account window scaling (RFC 1323).
+		 */
+		if (!tcph->syn)
+			win <<= sender->td_scale;
+
+		/*
+		 * Update sender data.
+		 */
+		swin = win + (sack - ack);
+		if (sender->td_maxwin < swin)
+			sender->td_maxwin = swin;
+		if (after(end, sender->td_end))
+			sender->td_end = end;
+		/*
+		 * Update receiver data.
+		 */
+		if (after(end, sender->td_maxend))
+			receiver->td_maxwin += end - sender->td_maxend;
+		if (after(sack + win, receiver->td_maxend - 1)) {
+			receiver->td_maxend = sack + win;
+			if (win == 0)
+				receiver->td_maxend++;
+		}
+
+		/* 
+		 * Check retransmissions.
+		 */
+		if (index == TCP_ACK_SET) {
+			if (state->last_dir == dir
+			    && state->last_seq == seq
+			    && state->last_ack == ack
+			    && state->last_end == end)
+				state->retrans++;
+			else {
+				state->last_dir = dir;
+				state->last_seq = seq;
+				state->last_ack = ack;
+				state->last_end = end;
+				state->retrans = 0;
+			}
+		}
+		/*
+		 * Close the window of disabled window tracking :-)
+		 */
+		if (sender->loose)
+			sender->loose--;
+
+		res = 1;
+	} else {
+		if (LOG_INVALID(IPPROTO_TCP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+			"nf_ct_tcp: %s ",
+			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)) ? "BUG"
+			: "ACK is under the lower bound (possible overly delayed ACK)"
+			: "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 "
+	       "receiver end=%u maxend=%u maxwin=%u\n",
+		res, sender->td_end, sender->td_maxend, sender->td_maxwin, 
+		receiver->td_end, receiver->td_maxend, receiver->td_maxwin);
+
+	return res;
+}
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+/* Update sender->td_end after NAT successfully mangled the packet */
+/* Caller must linearize skb at tcp header. */
+void nf_conntrack_tcp_update(struct sk_buff *skb,
+			     unsigned int dataoff,
+			     struct nf_conn *conntrack, 
+			     int dir)
+{
+	struct tcphdr *tcph = (void *)skb->data + dataoff;
+	__u32 end;
+#ifdef DEBUGP_VARS
+	struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir];
+	struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir];
+#endif
+
+	end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph);
+
+	write_lock_bh(&tcp_lock);
+	/*
+	 * We have to worry for the ack in the reply packet only...
+	 */
+	if (after(end, conntrack->proto.tcp.seen[dir].td_end))
+		conntrack->proto.tcp.seen[dir].td_end = end;
+	conntrack->proto.tcp.last_end = end;
+	write_unlock_bh(&tcp_lock);
+	DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
+	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+		sender->td_end, sender->td_maxend, sender->td_maxwin,
+		sender->td_scale, 
+		receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+		receiver->td_scale);
+}
+ 
+#endif
+
+#define	TH_FIN	0x01
+#define	TH_SYN	0x02
+#define	TH_RST	0x04
+#define	TH_PUSH	0x08
+#define	TH_ACK	0x10
+#define	TH_URG	0x20
+#define	TH_ECE	0x40
+#define	TH_CWR	0x80
+
+/* table of valid flag combinations - ECE and CWR are always valid */
+static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] =
+{
+	[TH_SYN]			= 1,
+	[TH_SYN|TH_ACK]			= 1,
+	[TH_SYN|TH_ACK|TH_PUSH]		= 1,
+	[TH_RST]			= 1,
+	[TH_RST|TH_ACK]			= 1,
+	[TH_RST|TH_ACK|TH_PUSH]		= 1,
+	[TH_FIN|TH_ACK]			= 1,
+	[TH_ACK]			= 1,
+	[TH_ACK|TH_PUSH]		= 1,
+	[TH_ACK|TH_URG]			= 1,
+	[TH_ACK|TH_URG|TH_PUSH]		= 1,
+	[TH_FIN|TH_ACK|TH_PUSH]		= 1,
+	[TH_FIN|TH_ACK|TH_URG]		= 1,
+	[TH_FIN|TH_ACK|TH_URG|TH_PUSH]	= 1,
+};
+
+/* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c.  */
+static int tcp_error(struct sk_buff *skb,
+		     unsigned int dataoff,
+		     enum ip_conntrack_info *ctinfo,
+		     int pf,
+		     unsigned int hooknum,
+		     int(*csum)(const struct sk_buff *,unsigned int))
+{
+	struct tcphdr _tcph, *th;
+	unsigned int tcplen = skb->len - dataoff;
+	u_int8_t tcpflags;
+
+	/* Smaller that minimal TCP header? */
+	th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
+	if (th == NULL) {
+		if (LOG_INVALID(IPPROTO_TCP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+				"nf_ct_tcp: short packet ");
+		return -NF_ACCEPT;
+  	}
+  
+	/* Not whole TCP header or malformed packet */
+	if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
+		if (LOG_INVALID(IPPROTO_TCP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+				"nf_ct_tcp: truncated/malformed packet ");
+		return -NF_ACCEPT;
+	}
+  
+	/* Checksum invalid? Ignore.
+	 * We skip checking packets on the outgoing path
+	 * because the semantic of CHECKSUM_HW is different there 
+	 * and moreover root might send raw packets.
+	 */
+	/* FIXME: Source route IP option packets --RR */
+	if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+	     (pf == PF_INET6 && hooknum  == NF_IP6_PRE_ROUTING))
+	    && skb->ip_summed != CHECKSUM_UNNECESSARY
+	    && csum(skb, dataoff)) {
+		if (LOG_INVALID(IPPROTO_TCP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+				  "nf_ct_tcp: bad TCP checksum ");
+		return -NF_ACCEPT;
+	}
+
+	/* Check TCP flags. */
+	tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR));
+	if (!tcp_valid_flags[tcpflags]) {
+		if (LOG_INVALID(IPPROTO_TCP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+				  "nf_ct_tcp: invalid TCP flag combination ");
+		return -NF_ACCEPT;
+	}
+
+	return NF_ACCEPT;
+}
+
+static int csum4(const struct sk_buff *skb, unsigned int dataoff)
+{
+	return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
+				 skb->len - dataoff, IPPROTO_TCP,
+			         skb->ip_summed == CHECKSUM_HW ? skb->csum
+			      	 : skb_checksum(skb, dataoff,
+						skb->len - dataoff, 0));
+}
+
+static int csum6(const struct sk_buff *skb, unsigned int dataoff)
+{
+	return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
+			       skb->len - dataoff, IPPROTO_TCP,
+			       skb->ip_summed == CHECKSUM_HW ? skb->csum
+			       : skb_checksum(skb, dataoff, skb->len - dataoff,
+					      0));
+}
+
+static int tcp_error4(struct sk_buff *skb,
+		      unsigned int dataoff,
+		      enum ip_conntrack_info *ctinfo,
+		      int pf,
+		      unsigned int hooknum)
+{
+	return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum4);
+}
+
+static int tcp_error6(struct sk_buff *skb,
+		      unsigned int dataoff,
+		      enum ip_conntrack_info *ctinfo,
+		      int pf,
+		      unsigned int hooknum)
+{
+	return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum6);
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int tcp_packet(struct nf_conn *conntrack,
+		      const struct sk_buff *skb,
+		      unsigned int dataoff,
+		      enum ip_conntrack_info ctinfo,
+		      int pf,
+		      unsigned int hooknum)
+{
+	enum tcp_conntrack new_state, old_state;
+	enum ip_conntrack_dir dir;
+	struct tcphdr *th, _tcph;
+	unsigned long timeout;
+	unsigned int index;
+
+	th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
+	BUG_ON(th == NULL);
+
+	write_lock_bh(&tcp_lock);
+	old_state = conntrack->proto.tcp.state;
+	dir = CTINFO2DIR(ctinfo);
+	index = get_conntrack_index(th);
+	new_state = tcp_conntracks[dir][index][old_state];
+
+	switch (new_state) {
+	case TCP_CONNTRACK_IGNORE:
+		/* Either SYN in ORIGINAL
+		 * or SYN/ACK in REPLY. */
+		if (index == TCP_SYNACK_SET
+		    && conntrack->proto.tcp.last_index == TCP_SYN_SET
+		    && conntrack->proto.tcp.last_dir != dir
+		    && ntohl(th->ack_seq) ==
+		    	     conntrack->proto.tcp.last_end) {
+			/* This SYN/ACK acknowledges a SYN that we earlier 
+			 * ignored as invalid. This means that the client and
+			 * the server are both in sync, while the firewall is
+			 * not. We kill this session and block the SYN/ACK so
+			 * that the client cannot but retransmit its SYN and 
+			 * thus initiate a clean new session.
+			 */
+		    	write_unlock_bh(&tcp_lock);
+			if (LOG_INVALID(IPPROTO_TCP))
+				nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+					  "nf_ct_tcp: killing out of sync session ");
+		    	if (del_timer(&conntrack->timeout))
+		    		conntrack->timeout.function((unsigned long)
+		    					    conntrack);
+		    	return -NF_DROP;
+		}
+		conntrack->proto.tcp.last_index = index;
+		conntrack->proto.tcp.last_dir = dir;
+		conntrack->proto.tcp.last_seq = ntohl(th->seq);
+		conntrack->proto.tcp.last_end =
+		    segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th);
+
+		write_unlock_bh(&tcp_lock);
+		if (LOG_INVALID(IPPROTO_TCP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+				  "nf_ct_tcp: invalid packed ignored ");
+		return NF_ACCEPT;
+	case TCP_CONNTRACK_MAX:
+		/* Invalid packet */
+		DEBUGP("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n",
+		       dir, get_conntrack_index(th),
+		       old_state);
+		write_unlock_bh(&tcp_lock);
+		if (LOG_INVALID(IPPROTO_TCP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+				  "nf_ct_tcp: invalid state ");
+		return -NF_ACCEPT;
+	case TCP_CONNTRACK_SYN_SENT:
+		if (old_state < TCP_CONNTRACK_TIME_WAIT)
+			break;
+		if ((conntrack->proto.tcp.seen[dir].flags &
+			IP_CT_TCP_FLAG_CLOSE_INIT)
+		    || after(ntohl(th->seq),
+			     conntrack->proto.tcp.seen[dir].td_end)) {
+		    	/* Attempt to reopen a closed connection.
+		    	* Delete this connection and look up again. */
+		    	write_unlock_bh(&tcp_lock);
+		    	if (del_timer(&conntrack->timeout))
+		    		conntrack->timeout.function((unsigned long)
+		    					    conntrack);
+		    	return -NF_REPEAT;
+		}
+	case TCP_CONNTRACK_CLOSE:
+		if (index == TCP_RST_SET
+		    && test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
+		    && conntrack->proto.tcp.last_index == TCP_SYN_SET
+		    && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) {
+			/* RST sent to invalid SYN we had let trough
+			 * SYN was in window then, tear down connection.
+			 * We skip window checking, because packet might ACK
+			 * segments we ignored in the SYN. */
+			goto in_window;
+		}
+		/* Just fall trough */
+	default:
+		/* Keep compilers happy. */
+		break;
+	}
+
+	if (!tcp_in_window(&conntrack->proto.tcp, dir, index,
+			   skb, dataoff, th, pf)) {
+		write_unlock_bh(&tcp_lock);
+		return -NF_ACCEPT;
+	}
+     in_window:
+	/* From now on we have got in-window packets */
+	conntrack->proto.tcp.last_index = index;
+
+	DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
+	       "syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n",
+		NIPQUAD(iph->saddr), ntohs(th->source),
+		NIPQUAD(iph->daddr), ntohs(th->dest),
+		(th->syn ? 1 : 0), (th->ack ? 1 : 0),
+		(th->fin ? 1 : 0), (th->rst ? 1 : 0),
+		old_state, new_state);
+
+	conntrack->proto.tcp.state = new_state;
+	if (old_state != new_state
+	    && (new_state == TCP_CONNTRACK_FIN_WAIT
+		|| new_state == TCP_CONNTRACK_CLOSE))
+		conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
+	timeout = conntrack->proto.tcp.retrans >= nf_ct_tcp_max_retrans
+		  && *tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans
+		  ? nf_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
+	write_unlock_bh(&tcp_lock);
+
+	nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+	if (new_state != old_state)
+		nf_conntrack_event_cache(IPCT_PROTOINFO, skb);
+
+	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+		/* If only reply is a RST, we can consider ourselves not to
+		   have an established connection: this is a fairly common
+		   problem case, so we can delete the conntrack
+		   immediately.  --RR */
+		if (th->rst) {
+			if (del_timer(&conntrack->timeout))
+				conntrack->timeout.function((unsigned long)
+							    conntrack);
+			return NF_ACCEPT;
+		}
+	} else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
+		   && (old_state == TCP_CONNTRACK_SYN_RECV
+		       || old_state == TCP_CONNTRACK_ESTABLISHED)
+		   && new_state == TCP_CONNTRACK_ESTABLISHED) {
+		/* Set ASSURED if we see see valid ack in ESTABLISHED 
+		   after SYN_RECV or a valid answer for a picked up 
+		   connection. */
+		set_bit(IPS_ASSURED_BIT, &conntrack->status);
+		nf_conntrack_event_cache(IPCT_STATUS, skb);
+	}
+	nf_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
+
+	return NF_ACCEPT;
+}
+ 
+/* Called when a new connection for this protocol found. */
+static int tcp_new(struct nf_conn *conntrack,
+		   const struct sk_buff *skb,
+		   unsigned int dataoff)
+{
+	enum tcp_conntrack new_state;
+	struct tcphdr *th, _tcph;
+#ifdef DEBUGP_VARS
+	struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];
+	struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];
+#endif
+
+	th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
+	BUG_ON(th == NULL);
+
+	/* Don't need lock here: this conntrack not in circulation yet */
+	new_state
+		= tcp_conntracks[0][get_conntrack_index(th)]
+		[TCP_CONNTRACK_NONE];
+
+	/* Invalid: delete conntrack */
+	if (new_state >= TCP_CONNTRACK_MAX) {
+		DEBUGP("nf_ct_tcp: invalid new deleting.\n");
+		return 0;
+	}
+
+	if (new_state == TCP_CONNTRACK_SYN_SENT) {
+		/* SYN packet */
+		conntrack->proto.tcp.seen[0].td_end =
+			segment_seq_plus_len(ntohl(th->seq), skb->len,
+					     dataoff, th);
+		conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
+		if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
+			conntrack->proto.tcp.seen[0].td_maxwin = 1;
+		conntrack->proto.tcp.seen[0].td_maxend =
+			conntrack->proto.tcp.seen[0].td_end;
+
+		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;
+	} else {
+		/*
+		 * We are in the middle of a connection,
+		 * its history is lost for us.
+		 * Let's try to use the data from the packet.
+		 */
+		conntrack->proto.tcp.seen[0].td_end =
+			segment_seq_plus_len(ntohl(th->seq), skb->len,
+					     dataoff, th);
+		conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
+		if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
+			conntrack->proto.tcp.seen[0].td_maxwin = 1;
+		conntrack->proto.tcp.seen[0].td_maxend =
+			conntrack->proto.tcp.seen[0].td_end + 
+			conntrack->proto.tcp.seen[0].td_maxwin;
+		conntrack->proto.tcp.seen[0].td_scale = 0;
+
+		/* We assume SACK. Should we assume window scaling too? */
+		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].td_end = 0;
+	conntrack->proto.tcp.seen[1].td_maxend = 0;
+	conntrack->proto.tcp.seen[1].td_maxwin = 1;
+	conntrack->proto.tcp.seen[1].td_scale = 0;      
+
+	/* tcp_packet will set them */
+	conntrack->proto.tcp.state = TCP_CONNTRACK_NONE;
+	conntrack->proto.tcp.last_index = TCP_NONE_SET;
+	 
+	DEBUGP("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i "
+	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+		sender->td_end, sender->td_maxend, sender->td_maxwin,
+		sender->td_scale, 
+		receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+		receiver->td_scale);
+	return 1;
+}
+  
+struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 =
+{
+	.l3proto		= PF_INET,
+	.proto 			= IPPROTO_TCP,
+	.name 			= "tcp",
+	.pkt_to_tuple 		= tcp_pkt_to_tuple,
+	.invert_tuple 		= tcp_invert_tuple,
+	.print_tuple 		= tcp_print_tuple,
+	.print_conntrack 	= tcp_print_conntrack,
+	.packet 		= tcp_packet,
+	.new 			= tcp_new,
+	.error			= tcp_error4,
+};
+
+struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 =
+{
+	.l3proto		= PF_INET6,
+	.proto 			= IPPROTO_TCP,
+	.name 			= "tcp",
+	.pkt_to_tuple 		= tcp_pkt_to_tuple,
+	.invert_tuple 		= tcp_invert_tuple,
+	.print_tuple 		= tcp_print_tuple,
+	.print_conntrack 	= tcp_print_conntrack,
+	.packet 		= tcp_packet,
+	.new 			= tcp_new,
+	.error			= tcp_error6,
+};
+
+EXPORT_SYMBOL(nf_conntrack_protocol_tcp4);
+EXPORT_SYMBOL(nf_conntrack_protocol_tcp6);
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
new file mode 100644
index 0000000..3cae7ce
--- /dev/null
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -0,0 +1,216 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- enable working with Layer 3 protocol independent connection tracking.
+ *
+ * Derived from net/ipv4/netfilter/ip_conntrack_proto_udp.c
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/udp.h>
+#include <linux/seq_file.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+#include <net/checksum.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+
+unsigned long nf_ct_udp_timeout = 30*HZ;
+unsigned long nf_ct_udp_timeout_stream = 180*HZ;
+
+static int udp_pkt_to_tuple(const struct sk_buff *skb,
+			     unsigned int dataoff,
+			     struct nf_conntrack_tuple *tuple)
+{
+	struct udphdr _hdr, *hp;
+
+	/* Actually only need first 8 bytes. */
+	hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+	if (hp == NULL)
+		return 0;
+
+	tuple->src.u.udp.port = hp->source;
+	tuple->dst.u.udp.port = hp->dest;
+
+	return 1;
+}
+
+static int udp_invert_tuple(struct nf_conntrack_tuple *tuple,
+			    const struct nf_conntrack_tuple *orig)
+{
+	tuple->src.u.udp.port = orig->dst.u.udp.port;
+	tuple->dst.u.udp.port = orig->src.u.udp.port;
+	return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static int udp_print_tuple(struct seq_file *s,
+			   const struct nf_conntrack_tuple *tuple)
+{
+	return seq_printf(s, "sport=%hu dport=%hu ",
+			  ntohs(tuple->src.u.udp.port),
+			  ntohs(tuple->dst.u.udp.port));
+}
+
+/* Print out the private part of the conntrack. */
+static int udp_print_conntrack(struct seq_file *s,
+			       const struct nf_conn *conntrack)
+{
+	return 0;
+}
+
+/* Returns verdict for packet, and may modify conntracktype */
+static int udp_packet(struct nf_conn *conntrack,
+		      const struct sk_buff *skb,
+		      unsigned int dataoff,
+		      enum ip_conntrack_info ctinfo,
+		      int pf,
+		      unsigned int hooknum)
+{
+	/* If we've seen traffic both ways, this is some kind of UDP
+	   stream.  Extend timeout. */
+	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+		nf_ct_refresh_acct(conntrack, ctinfo, skb,
+				   nf_ct_udp_timeout_stream);
+		/* Also, more likely to be important, and not a probe */
+		if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
+			nf_conntrack_event_cache(IPCT_STATUS, skb);
+	} else
+		nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_udp_timeout);
+
+	return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int udp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
+		   unsigned int dataoff)
+{
+	return 1;
+}
+
+static int udp_error(struct sk_buff *skb, unsigned int dataoff,
+		     enum ip_conntrack_info *ctinfo,
+		     int pf,
+		     unsigned int hooknum,
+		     int (*csum)(const struct sk_buff *, unsigned int))
+{
+	unsigned int udplen = skb->len - dataoff;
+	struct udphdr _hdr, *hdr;
+
+	/* Header is too small? */
+	hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+	if (hdr == NULL) {
+		if (LOG_INVALID(IPPROTO_UDP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+				      "nf_ct_udp: short packet ");
+		return -NF_ACCEPT;
+	}
+
+	/* Truncated/malformed packets */
+	if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
+		if (LOG_INVALID(IPPROTO_UDP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+				"nf_ct_udp: truncated/malformed packet ");
+		return -NF_ACCEPT;
+	}
+
+	/* Packet with no checksum */
+	if (!hdr->check)
+		return NF_ACCEPT;
+
+	/* Checksum invalid? Ignore.
+	 * We skip checking packets on the outgoing path
+	 * because the semantic of CHECKSUM_HW is different there
+	 * and moreover root might send raw packets.
+	 * FIXME: Source route IP option packets --RR */
+	if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+	     (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING))
+	    && skb->ip_summed != CHECKSUM_UNNECESSARY
+	    && csum(skb, dataoff)) {
+		if (LOG_INVALID(IPPROTO_UDP))
+			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+				"nf_ct_udp: bad UDP checksum ");
+		return -NF_ACCEPT;
+	}
+
+	return NF_ACCEPT;
+}
+
+static int csum4(const struct sk_buff *skb, unsigned int dataoff)
+{
+	return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
+				 skb->len - dataoff, IPPROTO_UDP,
+				 skb->ip_summed == CHECKSUM_HW ? skb->csum
+				 : skb_checksum(skb, dataoff,
+						skb->len - dataoff, 0));
+}
+
+static int csum6(const struct sk_buff *skb, unsigned int dataoff)
+{
+	return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
+			       skb->len - dataoff, IPPROTO_UDP,
+			       skb->ip_summed == CHECKSUM_HW ? skb->csum
+			       : skb_checksum(skb, dataoff, skb->len - dataoff,
+					      0));
+}
+
+static int udp_error4(struct sk_buff *skb,
+		      unsigned int dataoff,
+		      enum ip_conntrack_info *ctinfo,
+		      int pf,
+		      unsigned int hooknum)
+{
+	return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum4);
+}
+
+static int udp_error6(struct sk_buff *skb,
+		      unsigned int dataoff,
+		      enum ip_conntrack_info *ctinfo,
+		      int pf,
+		      unsigned int hooknum)
+{
+	return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum6);
+}
+
+struct nf_conntrack_protocol nf_conntrack_protocol_udp4 =
+{
+	.l3proto		= PF_INET,
+	.proto			= IPPROTO_UDP,
+	.name			= "udp",
+	.pkt_to_tuple		= udp_pkt_to_tuple,
+	.invert_tuple		= udp_invert_tuple,
+	.print_tuple		= udp_print_tuple,
+	.print_conntrack	= udp_print_conntrack,
+	.packet			= udp_packet,
+	.new			= udp_new,
+	.error			= udp_error4,
+};
+
+struct nf_conntrack_protocol nf_conntrack_protocol_udp6 =
+{
+	.l3proto		= PF_INET6,
+	.proto			= IPPROTO_UDP,
+	.name			= "udp",
+	.pkt_to_tuple		= udp_pkt_to_tuple,
+	.invert_tuple		= udp_invert_tuple,
+	.print_tuple		= udp_print_tuple,
+	.print_conntrack	= udp_print_conntrack,
+	.packet			= udp_packet,
+	.new			= udp_new,
+	.error			= udp_error6,
+};
+
+EXPORT_SYMBOL(nf_conntrack_protocol_udp4);
+EXPORT_SYMBOL(nf_conntrack_protocol_udp6);
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
new file mode 100644
index 0000000..45224db
--- /dev/null
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -0,0 +1,869 @@
+/* This file contains all the functions required for the standalone
+   nf_conntrack module.
+
+   These are not required by the compatibility layer.
+*/
+
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *	- generalize L3 protocol dependent part.
+ *
+ * Derived from net/ipv4/netfilter/ip_conntrack_standalone.c
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/percpu.h>
+#include <linux/netdevice.h>
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+
+#define ASSERT_READ_LOCK(x)
+#define ASSERT_WRITE_LOCK(x)
+
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_l3proto.h>
+#include <net/netfilter/nf_conntrack_protocol.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <linux/netfilter_ipv4/listhelp.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+MODULE_LICENSE("GPL");
+
+extern atomic_t nf_conntrack_count;
+DECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);
+
+static int kill_l3proto(struct nf_conn *i, void *data)
+{
+	return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == 
+			((struct nf_conntrack_l3proto *)data)->l3proto);
+}
+
+static int kill_proto(struct nf_conn *i, void *data)
+{
+	struct nf_conntrack_protocol *proto;
+	proto = (struct nf_conntrack_protocol *)data;
+	return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == 
+			proto->proto) &&
+	       (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num ==
+			proto->l3proto);
+}
+
+#ifdef CONFIG_PROC_FS
+static int
+print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
+	    struct nf_conntrack_l3proto *l3proto,
+	    struct nf_conntrack_protocol *proto)
+{
+	return l3proto->print_tuple(s, tuple) || proto->print_tuple(s, tuple);
+}
+
+#ifdef CONFIG_NF_CT_ACCT
+static unsigned int
+seq_print_counters(struct seq_file *s,
+		   const struct ip_conntrack_counter *counter)
+{
+	return seq_printf(s, "packets=%llu bytes=%llu ",
+			  (unsigned long long)counter->packets,
+			  (unsigned long long)counter->bytes);
+}
+#else
+#define seq_print_counters(x, y)	0
+#endif
+
+struct ct_iter_state {
+	unsigned int bucket;
+};
+
+static struct list_head *ct_get_first(struct seq_file *seq)
+{
+	struct ct_iter_state *st = seq->private;
+
+	for (st->bucket = 0;
+	     st->bucket < nf_conntrack_htable_size;
+	     st->bucket++) {
+		if (!list_empty(&nf_conntrack_hash[st->bucket]))
+			return nf_conntrack_hash[st->bucket].next;
+	}
+	return NULL;
+}
+
+static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head)
+{
+	struct ct_iter_state *st = seq->private;
+
+	head = head->next;
+	while (head == &nf_conntrack_hash[st->bucket]) {
+		if (++st->bucket >= nf_conntrack_htable_size)
+			return NULL;
+		head = nf_conntrack_hash[st->bucket].next;
+	}
+	return head;
+}
+
+static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct list_head *head = ct_get_first(seq);
+
+	if (head)
+		while (pos && (head = ct_get_next(seq, head)))
+			pos--;
+	return pos ? NULL : head;
+}
+
+static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	read_lock_bh(&nf_conntrack_lock);
+	return ct_get_idx(seq, *pos);
+}
+
+static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	(*pos)++;
+	return ct_get_next(s, v);
+}
+
+static void ct_seq_stop(struct seq_file *s, void *v)
+{
+	read_unlock_bh(&nf_conntrack_lock);
+}
+
+/* return 0 on success, 1 in case of error */
+static int ct_seq_show(struct seq_file *s, void *v)
+{
+	const struct nf_conntrack_tuple_hash *hash = v;
+	const struct nf_conn *conntrack = nf_ct_tuplehash_to_ctrack(hash);
+	struct nf_conntrack_l3proto *l3proto;
+	struct nf_conntrack_protocol *proto;
+
+	ASSERT_READ_LOCK(&nf_conntrack_lock);
+	NF_CT_ASSERT(conntrack);
+
+	/* we only want to print DIR_ORIGINAL */
+	if (NF_CT_DIRECTION(hash))
+		return 0;
+
+	l3proto = nf_ct_find_l3proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+				     .tuple.src.l3num);
+
+	NF_CT_ASSERT(l3proto);
+	proto = nf_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+				 .tuple.src.l3num,
+				 conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+				 .tuple.dst.protonum);
+	NF_CT_ASSERT(proto);
+
+	if (seq_printf(s, "%-8s %u %-8s %u %ld ",
+		       l3proto->name,
+		       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num,
+		       proto->name,
+		       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
+		       timer_pending(&conntrack->timeout)
+		       ? (long)(conntrack->timeout.expires - jiffies)/HZ : 0) != 0)
+		return -ENOSPC;
+
+	if (l3proto->print_conntrack(s, conntrack))
+		return -ENOSPC;
+
+	if (proto->print_conntrack(s, conntrack))
+		return -ENOSPC;
+
+	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+			l3proto, proto))
+		return -ENOSPC;
+
+	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL]))
+		return -ENOSPC;
+
+	if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
+		if (seq_printf(s, "[UNREPLIED] "))
+			return -ENOSPC;
+
+	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
+			l3proto, proto))
+		return -ENOSPC;
+
+	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY]))
+		return -ENOSPC;
+
+	if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
+		if (seq_printf(s, "[ASSURED] "))
+			return -ENOSPC;
+
+#if defined(CONFIG_NF_CONNTRACK_MARK)
+	if (seq_printf(s, "mark=%u ", conntrack->mark))
+		return -ENOSPC;
+#endif
+
+	if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
+		return -ENOSPC;
+	
+	return 0;
+}
+
+static struct seq_operations ct_seq_ops = {
+	.start = ct_seq_start,
+	.next  = ct_seq_next,
+	.stop  = ct_seq_stop,
+	.show  = ct_seq_show
+};
+
+static int ct_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	struct ct_iter_state *st;
+	int ret;
+
+	st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
+	if (st == NULL)
+		return -ENOMEM;
+	ret = seq_open(file, &ct_seq_ops);
+	if (ret)
+		goto out_free;
+	seq          = file->private_data;
+	seq->private = st;
+	memset(st, 0, sizeof(struct ct_iter_state));
+	return ret;
+out_free:
+	kfree(st);
+	return ret;
+}
+
+static struct file_operations ct_file_ops = {
+	.owner   = THIS_MODULE,
+	.open    = ct_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release_private,
+};
+
+/* expects */
+static void *exp_seq_start(struct seq_file *s, loff_t *pos)
+{
+	struct list_head *e = &nf_conntrack_expect_list;
+	loff_t i;
+
+	/* strange seq_file api calls stop even if we fail,
+	 * thus we need to grab lock since stop unlocks */
+	read_lock_bh(&nf_conntrack_lock);
+
+	if (list_empty(e))
+		return NULL;
+
+	for (i = 0; i <= *pos; i++) {
+		e = e->next;
+		if (e == &nf_conntrack_expect_list)
+			return NULL;
+	}
+	return e;
+}
+
+static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	struct list_head *e = v;
+
+	++*pos;
+	e = e->next;
+
+	if (e == &nf_conntrack_expect_list)
+		return NULL;
+
+	return e;
+}
+
+static void exp_seq_stop(struct seq_file *s, void *v)
+{
+	read_unlock_bh(&nf_conntrack_lock);
+}
+
+static int exp_seq_show(struct seq_file *s, void *v)
+{
+	struct nf_conntrack_expect *expect = v;
+
+	if (expect->timeout.function)
+		seq_printf(s, "%ld ", timer_pending(&expect->timeout)
+			   ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
+	else
+		seq_printf(s, "- ");
+	seq_printf(s, "l3proto = %u proto=%u ",
+		   expect->tuple.src.l3num,
+		   expect->tuple.dst.protonum);
+	print_tuple(s, &expect->tuple,
+		    nf_ct_find_l3proto(expect->tuple.src.l3num),
+		    nf_ct_find_proto(expect->tuple.src.l3num,
+				     expect->tuple.dst.protonum));
+	return seq_putc(s, '\n');
+}
+
+static struct seq_operations exp_seq_ops = {
+	.start = exp_seq_start,
+	.next = exp_seq_next,
+	.stop = exp_seq_stop,
+	.show = exp_seq_show
+};
+
+static int exp_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &exp_seq_ops);
+}
+
+static struct file_operations exp_file_ops = {
+	.owner   = THIS_MODULE,
+	.open    = exp_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release
+};
+
+static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	int cpu;
+
+	if (*pos == 0)
+		return SEQ_START_TOKEN;
+
+	for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
+		if (!cpu_possible(cpu))
+			continue;
+		*pos = cpu + 1;
+		return &per_cpu(nf_conntrack_stat, cpu);
+	}
+
+	return NULL;
+}
+
+static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	int cpu;
+
+	for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
+		if (!cpu_possible(cpu))
+			continue;
+		*pos = cpu + 1;
+		return &per_cpu(nf_conntrack_stat, cpu);
+	}
+
+	return NULL;
+}
+
+static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int ct_cpu_seq_show(struct seq_file *seq, void *v)
+{
+	unsigned int nr_conntracks = atomic_read(&nf_conntrack_count);
+	struct ip_conntrack_stat *st = v;
+
+	if (v == SEQ_START_TOKEN) {
+		seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete\n");
+		return 0;
+	}
+
+	seq_printf(seq, "%08x  %08x %08x %08x %08x %08x %08x %08x "
+			"%08x %08x %08x %08x %08x  %08x %08x %08x \n",
+		   nr_conntracks,
+		   st->searched,
+		   st->found,
+		   st->new,
+		   st->invalid,
+		   st->ignore,
+		   st->delete,
+		   st->delete_list,
+		   st->insert,
+		   st->insert_failed,
+		   st->drop,
+		   st->early_drop,
+		   st->error,
+
+		   st->expect_new,
+		   st->expect_create,
+		   st->expect_delete
+		);
+	return 0;
+}
+
+static struct seq_operations ct_cpu_seq_ops = {
+	.start	= ct_cpu_seq_start,
+	.next	= ct_cpu_seq_next,
+	.stop	= ct_cpu_seq_stop,
+	.show	= ct_cpu_seq_show,
+};
+
+static int ct_cpu_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ct_cpu_seq_ops);
+}
+
+static struct file_operations ct_cpu_seq_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = ct_cpu_seq_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release_private,
+};
+#endif /* CONFIG_PROC_FS */
+
+/* Sysctl support */
+
+#ifdef CONFIG_SYSCTL
+
+/* From nf_conntrack_core.c */
+extern int nf_conntrack_max;
+extern unsigned int nf_conntrack_htable_size;
+
+/* From nf_conntrack_proto_tcp.c */
+extern unsigned long nf_ct_tcp_timeout_syn_sent;
+extern unsigned long nf_ct_tcp_timeout_syn_recv;
+extern unsigned long nf_ct_tcp_timeout_established;
+extern unsigned long nf_ct_tcp_timeout_fin_wait;
+extern unsigned long nf_ct_tcp_timeout_close_wait;
+extern unsigned long nf_ct_tcp_timeout_last_ack;
+extern unsigned long nf_ct_tcp_timeout_time_wait;
+extern unsigned long nf_ct_tcp_timeout_close;
+extern unsigned long nf_ct_tcp_timeout_max_retrans;
+extern int nf_ct_tcp_loose;
+extern int nf_ct_tcp_be_liberal;
+extern int nf_ct_tcp_max_retrans;
+
+/* From nf_conntrack_proto_udp.c */
+extern unsigned long nf_ct_udp_timeout;
+extern unsigned long nf_ct_udp_timeout_stream;
+
+/* From nf_conntrack_proto_generic.c */
+extern unsigned long nf_ct_generic_timeout;
+
+/* Log invalid packets of a given protocol */
+static int log_invalid_proto_min = 0;
+static int log_invalid_proto_max = 255;
+
+static struct ctl_table_header *nf_ct_sysctl_header;
+
+static ctl_table nf_ct_sysctl_table[] = {
+	{
+		.ctl_name	= NET_NF_CONNTRACK_MAX,
+		.procname	= "nf_conntrack_max",
+		.data		= &nf_conntrack_max,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_COUNT,
+		.procname	= "nf_conntrack_count",
+		.data		= &nf_conntrack_count,
+		.maxlen		= sizeof(int),
+		.mode		= 0444,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name       = NET_NF_CONNTRACK_BUCKETS,
+		.procname       = "nf_conntrack_buckets",
+		.data           = &nf_conntrack_htable_size,
+		.maxlen         = sizeof(unsigned int),
+		.mode           = 0444,
+		.proc_handler   = &proc_dointvec,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
+		.procname	= "nf_conntrack_tcp_timeout_syn_sent",
+		.data		= &nf_ct_tcp_timeout_syn_sent,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,
+		.procname	= "nf_conntrack_tcp_timeout_syn_recv",
+		.data		= &nf_ct_tcp_timeout_syn_recv,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,
+		.procname	= "nf_conntrack_tcp_timeout_established",
+		.data		= &nf_ct_tcp_timeout_established,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,
+		.procname	= "nf_conntrack_tcp_timeout_fin_wait",
+		.data		= &nf_ct_tcp_timeout_fin_wait,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,
+		.procname	= "nf_conntrack_tcp_timeout_close_wait",
+		.data		= &nf_ct_tcp_timeout_close_wait,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,
+		.procname	= "nf_conntrack_tcp_timeout_last_ack",
+		.data		= &nf_ct_tcp_timeout_last_ack,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,
+		.procname	= "nf_conntrack_tcp_timeout_time_wait",
+		.data		= &nf_ct_tcp_timeout_time_wait,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,
+		.procname	= "nf_conntrack_tcp_timeout_close",
+		.data		= &nf_ct_tcp_timeout_close,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_UDP_TIMEOUT,
+		.procname	= "nf_conntrack_udp_timeout",
+		.data		= &nf_ct_udp_timeout,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM,
+		.procname	= "nf_conntrack_udp_timeout_stream",
+		.data		= &nf_ct_udp_timeout_stream,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_GENERIC_TIMEOUT,
+		.procname	= "nf_conntrack_generic_timeout",
+		.data		= &nf_ct_generic_timeout,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_LOG_INVALID,
+		.procname	= "nf_conntrack_log_invalid",
+		.data		= &nf_ct_log_invalid,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &log_invalid_proto_min,
+		.extra2		= &log_invalid_proto_max,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS,
+		.procname	= "nf_conntrack_tcp_timeout_max_retrans",
+		.data		= &nf_ct_tcp_timeout_max_retrans,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_LOOSE,
+		.procname	= "nf_conntrack_tcp_loose",
+		.data		= &nf_ct_tcp_loose,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_BE_LIBERAL,
+		.procname       = "nf_conntrack_tcp_be_liberal",
+		.data           = &nf_ct_tcp_be_liberal,
+		.maxlen         = sizeof(unsigned int),
+		.mode           = 0644,
+		.proc_handler   = &proc_dointvec,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_TCP_MAX_RETRANS,
+		.procname	= "nf_conntrack_tcp_max_retrans",
+		.data		= &nf_ct_tcp_max_retrans,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+
+	{ .ctl_name = 0 }
+};
+
+#define NET_NF_CONNTRACK_MAX 2089
+
+static ctl_table nf_ct_netfilter_table[] = {
+	{
+		.ctl_name	= NET_NETFILTER,
+		.procname	= "netfilter",
+		.mode		= 0555,
+		.child		= nf_ct_sysctl_table,
+	},
+	{
+		.ctl_name	= NET_NF_CONNTRACK_MAX,
+		.procname	= "nf_conntrack_max",
+		.data		= &nf_conntrack_max,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table nf_ct_net_table[] = {
+	{
+		.ctl_name	= CTL_NET,
+		.procname	= "net",
+		.mode		= 0555,
+		.child		= nf_ct_netfilter_table,
+	},
+	{ .ctl_name = 0 }
+};
+EXPORT_SYMBOL(nf_ct_log_invalid);
+#endif /* CONFIG_SYSCTL */
+
+static int init_or_cleanup(int init)
+{
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc, *proc_exp, *proc_stat;
+#endif
+	int ret = 0;
+
+	if (!init) goto cleanup;
+
+	ret = nf_conntrack_init();
+	if (ret < 0)
+		goto cleanup_nothing;
+
+#ifdef CONFIG_PROC_FS
+	proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops);
+	if (!proc) goto cleanup_init;
+
+	proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440,
+					&exp_file_ops);
+	if (!proc_exp) goto cleanup_proc;
+
+	proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat);
+	if (!proc_stat)
+		goto cleanup_proc_exp;
+
+	proc_stat->proc_fops = &ct_cpu_seq_fops;
+	proc_stat->owner = THIS_MODULE;
+#endif
+#ifdef CONFIG_SYSCTL
+	nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
+	if (nf_ct_sysctl_header == NULL) {
+		printk("nf_conntrack: can't register to sysctl.\n");
+		ret = -ENOMEM;
+		goto cleanup_proc_stat;
+	}
+#endif
+
+	return ret;
+
+ cleanup:
+#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(nf_ct_sysctl_header);
+ cleanup_proc_stat:
+#endif
+#ifdef CONFIG_PROC_FS
+	proc_net_remove("nf_conntrack_stat");
+ cleanup_proc_exp:
+	proc_net_remove("nf_conntrack_expect");
+ cleanup_proc:
+	proc_net_remove("nf_conntrack");
+ cleanup_init:
+#endif /* CNFIG_PROC_FS */
+	nf_conntrack_cleanup();
+ cleanup_nothing:
+	return ret;
+}
+
+int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
+{
+	int ret = 0;
+
+	write_lock_bh(&nf_conntrack_lock);
+	if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_generic_l3proto) {
+		ret = -EBUSY;
+		goto out;
+	}
+	nf_ct_l3protos[proto->l3proto] = proto;
+out:
+	write_unlock_bh(&nf_conntrack_lock);
+
+	return ret;
+}
+
+void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
+{
+	write_lock_bh(&nf_conntrack_lock);
+	nf_ct_l3protos[proto->l3proto] = &nf_conntrack_generic_l3proto;
+	write_unlock_bh(&nf_conntrack_lock);
+	
+	/* Somebody could be still looking at the proto in bh. */
+	synchronize_net();
+
+	/* Remove all contrack entries for this protocol */
+	nf_ct_iterate_cleanup(kill_l3proto, proto);
+}
+
+/* FIXME: Allow NULL functions and sub in pointers to generic for
+   them. --RR */
+int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto)
+{
+	int ret = 0;
+
+retry:
+	write_lock_bh(&nf_conntrack_lock);
+	if (nf_ct_protos[proto->l3proto]) {
+		if (nf_ct_protos[proto->l3proto][proto->proto]
+				!= &nf_conntrack_generic_protocol) {
+			ret = -EBUSY;
+			goto out_unlock;
+		}
+	} else {
+		/* l3proto may be loaded latter. */
+		struct nf_conntrack_protocol **proto_array;
+		int i;
+
+		write_unlock_bh(&nf_conntrack_lock);
+
+		proto_array = (struct nf_conntrack_protocol **)
+				kmalloc(MAX_NF_CT_PROTO *
+					 sizeof(struct nf_conntrack_protocol *),
+					GFP_KERNEL);
+		if (proto_array == NULL) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		for (i = 0; i < MAX_NF_CT_PROTO; i++)
+			proto_array[i] = &nf_conntrack_generic_protocol;
+
+		write_lock_bh(&nf_conntrack_lock);
+		if (nf_ct_protos[proto->l3proto]) {
+			/* bad timing, but no problem */
+			write_unlock_bh(&nf_conntrack_lock);
+			kfree(proto_array);
+		} else {
+			nf_ct_protos[proto->l3proto] = proto_array;
+			write_unlock_bh(&nf_conntrack_lock);
+		}
+
+		/*
+		 * Just once because array is never freed until unloading
+		 * nf_conntrack.ko
+		 */
+		goto retry;
+	}
+
+	nf_ct_protos[proto->l3proto][proto->proto] = proto;
+
+out_unlock:
+	write_unlock_bh(&nf_conntrack_lock);
+out:
+	return ret;
+}
+
+void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto)
+{
+	write_lock_bh(&nf_conntrack_lock);
+	nf_ct_protos[proto->l3proto][proto->proto]
+		= &nf_conntrack_generic_protocol;
+	write_unlock_bh(&nf_conntrack_lock);
+	
+	/* Somebody could be still looking at the proto in bh. */
+	synchronize_net();
+
+	/* Remove all contrack entries for this protocol */
+	nf_ct_iterate_cleanup(kill_proto, proto);
+}
+
+static int __init init(void)
+{
+	return init_or_cleanup(1);
+}
+
+static void __exit fini(void)
+{
+	init_or_cleanup(0);
+}
+
+module_init(init);
+module_exit(fini);
+
+/* Some modules need us, but don't depend directly on any symbol.
+   They should call this. */
+void need_nf_conntrack(void)
+{
+}
+
+#ifdef CONFIG_NF_CONNTRACK_EVENTS
+EXPORT_SYMBOL_GPL(nf_conntrack_chain);
+EXPORT_SYMBOL_GPL(nf_conntrack_expect_chain);
+EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier);
+EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
+EXPORT_SYMBOL_GPL(__nf_ct_event_cache_init);
+EXPORT_PER_CPU_SYMBOL_GPL(nf_conntrack_ecache);
+EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events);
+#endif
+EXPORT_SYMBOL(nf_conntrack_l3proto_register);
+EXPORT_SYMBOL(nf_conntrack_l3proto_unregister);
+EXPORT_SYMBOL(nf_conntrack_protocol_register);
+EXPORT_SYMBOL(nf_conntrack_protocol_unregister);
+EXPORT_SYMBOL(nf_ct_invert_tuplepr);
+EXPORT_SYMBOL(nf_conntrack_alter_reply);
+EXPORT_SYMBOL(nf_conntrack_destroyed);
+EXPORT_SYMBOL(need_nf_conntrack);
+EXPORT_SYMBOL(nf_conntrack_helper_register);
+EXPORT_SYMBOL(nf_conntrack_helper_unregister);
+EXPORT_SYMBOL(nf_ct_iterate_cleanup);
+EXPORT_SYMBOL(__nf_ct_refresh_acct);
+EXPORT_SYMBOL(nf_ct_protos);
+EXPORT_SYMBOL(nf_ct_find_proto);
+EXPORT_SYMBOL(nf_ct_l3protos);
+EXPORT_SYMBOL(nf_conntrack_expect_alloc);
+EXPORT_SYMBOL(nf_conntrack_expect_put);
+EXPORT_SYMBOL(nf_conntrack_expect_related);
+EXPORT_SYMBOL(nf_conntrack_unexpect_related);
+EXPORT_SYMBOL(nf_conntrack_tuple_taken);
+EXPORT_SYMBOL(nf_conntrack_htable_size);
+EXPORT_SYMBOL(nf_conntrack_lock);
+EXPORT_SYMBOL(nf_conntrack_hash);
+EXPORT_SYMBOL(nf_conntrack_untracked);
+EXPORT_SYMBOL_GPL(nf_conntrack_find_get);
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+EXPORT_SYMBOL(nf_conntrack_tcp_update);
+#endif
+EXPORT_SYMBOL(__nf_conntrack_confirm);
+EXPORT_SYMBOL(nf_ct_get_tuple);
+EXPORT_SYMBOL(nf_ct_invert_tuple);
+EXPORT_SYMBOL(nf_conntrack_in);
+EXPORT_SYMBOL(__nf_conntrack_attach);
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 4bc27a6..83f4c53 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -128,7 +128,7 @@
 	memset(NFA_DATA(nfa) + attrlen, 0, NFA_ALIGN(size) - size);
 }
 
-int nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len)
+void nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len)
 {
 	memset(tb, 0, sizeof(struct nfattr *) * maxattr);
 
@@ -138,8 +138,6 @@
 			tb[flavor-1] = nfa;
 		nfa = NFA_NEXT(nfa, len);
 	}
-
-	return 0;
 }
 
 /**
@@ -242,15 +240,18 @@
 	ss = nfnetlink_get_subsys(type);
 	if (!ss) {
 #ifdef CONFIG_KMOD
-		/* don't call nfnl_shunlock, since it would reenter
-		 * with further packet processing */
-		up(&nfnl_sem);
-		request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
-		nfnl_shlock();
-		ss = nfnetlink_get_subsys(type);
+		if (cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
+			/* don't call nfnl_shunlock, since it would reenter
+			 * with further packet processing */
+			up(&nfnl_sem);
+			request_module("nfnetlink-subsys-%d",
+					NFNL_SUBSYS_ID(type));
+			nfnl_shlock();
+			ss = nfnetlink_get_subsys(type);
+		}
 		if (!ss)
 #endif
-		goto err_inval;
+			goto err_inval;
 	}
 
 	nc = nfnetlink_find_client(type, ss);
diff --git a/net/netlink/Makefile b/net/netlink/Makefile
index 39d9c2d..e3589c2 100644
--- a/net/netlink/Makefile
+++ b/net/netlink/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the netlink driver.
 #
 
-obj-y  				:= af_netlink.o
+obj-y  				:= af_netlink.o attr.o genetlink.o
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 5ca2835..8c38ee6 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -58,6 +58,7 @@
 
 #include <net/sock.h>
 #include <net/scm.h>
+#include <net/netlink.h>
 
 #define Nprintk(a...)
 #define NLGRPSZ(x)	(ALIGN(x, sizeof(unsigned long) * 8) / 8)
@@ -427,7 +428,8 @@
 
 	spin_lock(&nlk->cb_lock);
 	if (nlk->cb) {
-		nlk->cb->done(nlk->cb);
+		if (nlk->cb->done)
+			nlk->cb->done(nlk->cb);
 		netlink_destroy_callback(nlk->cb);
 		nlk->cb = NULL;
 	}
@@ -1322,7 +1324,8 @@
 	skb_queue_tail(&sk->sk_receive_queue, skb);
 	sk->sk_data_ready(sk, skb->len);
 
-	cb->done(cb);
+	if (cb->done)
+		cb->done(cb);
 	nlk->cb = NULL;
 	spin_unlock(&nlk->cb_lock);
 
@@ -1409,6 +1412,94 @@
 	netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
 }
 
+static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
+						     struct nlmsghdr *, int *))
+{
+	unsigned int total_len;
+	struct nlmsghdr *nlh;
+	int err;
+
+	while (skb->len >= nlmsg_total_size(0)) {
+		nlh = (struct nlmsghdr *) skb->data;
+
+		if (skb->len < nlh->nlmsg_len)
+			return 0;
+
+		total_len = min(NLMSG_ALIGN(nlh->nlmsg_len), skb->len);
+
+		if (cb(skb, nlh, &err) < 0) {
+			/* Not an error, but we have to interrupt processing
+			 * here. Note: that in this case we do not pull
+			 * message from skb, it will be processed later.
+			 */
+			if (err == 0)
+				return -1;
+			netlink_ack(skb, nlh, err);
+		} else if (nlh->nlmsg_flags & NLM_F_ACK)
+			netlink_ack(skb, nlh, 0);
+
+		skb_pull(skb, total_len);
+	}
+
+	return 0;
+}
+
+/**
+ * nelink_run_queue - Process netlink receive queue.
+ * @sk: Netlink socket containing the queue
+ * @qlen: Place to store queue length upon entry
+ * @cb: Callback function invoked for each netlink message found
+ *
+ * Processes as much as there was in the queue upon entry and invokes
+ * a callback function for each netlink message found. The callback
+ * function may refuse a message by returning a negative error code
+ * but setting the error pointer to 0 in which case this function
+ * returns with a qlen != 0.
+ *
+ * qlen must be initialized to 0 before the initial entry, afterwards
+ * the function may be called repeatedly until qlen reaches 0.
+ */
+void netlink_run_queue(struct sock *sk, unsigned int *qlen,
+		       int (*cb)(struct sk_buff *, struct nlmsghdr *, int *))
+{
+	struct sk_buff *skb;
+
+	if (!*qlen || *qlen > skb_queue_len(&sk->sk_receive_queue))
+		*qlen = skb_queue_len(&sk->sk_receive_queue);
+
+	for (; *qlen; (*qlen)--) {
+		skb = skb_dequeue(&sk->sk_receive_queue);
+		if (netlink_rcv_skb(skb, cb)) {
+			if (skb->len)
+				skb_queue_head(&sk->sk_receive_queue, skb);
+			else {
+				kfree_skb(skb);
+				(*qlen)--;
+			}
+			break;
+		}
+
+		kfree_skb(skb);
+	}
+}
+
+/**
+ * netlink_queue_skip - Skip netlink message while processing queue.
+ * @nlh: Netlink message to be skipped
+ * @skb: Socket buffer containing the netlink messages.
+ *
+ * Pulls the given netlink message off the socket buffer so the next
+ * call to netlink_queue_run() will not reconsider the message.
+ */
+void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb)
+{
+	int msglen = NLMSG_ALIGN(nlh->nlmsg_len);
+
+	if (msglen > skb->len)
+		msglen = skb->len;
+
+	skb_pull(skb, msglen);
+}
 
 #ifdef CONFIG_PROC_FS
 struct nl_seq_iter {
@@ -1657,6 +1748,8 @@
 core_initcall(netlink_proto_init);
 
 EXPORT_SYMBOL(netlink_ack);
+EXPORT_SYMBOL(netlink_run_queue);
+EXPORT_SYMBOL(netlink_queue_skip);
 EXPORT_SYMBOL(netlink_broadcast);
 EXPORT_SYMBOL(netlink_dump_start);
 EXPORT_SYMBOL(netlink_kernel_create);
diff --git a/net/netlink/attr.c b/net/netlink/attr.c
new file mode 100644
index 0000000..fffef4a
--- /dev/null
+++ b/net/netlink/attr.c
@@ -0,0 +1,328 @@
+/*
+ * NETLINK      Netlink attributes
+ *
+ * 		Authors:	Thomas Graf <tgraf@suug.ch>
+ * 				Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <net/netlink.h>
+
+static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = {
+	[NLA_U8]	= sizeof(u8),
+	[NLA_U16]	= sizeof(u16),
+	[NLA_U32]	= sizeof(u32),
+	[NLA_U64]	= sizeof(u64),
+	[NLA_STRING]	= 1,
+	[NLA_NESTED]	= NLA_HDRLEN,
+};
+
+static int validate_nla(struct nlattr *nla, int maxtype,
+			struct nla_policy *policy)
+{
+	struct nla_policy *pt;
+	int minlen = 0;
+
+	if (nla->nla_type <= 0 || nla->nla_type > maxtype)
+		return 0;
+
+	pt = &policy[nla->nla_type];
+
+	BUG_ON(pt->type > NLA_TYPE_MAX);
+
+	if (pt->minlen)
+		minlen = pt->minlen;
+	else if (pt->type != NLA_UNSPEC)
+		minlen = nla_attr_minlen[pt->type];
+
+	if (pt->type == NLA_FLAG && nla_len(nla) > 0)
+		return -ERANGE;
+
+	if (nla_len(nla) < minlen)
+		return -ERANGE;
+
+	return 0;
+}
+
+/**
+ * nla_validate - Validate a stream of attributes
+ * @head: head of attribute stream
+ * @len: length of attribute stream
+ * @maxtype: maximum attribute type to be expected
+ * @policy: validation policy
+ *
+ * Validates all attributes in the specified attribute stream against the
+ * specified policy. Attributes with a type exceeding maxtype will be
+ * ignored. See documenation of struct nla_policy for more details.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int nla_validate(struct nlattr *head, int len, int maxtype,
+		 struct nla_policy *policy)
+{
+	struct nlattr *nla;
+	int rem, err;
+
+	nla_for_each_attr(nla, head, len, rem) {
+		err = validate_nla(nla, maxtype, policy);
+		if (err < 0)
+			goto errout;
+	}
+
+	err = 0;
+errout:
+	return err;
+}
+
+/**
+ * nla_parse - Parse a stream of attributes into a tb buffer
+ * @tb: destination array with maxtype+1 elements
+ * @maxtype: maximum attribute type to be expected
+ * @head: head of attribute stream
+ * @len: length of attribute stream
+ *
+ * Parses a stream of attributes and stores a pointer to each attribute in
+ * the tb array accessable via the attribute type. Attributes with a type
+ * exceeding maxtype will be silently ignored for backwards compatibility
+ * reasons. policy may be set to NULL if no validation is required.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
+	      struct nla_policy *policy)
+{
+	struct nlattr *nla;
+	int rem, err;
+
+	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+
+	nla_for_each_attr(nla, head, len, rem) {
+		u16 type = nla->nla_type;
+
+		if (type > 0 && type <= maxtype) {
+			if (policy) {
+				err = validate_nla(nla, maxtype, policy);
+				if (err < 0)
+					goto errout;
+			}
+
+			tb[type] = nla;
+		}
+	}
+
+	if (unlikely(rem > 0))
+		printk(KERN_WARNING "netlink: %d bytes leftover after parsing "
+		       "attributes.\n", rem);
+
+	err = 0;
+errout:
+	return err;
+}
+
+/**
+ * nla_find - Find a specific attribute in a stream of attributes
+ * @head: head of attribute stream
+ * @len: length of attribute stream
+ * @attrtype: type of attribute to look for
+ *
+ * Returns the first attribute in the stream matching the specified type.
+ */
+struct nlattr *nla_find(struct nlattr *head, int len, int attrtype)
+{
+	struct nlattr *nla;
+	int rem;
+
+	nla_for_each_attr(nla, head, len, rem)
+		if (nla->nla_type == attrtype)
+			return nla;
+
+	return NULL;
+}
+
+/**
+ * nla_strlcpy - Copy string attribute payload into a sized buffer
+ * @dst: where to copy the string to
+ * @src: attribute to copy the string from
+ * @dstsize: size of destination buffer
+ *
+ * Copies at most dstsize - 1 bytes into the destination buffer.
+ * The result is always a valid NUL-terminated string. Unlike
+ * strlcpy the destination buffer is always padded out.
+ *
+ * Returns the length of the source buffer.
+ */
+size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
+{
+	size_t srclen = nla_len(nla);
+	char *src = nla_data(nla);
+
+	if (srclen > 0 && src[srclen - 1] == '\0')
+		srclen--;
+
+	if (dstsize > 0) {
+		size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
+
+		memset(dst, 0, dstsize);
+		memcpy(dst, src, len);
+	}
+
+	return srclen;
+}
+
+/**
+ * nla_memcpy - Copy a netlink attribute into another memory area
+ * @dest: where to copy to memcpy
+ * @src: netlink attribute to copy from
+ * @count: size of the destination area
+ *
+ * Note: The number of bytes copied is limited by the length of
+ *       attribute's payload. memcpy
+ *
+ * Returns the number of bytes copied.
+ */
+int nla_memcpy(void *dest, struct nlattr *src, int count)
+{
+	int minlen = min_t(int, count, nla_len(src));
+
+	memcpy(dest, nla_data(src), minlen);
+
+	return minlen;
+}
+
+/**
+ * nla_memcmp - Compare an attribute with sized memory area
+ * @nla: netlink attribute
+ * @data: memory area
+ * @size: size of memory area
+ */
+int nla_memcmp(const struct nlattr *nla, const void *data,
+			     size_t size)
+{
+	int d = nla_len(nla) - size;
+
+	if (d == 0)
+		d = memcmp(nla_data(nla), data, size);
+
+	return d;
+}
+
+/**
+ * nla_strcmp - Compare a string attribute against a string
+ * @nla: netlink string attribute
+ * @str: another string
+ */
+int nla_strcmp(const struct nlattr *nla, const char *str)
+{
+	int len = strlen(str) + 1;
+	int d = nla_len(nla) - len;
+
+	if (d == 0)
+		d = memcmp(nla_data(nla), str, len);
+
+	return d;
+}
+
+/**
+ * __nla_reserve - reserve room for attribute on the skb
+ * @skb: socket buffer to reserve room on
+ * @attrtype: attribute type
+ * @attrlen: length of attribute payload
+ *
+ * Adds a netlink attribute header to a socket buffer and reserves
+ * room for the payload but does not copy it.
+ *
+ * The caller is responsible to ensure that the skb provides enough
+ * tailroom for the attribute header and payload.
+ */
+struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
+{
+	struct nlattr *nla;
+
+	nla = (struct nlattr *) skb_put(skb, nla_total_size(attrlen));
+	nla->nla_type = attrtype;
+	nla->nla_len = nla_attr_size(attrlen);
+
+	memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
+
+	return nla;
+}
+
+/**
+ * nla_reserve - reserve room for attribute on the skb
+ * @skb: socket buffer to reserve room on
+ * @attrtype: attribute type
+ * @attrlen: length of attribute payload
+ *
+ * Adds a netlink attribute header to a socket buffer and reserves
+ * room for the payload but does not copy it.
+ *
+ * Returns NULL if the tailroom of the skb is insufficient to store
+ * the attribute header and payload.
+ */
+struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
+{
+	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
+		return NULL;
+
+	return __nla_reserve(skb, attrtype, attrlen);
+}
+
+/**
+ * __nla_put - Add a netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @attrlen: length of attribute payload
+ * @data: head of attribute payload
+ *
+ * The caller is responsible to ensure that the skb provides enough
+ * tailroom for the attribute header and payload.
+ */
+void __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
+			     const void *data)
+{
+	struct nlattr *nla;
+
+	nla = __nla_reserve(skb, attrtype, attrlen);
+	memcpy(nla_data(nla), data, attrlen);
+}
+
+
+/**
+ * nla_put - Add a netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @attrlen: length of attribute payload
+ * @data: head of attribute payload
+ *
+ * Returns -1 if the tailroom of the skb is insufficient to store
+ * the attribute header and payload.
+ */
+int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
+{
+	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
+		return -1;
+
+	__nla_put(skb, attrtype, attrlen, data);
+	return 0;
+}
+
+
+EXPORT_SYMBOL(nla_validate);
+EXPORT_SYMBOL(nla_parse);
+EXPORT_SYMBOL(nla_find);
+EXPORT_SYMBOL(nla_strlcpy);
+EXPORT_SYMBOL(__nla_reserve);
+EXPORT_SYMBOL(nla_reserve);
+EXPORT_SYMBOL(__nla_put);
+EXPORT_SYMBOL(nla_put);
+EXPORT_SYMBOL(nla_memcpy);
+EXPORT_SYMBOL(nla_memcmp);
+EXPORT_SYMBOL(nla_strcmp);
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
new file mode 100644
index 0000000..287cfcc
--- /dev/null
+++ b/net/netlink/genetlink.c
@@ -0,0 +1,579 @@
+/*
+ * NETLINK      Generic Netlink Family
+ *
+ * 		Authors:	Jamal Hadi Salim
+ * 				Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/genetlink.h>
+
+struct sock *genl_sock = NULL;
+
+static DECLARE_MUTEX(genl_sem); /* serialization of message processing */
+
+static void genl_lock(void)
+{
+	down(&genl_sem);
+}
+
+static int genl_trylock(void)
+{
+	return down_trylock(&genl_sem);
+}
+
+static void genl_unlock(void)
+{
+	up(&genl_sem);
+
+	if (genl_sock && genl_sock->sk_receive_queue.qlen)
+		genl_sock->sk_data_ready(genl_sock, 0);
+}
+
+#define GENL_FAM_TAB_SIZE	16
+#define GENL_FAM_TAB_MASK	(GENL_FAM_TAB_SIZE - 1)
+
+static struct list_head family_ht[GENL_FAM_TAB_SIZE];
+
+static int genl_ctrl_event(int event, void *data);
+
+static inline unsigned int genl_family_hash(unsigned int id)
+{
+	return id & GENL_FAM_TAB_MASK;
+}
+
+static inline struct list_head *genl_family_chain(unsigned int id)
+{
+	return &family_ht[genl_family_hash(id)];
+}
+
+static struct genl_family *genl_family_find_byid(unsigned int id)
+{
+	struct genl_family *f;
+
+	list_for_each_entry(f, genl_family_chain(id), family_list)
+		if (f->id == id)
+			return f;
+
+	return NULL;
+}
+
+static struct genl_family *genl_family_find_byname(char *name)
+{
+	struct genl_family *f;
+	int i;
+
+	for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
+		list_for_each_entry(f, genl_family_chain(i), family_list)
+			if (strcmp(f->name, name) == 0)
+				return f;
+
+	return NULL;
+}
+
+static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
+{
+	struct genl_ops *ops;
+
+	list_for_each_entry(ops, &family->ops_list, ops_list)
+		if (ops->cmd == cmd)
+			return ops;
+
+	return NULL;
+}
+
+/* Of course we are going to have problems once we hit
+ * 2^16 alive types, but that can only happen by year 2K
+*/
+static inline u16 genl_generate_id(void)
+{
+	static u16 id_gen_idx;
+	int overflowed = 0;
+
+	do {
+		if (id_gen_idx == 0)
+			id_gen_idx = GENL_MIN_ID;
+
+		if (++id_gen_idx > GENL_MAX_ID) {
+			if (!overflowed) {
+				overflowed = 1;
+				id_gen_idx = 0;
+				continue;
+			} else
+				return 0;
+		}
+
+	} while (genl_family_find_byid(id_gen_idx));
+
+	return id_gen_idx;
+}
+
+/**
+ * genl_register_ops - register generic netlink operations
+ * @family: generic netlink family
+ * @ops: operations to be registered
+ *
+ * Registers the specified operations and assigns them to the specified
+ * family. Either a doit or dumpit callback must be specified or the
+ * operation will fail. Only one operation structure per command
+ * identifier may be registered.
+ *
+ * See include/net/genetlink.h for more documenation on the operations
+ * structure.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int genl_register_ops(struct genl_family *family, struct genl_ops *ops)
+{
+	int err = -EINVAL;
+
+	if (ops->dumpit == NULL && ops->doit == NULL)
+		goto errout;
+
+	if (genl_get_cmd(ops->cmd, family)) {
+		err = -EEXIST;
+		goto errout;
+	}
+
+	genl_lock();
+	list_add_tail(&ops->ops_list, &family->ops_list);
+	genl_unlock();
+
+	genl_ctrl_event(CTRL_CMD_NEWOPS, ops);
+	err = 0;
+errout:
+	return err;
+}
+
+/**
+ * genl_unregister_ops - unregister generic netlink operations
+ * @family: generic netlink family
+ * @ops: operations to be unregistered
+ *
+ * Unregisters the specified operations and unassigns them from the
+ * specified family. The operation blocks until the current message
+ * processing has finished and doesn't start again until the
+ * unregister process has finished.
+ *
+ * Note: It is not necessary to unregister all operations before
+ *       unregistering the family, unregistering the family will cause
+ *       all assigned operations to be unregistered automatically.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops)
+{
+	struct genl_ops *rc;
+
+	genl_lock();
+	list_for_each_entry(rc, &family->ops_list, ops_list) {
+		if (rc == ops) {
+			list_del(&ops->ops_list);
+			genl_unlock();
+			genl_ctrl_event(CTRL_CMD_DELOPS, ops);
+			return 0;
+		}
+	}
+	genl_unlock();
+
+	return -ENOENT;
+}
+
+/**
+ * genl_register_family - register a generic netlink family
+ * @family: generic netlink family
+ *
+ * Registers the specified family after validating it first. Only one
+ * family may be registered with the same family name or identifier.
+ * The family id may equal GENL_ID_GENERATE causing an unique id to
+ * be automatically generated and assigned.
+ *
+ * Return 0 on success or a negative error code.
+ */
+int genl_register_family(struct genl_family *family)
+{
+	int err = -EINVAL;
+
+	if (family->id && family->id < GENL_MIN_ID)
+		goto errout;
+
+	if (family->id > GENL_MAX_ID)
+		goto errout;
+
+	INIT_LIST_HEAD(&family->ops_list);
+
+	genl_lock();
+
+	if (genl_family_find_byname(family->name)) {
+		err = -EEXIST;
+		goto errout_locked;
+	}
+
+	if (genl_family_find_byid(family->id)) {
+		err = -EEXIST;
+		goto errout_locked;
+	}
+
+	if (!try_module_get(family->owner)) {
+		err = -EBUSY;
+		goto errout_locked;
+	}
+
+	if (family->id == GENL_ID_GENERATE) {
+		u16 newid = genl_generate_id();
+
+		if (!newid) {
+			err = -ENOMEM;
+			goto errout_locked;
+		}
+
+		family->id = newid;
+	}
+
+	if (family->maxattr) {
+		family->attrbuf = kmalloc((family->maxattr+1) *
+					sizeof(struct nlattr *), GFP_KERNEL);
+		if (family->attrbuf == NULL) {
+			err = -ENOMEM;
+			goto errout;
+		}
+	} else
+		family->attrbuf = NULL;
+
+	list_add_tail(&family->family_list, genl_family_chain(family->id));
+	genl_unlock();
+
+	genl_ctrl_event(CTRL_CMD_NEWFAMILY, family);
+
+	return 0;
+
+errout_locked:
+	genl_unlock();
+errout:
+	return err;
+}
+
+/**
+ * genl_unregister_family - unregister generic netlink family
+ * @family: generic netlink family
+ *
+ * Unregisters the specified family.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int genl_unregister_family(struct genl_family *family)
+{
+	struct genl_family *rc;
+
+	genl_lock();
+
+	list_for_each_entry(rc, genl_family_chain(family->id), family_list) {
+		if (family->id != rc->id || strcmp(rc->name, family->name))
+			continue;
+
+		list_del(&rc->family_list);
+		INIT_LIST_HEAD(&family->ops_list);
+		genl_unlock();
+
+		module_put(family->owner);
+		kfree(family->attrbuf);
+		genl_ctrl_event(CTRL_CMD_DELFAMILY, family);
+		return 0;
+	}
+
+	genl_unlock();
+
+	return -ENOENT;
+}
+
+static inline int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
+			       int *errp)
+{
+	struct genl_ops *ops;
+	struct genl_family *family;
+	struct genl_info info;
+	struct genlmsghdr *hdr = nlmsg_data(nlh);
+	int hdrlen, err = -EINVAL;
+
+	if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
+		goto ignore;
+
+	if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
+		goto ignore;
+
+       	family = genl_family_find_byid(nlh->nlmsg_type);
+	if (family == NULL) {
+		err = -ENOENT;
+		goto errout;
+	}
+
+	hdrlen = GENL_HDRLEN + family->hdrsize;
+	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
+		goto errout;
+
+	ops = genl_get_cmd(hdr->cmd, family);
+	if (ops == NULL) {
+		err = -EOPNOTSUPP;
+		goto errout;
+	}
+
+	if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb)) {
+		err = -EPERM;
+		goto errout;
+	}
+
+	if (nlh->nlmsg_flags & NLM_F_DUMP) {
+		if (ops->dumpit == NULL) {
+			err = -EOPNOTSUPP;
+			goto errout;
+		}
+
+		*errp = err = netlink_dump_start(genl_sock, skb, nlh,
+						 ops->dumpit, NULL);
+		if (err == 0)
+			skb_pull(skb, min(NLMSG_ALIGN(nlh->nlmsg_len),
+					  skb->len));
+		return -1;
+	}
+
+	if (ops->doit == NULL) {
+		err = -EOPNOTSUPP;
+		goto errout;
+	}
+
+	if (family->attrbuf) {
+		err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr,
+				  ops->policy);
+		if (err < 0)
+			goto errout;
+	}
+
+	info.snd_seq = nlh->nlmsg_seq;
+	info.snd_pid = NETLINK_CB(skb).pid;
+	info.nlhdr = nlh;
+	info.genlhdr = nlmsg_data(nlh);
+	info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
+	info.attrs = family->attrbuf;
+
+	*errp = err = ops->doit(skb, &info);
+	return err;
+
+ignore:
+	return 0;
+
+errout:
+	*errp = err;
+	return -1;
+}
+
+static void genl_rcv(struct sock *sk, int len)
+{
+	unsigned int qlen = 0;
+
+	do {
+		if (genl_trylock())
+			return;
+		netlink_run_queue(sk, &qlen, &genl_rcv_msg);
+		genl_unlock();
+	} while (qlen && genl_sock && genl_sock->sk_receive_queue.qlen);
+}
+
+/**************************************************************************
+ * Controller
+ **************************************************************************/
+
+static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
+			  u32 flags, struct sk_buff *skb, u8 cmd)
+{
+	void *hdr;
+
+	hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd,
+			  family->version);
+	if (hdr == NULL)
+		return -1;
+
+	NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name);
+	NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id);
+
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	return genlmsg_cancel(skb, hdr);
+}
+
+static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
+{
+
+	int i, n = 0;
+	struct genl_family *rt;
+	int chains_to_skip = cb->args[0];
+	int fams_to_skip = cb->args[1];
+
+	for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
+		if (i < chains_to_skip)
+			continue;
+		n = 0;
+		list_for_each_entry(rt, genl_family_chain(i), family_list) {
+			if (++n < fams_to_skip)
+				continue;
+			if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid,
+					   cb->nlh->nlmsg_seq, NLM_F_MULTI,
+					   skb, CTRL_CMD_NEWFAMILY) < 0)
+				goto errout;
+		}
+
+		fams_to_skip = 0;
+	}
+
+errout:
+	cb->args[0] = i;
+	cb->args[1] = n;
+
+	return skb->len;
+}
+
+static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
+				      int seq, int cmd)
+{
+	struct sk_buff *skb;
+	int err;
+
+	skb = nlmsg_new(NLMSG_GOODSIZE);
+	if (skb == NULL)
+		return ERR_PTR(-ENOBUFS);
+
+	err = ctrl_fill_info(family, pid, seq, 0, skb, cmd);
+	if (err < 0) {
+		nlmsg_free(skb);
+		return ERR_PTR(err);
+	}
+
+	return skb;
+}
+
+static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = {
+	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
+	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_STRING },
+};
+
+static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
+{
+	struct sk_buff *msg;
+	struct genl_family *res = NULL;
+	int err = -EINVAL;
+
+	if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
+		u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]);
+		res = genl_family_find_byid(id);
+	}
+
+	if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
+		char name[GENL_NAMSIZ];
+
+		if (nla_strlcpy(name, info->attrs[CTRL_ATTR_FAMILY_NAME],
+				GENL_NAMSIZ) >= GENL_NAMSIZ)
+			goto errout;
+
+		res = genl_family_find_byname(name);
+	}
+
+	if (res == NULL) {
+		err = -ENOENT;
+		goto errout;
+	}
+
+	msg = ctrl_build_msg(res, info->snd_pid, info->snd_seq,
+			     CTRL_CMD_NEWFAMILY);
+	if (IS_ERR(msg)) {
+		err = PTR_ERR(msg);
+		goto errout;
+	}
+
+	err = genlmsg_unicast(msg, info->snd_pid);
+errout:
+	return err;
+}
+
+static int genl_ctrl_event(int event, void *data)
+{
+	struct sk_buff *msg;
+
+	if (genl_sock == NULL)
+		return 0;
+
+	switch (event) {
+	case CTRL_CMD_NEWFAMILY:
+	case CTRL_CMD_DELFAMILY:
+		msg = ctrl_build_msg(data, 0, 0, event);
+		if (IS_ERR(msg))
+			return PTR_ERR(msg);
+
+		genlmsg_multicast(msg, 0, GENL_ID_CTRL);
+		break;
+	}
+
+	return 0;
+}
+
+static struct genl_ops genl_ctrl_ops = {
+	.cmd		= CTRL_CMD_GETFAMILY,
+	.doit		= ctrl_getfamily,
+	.dumpit		= ctrl_dumpfamily,
+	.policy		= ctrl_policy,
+};
+
+static struct genl_family genl_ctrl = {
+	.id = GENL_ID_CTRL,
+	.name = "nlctrl",
+	.version = 0x1,
+	.maxattr = CTRL_ATTR_MAX,
+	.owner = THIS_MODULE,
+};
+
+static int __init genl_init(void)
+{
+	int i, err;
+
+	for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
+		INIT_LIST_HEAD(&family_ht[i]);
+
+	err = genl_register_family(&genl_ctrl);
+	if (err < 0)
+		goto errout;
+
+	err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops);
+	if (err < 0)
+		goto errout_register;
+
+	netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
+	genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID,
+					  genl_rcv, THIS_MODULE);
+	if (genl_sock == NULL) {
+		panic("GENL: Cannot initialize generic netlink\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+
+errout_register:
+	genl_unregister_family(&genl_ctrl);
+errout:
+	panic("GENL: Cannot register controller: %d\n", err);
+	return err;
+}
+
+subsys_initcall(genl_init);
+
+EXPORT_SYMBOL(genl_sock);
+EXPORT_SYMBOL(genl_register_ops);
+EXPORT_SYMBOL(genl_unregister_ops);
+EXPORT_SYMBOL(genl_register_family);
+EXPORT_SYMBOL(genl_unregister_family);
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index b18fe50..8631b65 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -240,8 +240,7 @@
 	if ((s = rose_neigh_list) == rose_neigh) {
 		rose_neigh_list = rose_neigh->next;
 		spin_unlock_bh(&rose_neigh_list_lock);
-		if (rose_neigh->digipeat != NULL)
-			kfree(rose_neigh->digipeat);
+		kfree(rose_neigh->digipeat);
 		kfree(rose_neigh);
 		return;
 	}
@@ -250,8 +249,7 @@
 		if (s->next == rose_neigh) {
 			s->next = rose_neigh->next;
 			spin_unlock_bh(&rose_neigh_list_lock);
-			if (rose_neigh->digipeat != NULL)
-				kfree(rose_neigh->digipeat);
+			kfree(rose_neigh->digipeat);
 			kfree(rose_neigh);
 			return;
 		}
diff --git a/net/rxrpc/transport.c b/net/rxrpc/transport.c
index 122c086..dbe6105 100644
--- a/net/rxrpc/transport.c
+++ b/net/rxrpc/transport.c
@@ -23,6 +23,7 @@
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/icmp.h>
+#include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/ip.h>
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -475,15 +476,11 @@
 
 		/* we'll probably need to checksum it (didn't call
 		 * sock_recvmsg) */
-		if (pkt->ip_summed != CHECKSUM_UNNECESSARY) {
-			if ((unsigned short)
-			    csum_fold(skb_checksum(pkt, 0, pkt->len,
-						   pkt->csum))) {
-				kfree_skb(pkt);
-				rxrpc_krxiod_queue_transport(trans);
-				_leave(" CSUM failed");
-				return;
-			}
+		if (skb_checksum_complete(pkt)) {
+			kfree_skb(pkt);
+			rxrpc_krxiod_queue_transport(trans);
+			_leave(" CSUM failed");
+			return;
 		}
 
 		addr = pkt->nh.iph->saddr;
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 29d8b9a..7547048 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -298,8 +298,7 @@
 	return 0;
 
 errout:
-	if (f)
-		kfree(f);
+	kfree(f);
 	return err;
 }
 
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index 02996ac..520ff71 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -525,8 +525,7 @@
 	return 0;
 
 errout:
-	if (f)
-		kfree(f);
+	kfree(f);
 	return err;
 }
 
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h
index 006168d..572f06b 100644
--- a/net/sched/cls_rsvp.h
+++ b/net/sched/cls_rsvp.h
@@ -555,8 +555,7 @@
 	goto insert;
 
 errout:
-	if (f)
-		kfree(f);
+	kfree(f);
 errout2:
 	tcf_exts_destroy(tp, &e);
 	return err;
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index 404d9d8..9f92117 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -194,8 +194,7 @@
 	}
 	tcf_unbind_filter(tp, &r->res);
 	tcf_exts_destroy(tp, &r->exts);
-	if (f)
-		kfree(f);
+	kfree(f);
 	return 0;
 }
 
@@ -442,10 +441,8 @@
 	walker.skip = 0;
 	walker.fn = &tcindex_destroy_element;
 	tcindex_walk(tp,&walker);
-	if (p->perfect)
-		kfree(p->perfect);
-	if (p->h)
-		kfree(p->h);
+	kfree(p->perfect);
+	kfree(p->h);
 	kfree(p);
 	tp->root = NULL;
 }
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 364b87d..2b67047 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -347,7 +347,7 @@
 	if (n->ht_down)
 		n->ht_down->refcnt--;
 #ifdef CONFIG_CLS_U32_PERF
-	if (n && (NULL != n->pf))
+	if (n)
 		kfree(n->pf);
 #endif
 	kfree(n);
@@ -680,7 +680,7 @@
 		return 0;
 	}
 #ifdef CONFIG_CLS_U32_PERF
-	if (n && (NULL != n->pf))
+	if (n)
 		kfree(n->pf);
 #endif
 	kfree(n);
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index cf68a59..700844d 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -561,8 +561,7 @@
 
 static void meta_var_destroy(struct meta_value *v)
 {
-	if (v->val)
-		kfree((void *) v->val);
+	kfree((void *) v->val);
 }
 
 static void meta_var_apply_extras(struct meta_value *v,
diff --git a/net/sched/ematch.c b/net/sched/ematch.c
index ebfe2e7..64b047c 100644
--- a/net/sched/ematch.c
+++ b/net/sched/ematch.c
@@ -298,6 +298,11 @@
 	struct tcf_ematch_tree_hdr *tree_hdr;
 	struct tcf_ematch *em;
 
+	if (!rta) {
+		memset(tree, 0, sizeof(*tree));
+		return 0;
+	}
+
 	if (rtattr_parse_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0)
 		goto errout;
 
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 12b0f58..8c8ddf7 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -344,9 +344,7 @@
 	}
 
 	/* Free peer's cached cookie. */
-	if (asoc->peer.cookie) {
-		kfree(asoc->peer.cookie);
-	}
+	kfree(asoc->peer.cookie);
 
 	/* Release the transport structures. */
 	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 660c61b..f9573eb 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -254,8 +254,7 @@
 	aiparam.adaption_ind = htonl(sp->adaption_ind);
 	sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
 nodata:
-	if (addrs.v)
-		kfree(addrs.v);
+	kfree(addrs.v);
 	return retval;
 }
 
@@ -347,8 +346,7 @@
 nomem_chunk:
 	kfree(cookie);
 nomem_cookie:
-	if (addrs.v)
-		kfree(addrs.v);
+	kfree(addrs.v);
 	return retval;
 }
 
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 13f8ae9..d0dfdfd 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -143,6 +143,6 @@
 
 	return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE);
 out_err:
-	if (md5cksum.data) kfree(md5cksum.data);
+	kfree(md5cksum.data);
 	return GSS_S_FAILURE;
 }
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 2030475..db055fd 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -176,6 +176,6 @@
 
 	ret = GSS_S_COMPLETE;
 out:
-	if (md5cksum.data) kfree(md5cksum.data);
+	kfree(md5cksum.data);
 	return ret;
 }
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index b048bf6..f8bac6c 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -60,8 +60,7 @@
 
 	for (i = 0; i < gm->gm_pf_num; i++) {
 		pf = &gm->gm_pfs[i];
-		if (pf->auth_domain_name)
-			kfree(pf->auth_domain_name);
+		kfree(pf->auth_domain_name);
 		pf->auth_domain_name = NULL;
 	}
 }
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
index 148201e..d1e12b2 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_seal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c
@@ -122,8 +122,7 @@
 
 	return  GSS_S_COMPLETE;
 out_err:
-	if (md5cksum.data) 
-		kfree(md5cksum.data);
+	kfree(md5cksum.data);
 	token->data = NULL;
 	token->len = 0;
 	return GSS_S_FAILURE;
diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c
index 46c08a0..1f82457 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_token.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_token.c
@@ -259,8 +259,7 @@
 
 	ret = GSS_S_COMPLETE;
 out:
-	if (spkm3_ctx_id.data)
-		kfree(spkm3_ctx_id.data);
+	kfree(spkm3_ctx_id.data);
 	return ret;
 }
 
diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c
index c3c0d95..241d5b3 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_unseal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_unseal.c
@@ -120,9 +120,7 @@
 	/* XXX: need to add expiration and sequencing */
 	ret = GSS_S_COMPLETE;
 out:
-	if (md5cksum.data) 
-		kfree(md5cksum.data);
-	if (wire_cksum.data) 
-		kfree(wire_cksum.data);
+	kfree(md5cksum.data);
+	kfree(wire_cksum.data);
 	return ret;
 }
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 702ede3..61c3abe 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -55,6 +55,7 @@
 static void	call_bind_status(struct rpc_task *task);
 static void	call_transmit(struct rpc_task *task);
 static void	call_status(struct rpc_task *task);
+static void	call_transmit_status(struct rpc_task *task);
 static void	call_refresh(struct rpc_task *task);
 static void	call_refreshresult(struct rpc_task *task);
 static void	call_timeout(struct rpc_task *task);
@@ -672,6 +673,18 @@
 	rpc_exit(task, -ERESTARTSYS);
 }
 
+static inline int
+rpc_task_need_encode(struct rpc_task *task)
+{
+	return task->tk_rqstp->rq_snd_buf.len == 0;
+}
+
+static inline void
+rpc_task_force_reencode(struct rpc_task *task)
+{
+	task->tk_rqstp->rq_snd_buf.len = 0;
+}
+
 /*
  * 3.	Encode arguments of an RPC call
  */
@@ -867,12 +880,14 @@
 	if (task->tk_status != 0)
 		return;
 	/* Encode here so that rpcsec_gss can use correct sequence number. */
-	if (task->tk_rqstp->rq_bytes_sent == 0) {
+	if (rpc_task_need_encode(task)) {
+		task->tk_rqstp->rq_bytes_sent = 0;
 		call_encode(task);
 		/* Did the encode result in an error condition? */
 		if (task->tk_status != 0)
 			goto out_nosend;
 	}
+	task->tk_action = call_transmit_status;
 	xprt_transmit(task);
 	if (task->tk_status < 0)
 		return;
@@ -884,6 +899,7 @@
 out_nosend:
 	/* release socket write lock before attempting to handle error */
 	xprt_abort_transmit(task);
+	rpc_task_force_reencode(task);
 }
 
 /*
@@ -915,7 +931,6 @@
 		break;
 	case -ECONNREFUSED:
 	case -ENOTCONN:
-		req->rq_bytes_sent = 0;
 		if (clnt->cl_autobind)
 			clnt->cl_port = 0;
 		task->tk_action = call_bind;
@@ -937,7 +952,18 @@
 }
 
 /*
- * 6a.	Handle RPC timeout
+ * 6a.	Handle transmission errors.
+ */
+static void
+call_transmit_status(struct rpc_task *task)
+{
+	if (task->tk_status != -EAGAIN)
+		rpc_task_force_reencode(task);
+	call_status(task);
+}
+
+/*
+ * 6b.	Handle RPC timeout
  * 	We do not release the request slot, so we keep using the
  *	same XID for all retransmits.
  */
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 4f188d0..81e00a6 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -603,7 +603,7 @@
 		return ERR_PTR(error);
 	dir = nd->dentry->d_inode;
 	down(&dir->i_sem);
-	dentry = lookup_hash(&nd->last, nd->dentry);
+	dentry = lookup_hash(nd);
 	if (IS_ERR(dentry))
 		goto out_err;
 	if (dentry->d_inode) {
@@ -665,7 +665,7 @@
 		return error;
 	dir = nd.dentry->d_inode;
 	down(&dir->i_sem);
-	dentry = lookup_hash(&nd.last, nd.dentry);
+	dentry = lookup_hash(&nd);
 	if (IS_ERR(dentry)) {
 		error = PTR_ERR(dentry);
 		goto out_release;
@@ -726,7 +726,7 @@
 		return error;
 	dir = nd.dentry->d_inode;
 	down(&dir->i_sem);
-	dentry = lookup_hash(&nd.last, nd.dentry);
+	dentry = lookup_hash(&nd);
 	if (IS_ERR(dentry)) {
 		error = PTR_ERR(dentry);
 		goto out_release;
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
index 8f97e90..eb330d4 100644
--- a/net/sunrpc/socklib.c
+++ b/net/sunrpc/socklib.c
@@ -6,6 +6,9 @@
  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
  */
 
+#include <linux/compiler.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
 #include <linux/types.h>
 #include <linux/pagemap.h>
 #include <linux/udp.h>
@@ -165,6 +168,8 @@
 		return -1;
 	if ((unsigned short)csum_fold(desc.csum))
 		return -1;
+	if (unlikely(skb->ip_summed == CHECKSUM_HW))
+		netdev_rx_csum_fault(skb->dev);
 	return 0;
 no_checksum:
 	if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0)
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 5a220b2..e4296c8 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -196,12 +196,9 @@
 	struct svc_serv	*serv = rqstp->rq_server;
 
 	svc_release_buffer(rqstp);
-	if (rqstp->rq_resp)
-		kfree(rqstp->rq_resp);
-	if (rqstp->rq_argp)
-		kfree(rqstp->rq_argp);
-	if (rqstp->rq_auth_data)
-		kfree(rqstp->rq_auth_data);
+	kfree(rqstp->rq_resp);
+	kfree(rqstp->rq_argp);
+	kfree(rqstp->rq_auth_data);
 	kfree(rqstp);
 
 	/* Release the server */
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index f16e7cd..e50e7cf 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -623,12 +623,9 @@
 		/* we can use it in-place */
 		rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr);
 		rqstp->rq_arg.head[0].iov_len = len;
-		if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
-			if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
-				skb_free_datagram(svsk->sk_sk, skb);
-				return 0;
-			}
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		if (skb_checksum_complete(skb)) {
+			skb_free_datagram(svsk->sk_sk, skb);
+			return 0;
 		}
 		rqstp->rq_skbuff = skb;
 	}
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 32df433..aaf08cdd 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -992,8 +992,7 @@
 	err = 0;
 
 out:
-	if (elem)
-		kfree(elem);
+	kfree(elem);
 	if (ppages)
 		kunmap(*ppages);
 	return err;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 41feca3..acc73ba 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -676,7 +676,7 @@
 		err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd);
 		if (err)
 			goto fail;
-		err = permission(nd.dentry->d_inode,MAY_WRITE, &nd);
+		err = vfs_permission(&nd, MAY_WRITE);
 		if (err)
 			goto put_fail;
 
diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c
index 596cb96..59fec59 100644
--- a/net/wanrouter/af_wanpipe.c
+++ b/net/wanrouter/af_wanpipe.c
@@ -1099,7 +1099,7 @@
 	sock_reset_flag(sk, SOCK_ZAPPED);
 	wp = wp_sk(sk);
 
-	if (wp && wp->mbox) {
+	if (wp) {
 		kfree(wp->mbox);
 		wp->mbox = NULL;
 	}
@@ -1186,10 +1186,8 @@
 		return;
 	}
 
-	if (wp_sk(sk)) {
-		kfree(wp_sk(sk));
-		wp_sk(sk) = NULL;
-	}
+	kfree(wp_sk(sk));
+	wp_sk(sk) = NULL;
 
 	if (atomic_read(&sk->sk_refcnt) != 1) {
 		atomic_set(&sk->sk_refcnt, 1);
@@ -1219,10 +1217,8 @@
 	sk->sk_socket = NULL;
 
 
-	if (wp_sk(sk)) {
-		kfree(wp_sk(sk));
-		wp_sk(sk) = NULL;
-	}
+	kfree(wp_sk(sk));
+	wp_sk(sk) = NULL;
 
 	if (atomic_read(&sk->sk_refcnt) != 1) {
 		atomic_set(&sk->sk_refcnt, 1);
@@ -1243,10 +1239,8 @@
 
 	sk->sk_socket = NULL;
 
-	if (wp_sk(sk)) {
-		kfree(wp_sk(sk));
-		wp_sk(sk) = NULL;
-	}
+	kfree(wp_sk(sk));
+	wp_sk(sk) = NULL;
 
 	if (atomic_read(&sk->sk_refcnt) != 1) {
 		atomic_set(&sk->sk_refcnt, 1);
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 13b650a..bcf7b3f 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -714,10 +714,8 @@
 	}
 
 	/* This code has moved from del_if() function */
-	if (dev->priv) {
-		kfree(dev->priv);
-		dev->priv = NULL;
-	}
+	kfree(dev->priv);
+	dev->priv = NULL;
 
 #ifdef CONFIG_WANPIPE_MULTPPP
 	if (cnf->config_id == WANCONFIG_MPPP)
@@ -851,10 +849,8 @@
 
 	/* Due to new interface linking method using dev->priv,
 	 * this code has moved from del_if() function.*/
-	if (dev->priv){
-		kfree(dev->priv);
-		dev->priv=NULL;
-	}
+	kfree(dev->priv);
+	dev->priv=NULL;
 
 	unregister_netdev(dev);
 
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 8b9a474..7cf48aa 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -62,14 +62,10 @@
 {
 	if (del_timer(&x->timer))
 		BUG();
-	if (x->aalg)
-		kfree(x->aalg);
-	if (x->ealg)
-		kfree(x->ealg);
-	if (x->calg)
-		kfree(x->calg);
-	if (x->encap)
-		kfree(x->encap);
+	kfree(x->aalg);
+	kfree(x->ealg);
+	kfree(x->calg);
+	kfree(x->encap);
 	if (x->type) {
 		x->type->destructor(x);
 		xfrm_put_type(x->type);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index c35336a..0cdd9a0 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -18,7 +18,6 @@
 #include <linux/string.h>
 #include <linux/net.h>
 #include <linux/skbuff.h>
-#include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 #include <linux/pfkeyv2.h>
 #include <linux/ipsec.h>
@@ -26,6 +25,7 @@
 #include <linux/security.h>
 #include <net/sock.h>
 #include <net/xfrm.h>
+#include <net/netlink.h>
 #include <asm/uaccess.h>
 
 static struct sock *xfrm_nl;
@@ -948,11 +948,6 @@
 	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
 };
 
-static int xfrm_done(struct netlink_callback *cb)
-{
-	return 0;
-}
-
 static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
 {
 	struct rtattr *xfrma[XFRMA_MAX];
@@ -984,20 +979,15 @@
 	if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
 	     type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
 	    (nlh->nlmsg_flags & NLM_F_DUMP)) {
-		u32 rlen;
-
 		if (link->dump == NULL)
 			goto err_einval;
 
 		if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh,
-						link->dump,
-						xfrm_done)) != 0) {
+						link->dump, NULL)) != 0) {
 			return -1;
 		}
-		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-		if (rlen > skb->len)
-			rlen = skb->len;
-		skb_pull(skb, rlen);
+
+		netlink_queue_skip(nlh, skb);
 		return -1;
 	}
 
@@ -1032,60 +1022,13 @@
 	return -1;
 }
 
-static int xfrm_user_rcv_skb(struct sk_buff *skb)
-{
-	int err;
-	struct nlmsghdr *nlh;
-
-	while (skb->len >= NLMSG_SPACE(0)) {
-		u32 rlen;
-
-		nlh = (struct nlmsghdr *) skb->data;
-		if (nlh->nlmsg_len < sizeof(*nlh) ||
-		    skb->len < nlh->nlmsg_len)
-			return 0;
-		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-		if (rlen > skb->len)
-			rlen = skb->len;
-		if (xfrm_user_rcv_msg(skb, nlh, &err) < 0) {
-			if (err == 0)
-				return -1;
-			netlink_ack(skb, nlh, err);
-		} else if (nlh->nlmsg_flags & NLM_F_ACK)
-			netlink_ack(skb, nlh, 0);
-		skb_pull(skb, rlen);
-	}
-
-	return 0;
-}
-
 static void xfrm_netlink_rcv(struct sock *sk, int len)
 {
-	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
+	unsigned int qlen = 0;
 
 	do {
-		struct sk_buff *skb;
-
 		down(&xfrm_cfg_sem);
-
-		if (qlen > skb_queue_len(&sk->sk_receive_queue))
-			qlen = skb_queue_len(&sk->sk_receive_queue);
-
-		for (; qlen; qlen--) {
-			skb = skb_dequeue(&sk->sk_receive_queue);
-			if (xfrm_user_rcv_skb(skb)) {
-				if (skb->len)
-					skb_queue_head(&sk->sk_receive_queue,
-						       skb);
-				else {
-					kfree_skb(skb);
-					qlen--;
-				}
-				break;
-			}
-			kfree_skb(skb);
-		}
-
+		netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg);
 		up(&xfrm_cfg_sem);
 
 	} while (qlen);
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index c65c435..9d67782 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -114,7 +114,7 @@
 endif
 
 clean-files	:= lkc_defs.h qconf.moc .tmp_qtcheck \
-		   .tmp_gtkcheck zconf.tab.c zconf.tab.h lex.zconf.c
+		   .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c
 
 # Needed for systems without gettext
 KBUILD_HAVE_NLS := $(shell \
@@ -136,12 +136,6 @@
 HOSTCFLAGS_gconf.o	= `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --cflags` \
                           -D LKC_DIRECT_LINK
 
-$(obj)/conf.o $(obj)/mconf.o $(obj)/qconf.o $(obj)/gconf.o $(obj)/kxgettext: $(obj)/zconf.tab.h
-
-$(obj)/zconf.tab.h: $(src)/zconf.tab.h_shipped
-$(obj)/zconf.tab.c: $(src)/zconf.tab.c_shipped
-$(obj)/lex.zconf.c: $(src)/lex.zconf.c_shipped
-
 $(obj)/qconf.o: $(obj)/.tmp_qtcheck
 
 ifeq ($(qconf-target),1)
@@ -207,7 +201,7 @@
 	fi
 endif
 
-$(obj)/zconf.tab.o: $(obj)/lex.zconf.c
+$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c
 
 $(obj)/kconfig_load.o: $(obj)/lkc_defs.h
 
@@ -223,20 +217,27 @@
 
 
 ###
-# The following requires flex/bison
+# The following requires flex/bison/gperf
 # By default we use the _shipped versions, uncomment the following line if
 # you are modifying the flex/bison src.
 # LKC_GENPARSER := 1
 
 ifdef LKC_GENPARSER
 
-$(obj)/zconf.tab.c: $(obj)/zconf.y 
-$(obj)/zconf.tab.h: $(obj)/zconf.tab.c
+$(obj)/zconf.tab.c: $(src)/zconf.y
+$(obj)/lex.zconf.c: $(src)/zconf.l
+$(obj)/zconf.hash.c: $(src)/zconf.gperf
 
 %.tab.c: %.y
-	bison -t -d -v -b $* -p $(notdir $*) $<
+	bison -l -b $* -p $(notdir $*) $<
+	cp $@ $@_shipped
 
 lex.%.c: %.l
-	flex -P$(notdir $*) -o$@ $<
+	flex -L -P$(notdir $*) -o$@ $<
+	cp $@ $@_shipped
+
+%.hash.c: %.gperf
+	gperf < $< > $@
+	cp $@ $@_shipped
 
 endif
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index bc20cab..8ba5d29 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -82,6 +82,15 @@
 	}
 
 	switch (input_mode) {
+	case set_no:
+	case set_mod:
+	case set_yes:
+	case set_random:
+		if (sym_has_value(sym)) {
+			printf("%s\n", def);
+			return;
+		}
+		break;
 	case ask_new:
 	case ask_silent:
 		if (sym_has_value(sym)) {
@@ -467,15 +476,14 @@
 		return;
 
 	sym = menu->sym;
-	if (sym) {
-		if (sym_is_changable(sym) && !sym_has_value(sym)) {
+	if (sym && !sym_has_value(sym)) {
+		if (sym_is_changable(sym) ||
+		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
 			if (!conf_cnt++)
 				printf(_("*\n* Restart config...\n*\n"));
 			rootEntry = menu_get_parent_menu(menu);
 			conf(rootEntry);
 		}
-		if (sym_is_choice(sym) && sym_get_tristate_value(sym) != mod)
-			return;
 	}
 
 	for (child = menu->list; child; child = child->next)
@@ -559,6 +567,27 @@
 	case ask_new:
 		conf_read(NULL);
 		break;
+	case set_no:
+	case set_mod:
+	case set_yes:
+	case set_random:
+		name = getenv("KCONFIG_ALLCONFIG");
+		if (name && !stat(name, &tmpstat)) {
+			conf_read_simple(name);
+			break;
+		}
+		switch (input_mode) {
+		case set_no:	 name = "allno.config"; break;
+		case set_mod:	 name = "allmod.config"; break;
+		case set_yes:	 name = "allyes.config"; break;
+		case set_random: name = "allrandom.config"; break;
+		default: break;
+		}
+		if (!stat(name, &tmpstat))
+			conf_read_simple(name);
+		else if (!stat("all.config", &tmpstat))
+			conf_read_simple("all.config");
+		break;
 	default:
 		break;
 	}
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 02f670c..ccd4513 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -14,6 +14,12 @@
 #define LKC_DIRECT_LINK
 #include "lkc.h"
 
+static void conf_warning(const char *fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
 const char conf_def_filename[] = ".config";
 
 const char conf_defname[] = "arch/$ARCH/defconfig";
@@ -27,6 +33,17 @@
 	NULL,
 };
 
+static void conf_warning(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+	conf_warnings++;
+}
+
 static char *conf_expand_value(const char *in)
 {
 	struct symbol *sym;
@@ -69,15 +86,12 @@
 	return name;
 }
 
-int conf_read(const char *name)
+int conf_read_simple(const char *name)
 {
 	FILE *in = NULL;
 	char line[1024];
 	char *p, *p2;
-	int lineno = 0;
 	struct symbol *sym;
-	struct property *prop;
-	struct expr *e;
 	int i;
 
 	if (name) {
@@ -95,12 +109,18 @@
 			}
 		}
 	}
-
 	if (!in)
 		return 1;
 
+	conf_filename = name;
+	conf_lineno = 0;
+	conf_warnings = 0;
+	conf_unsaved = 0;
+
 	for_all_symbols(i, sym) {
 		sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
+		if (sym_is_choice(sym))
+			sym->flags &= ~SYMBOL_NEW;
 		sym->flags &= ~SYMBOL_VALID;
 		switch (sym->type) {
 		case S_INT:
@@ -115,7 +135,7 @@
 	}
 
 	while (fgets(line, sizeof(line), in)) {
-		lineno++;
+		conf_lineno++;
 		sym = NULL;
 		switch (line[0]) {
 		case '#':
@@ -129,7 +149,10 @@
 				continue;
 			sym = sym_find(line + 9);
 			if (!sym) {
-				fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line + 9);
+				conf_warning("trying to assign nonexistent symbol %s", line + 9);
+				break;
+			} else if (!(sym->flags & SYMBOL_NEW)) {
+				conf_warning("trying to reassign symbol %s", sym->name);
 				break;
 			}
 			switch (sym->type) {
@@ -143,8 +166,10 @@
 			}
 			break;
 		case 'C':
-			if (memcmp(line, "CONFIG_", 7))
+			if (memcmp(line, "CONFIG_", 7)) {
+				conf_warning("unexpected data");
 				continue;
+			}
 			p = strchr(line + 7, '=');
 			if (!p)
 				continue;
@@ -154,7 +179,10 @@
 				*p2 = 0;
 			sym = sym_find(line + 7);
 			if (!sym) {
-				fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line + 7);
+				conf_warning("trying to assign nonexistent symbol %s", line + 7);
+				break;
+			} else if (!(sym->flags & SYMBOL_NEW)) {
+				conf_warning("trying to reassign symbol %s", sym->name);
 				break;
 			}
 			switch (sym->type) {
@@ -175,6 +203,7 @@
 					sym->flags &= ~SYMBOL_NEW;
 					break;
 				}
+				conf_warning("symbol value '%s' invalid for %s", p, sym->name);
 				break;
 			case S_STRING:
 				if (*p++ != '"')
@@ -187,8 +216,8 @@
 					memmove(p2, p2 + 1, strlen(p2));
 				}
 				if (!p2) {
-					fprintf(stderr, "%s:%d: invalid string found\n", name, lineno);
-					exit(1);
+					conf_warning("invalid string found");
+					continue;
 				}
 			case S_INT:
 			case S_HEX:
@@ -196,8 +225,8 @@
 					sym->user.val = strdup(p);
 					sym->flags &= ~SYMBOL_NEW;
 				} else {
-					fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name);
-					exit(1);
+					conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+					continue;
 				}
 				break;
 			default:
@@ -207,6 +236,7 @@
 		case '\n':
 			break;
 		default:
+			conf_warning("unexpected data");
 			continue;
 		}
 		if (sym && sym_is_choice_value(sym)) {
@@ -215,25 +245,63 @@
 			case no:
 				break;
 			case mod:
-				if (cs->user.tri == yes)
-					/* warn? */;
+				if (cs->user.tri == yes) {
+					conf_warning("%s creates inconsistent choice state", sym->name);
+					cs->flags |= SYMBOL_NEW;
+				}
 				break;
 			case yes:
-				if (cs->user.tri != no)
-					/* warn? */;
-				cs->user.val = sym;
+				if (cs->user.tri != no) {
+					conf_warning("%s creates inconsistent choice state", sym->name);
+					cs->flags |= SYMBOL_NEW;
+				} else
+					cs->user.val = sym;
 				break;
 			}
 			cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
-			cs->flags &= ~SYMBOL_NEW;
 		}
 	}
 	fclose(in);
 
 	if (modules_sym)
 		sym_calc_value(modules_sym);
+	return 0;
+}
+
+int conf_read(const char *name)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *e;
+	int i;
+
+	if (conf_read_simple(name))
+		return 1;
+
 	for_all_symbols(i, sym) {
 		sym_calc_value(sym);
+		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+			goto sym_ok;
+		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+			/* check that calculated value agrees with saved value */
+			switch (sym->type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				if (sym->user.tri != sym_get_tristate_value(sym))
+					break;
+				if (!sym_is_choice(sym))
+					goto sym_ok;
+			default:
+				if (!strcmp(sym->curr.val, sym->user.val))
+					goto sym_ok;
+				break;
+			}
+		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+			/* no previous value and not saved */
+			goto sym_ok;
+		conf_unsaved++;
+		/* maybe print value in verbose mode... */
+	sym_ok:
 		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
 			if (sym->visible == no)
 				sym->flags |= SYMBOL_NEW;
@@ -241,8 +309,10 @@
 			case S_STRING:
 			case S_INT:
 			case S_HEX:
-				if (!sym_string_within_range(sym, sym->user.val))
+				if (!sym_string_within_range(sym, sym->user.val)) {
 					sym->flags |= SYMBOL_NEW;
+					sym->flags &= ~SYMBOL_VALID;
+				}
 			default:
 				break;
 			}
@@ -255,7 +325,7 @@
 				sym->flags |= e->right.sym->flags & SYMBOL_NEW;
 	}
 
-	sym_change_count = 1;
+	sym_change_count = conf_warnings && conf_unsaved;
 
 	return 0;
 }
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 7d39ff4..1b36ef1 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -93,7 +93,6 @@
 #define SYMBOL_NEW		0x0800
 #define SYMBOL_AUTO		0x1000
 #define SYMBOL_CHECKED		0x2000
-#define SYMBOL_CHECK_DONE	0x4000
 #define SYMBOL_WARNED		0x8000
 
 #define SYMBOL_MAXLENGTH	256
diff --git a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped
index 22dda11..24e3c8c 100644
--- a/scripts/kconfig/lex.zconf.c_shipped
+++ b/scripts/kconfig/lex.zconf.c_shipped
@@ -1,5 +1,5 @@
 
-#line 3 "lex.zconf.c"
+#line 3 "scripts/kconfig/lex.zconf.c"
 
 #define  YY_INT_ALIGNED short int
 
@@ -323,7 +323,7 @@
 
 /* Begin user sect3 */
 
-#define zconfwrap(n) 1
+#define zconfwrap() 1
 #define YY_SKIP_YYWRAP
 
 typedef unsigned char YY_CHAR;
@@ -338,1567 +338,323 @@
 
 extern char *zconftext;
 #define yytext_ptr zconftext
-static yyconst flex_int16_t yy_nxt[][38] =
+static yyconst flex_int16_t yy_nxt[][17] =
     {
     {
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0
+        0,    0,    0,    0,    0,    0,    0
     },
 
     {
        11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12
+       12,   12,   12,   12,   12,   12,   12
     },
 
     {
        11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
-
-       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12
+       12,   12,   12,   12,   12,   12,   12
     },
 
     {
        11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
-       16,   16,   16,   18,   16,   16,   18,   18,   19,   20,
-       21,   22,   18,   18,   23,   24,   18,   25,   18,   26,
-       27,   18,   28,   29,   30,   18,   18,   16
+       16,   16,   16,   18,   16,   16,   16
     },
 
     {
        11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
-       16,   16,   16,   18,   16,   16,   18,   18,   19,   20,
-       21,   22,   18,   18,   23,   24,   18,   25,   18,   26,
-       27,   18,   28,   29,   30,   18,   18,   16
+       16,   16,   16,   18,   16,   16,   16
 
     },
 
     {
-       11,   31,   32,   33,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
     },
 
     {
-       11,   31,   32,   33,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
     },
 
     {
-       11,   34,   34,   35,   34,   36,   34,   34,   36,   34,
-       34,   34,   34,   34,   34,   37,   34,   34,   34,   34,
-
-       34,   34,   34,   34,   34,   34,   34,   34,   34,   34,
-       34,   34,   34,   34,   34,   34,   34,   34
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
     },
 
     {
-       11,   34,   34,   35,   34,   36,   34,   34,   36,   34,
-       34,   34,   34,   34,   34,   37,   34,   34,   34,   34,
-       34,   34,   34,   34,   34,   34,   34,   34,   34,   34,
-       34,   34,   34,   34,   34,   34,   34,   34
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
     },
 
     {
-       11,   38,   38,   39,   40,   41,   42,   43,   41,   44,
-       45,   46,   47,   47,   48,   49,   47,   47,   47,   47,
-       47,   47,   47,   47,   47,   50,   47,   47,   47,   51,
-       47,   47,   47,   47,   47,   47,   47,   52
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
 
     },
 
     {
-       11,   38,   38,   39,   40,   41,   42,   43,   41,   44,
-       45,   46,   47,   47,   48,   49,   47,   47,   47,   47,
-       47,   47,   47,   47,   47,   50,   47,   47,   47,   51,
-       47,   47,   47,   47,   47,   47,   47,   52
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
     },
 
     {
       -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
-      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
-      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
-      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11
+      -11,  -11,  -11,  -11,  -11,  -11,  -11
     },
 
     {
        11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
-      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
-
-      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
-      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12
+      -12,  -12,  -12,  -12,  -12,  -12,  -12
     },
 
     {
-       11,  -13,   53,   54,  -13,  -13,   55,  -13,  -13,  -13,
-      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,
-      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,
-      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13
+       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13,
+      -13,  -13,  -13,  -13,  -13,  -13,  -13
     },
 
     {
        11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
-      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
-      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
-      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14
+      -14,  -14,  -14,  -14,  -14,  -14,  -14
 
     },
 
     {
-       11,   56,   56,   57,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
     },
 
     {
        11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
-      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
-      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
-      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16
+      -16,  -16,  -16,  -16,  -16,  -16,  -16
     },
 
     {
        11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
-      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
-
-      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
-      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17
+      -17,  -17,  -17,  -17,  -17,  -17,  -17
     },
 
     {
        11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
-      -18,  -18,  -18,   58,  -18,  -18,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -18
+      -18,  -18,  -18,   44,  -18,  -18,  -18
     },
 
     {
-       11,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,
-      -19,  -19,  -19,   58,  -19,  -19,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   59,
-       58,   58,   58,   58,   58,   58,   58,  -19
+       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
 
     },
 
     {
-       11,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,
-      -20,  -20,  -20,   58,  -20,  -20,   58,   58,   58,   58,
-       58,   58,   58,   58,   60,   58,   58,   58,   58,   61,
-       58,   58,   58,   58,   58,   58,   58,  -20
+       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20,
+      -20,  -20,  -20,  -20,  -20,  -20,  -20
     },
 
     {
-       11,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,
-      -21,  -21,  -21,   58,  -21,  -21,   58,   58,   58,   58,
-       58,   62,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -21
+       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
     },
 
     {
-       11,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,
-      -22,  -22,  -22,   58,  -22,  -22,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   63,   58,
-       58,   58,   58,   58,   58,   58,   58,  -22
+       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49,
+       49,   49,   49,   49,   49,  -22,   49
     },
 
     {
        11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
-      -23,  -23,  -23,   58,  -23,  -23,   58,   58,   58,   58,
-       58,   64,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -23
+      -23,  -23,  -23,  -23,  -23,  -23,  -23
     },
 
     {
        11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
-      -24,  -24,  -24,   58,  -24,  -24,   58,   58,   58,   58,
-       58,   58,   65,   58,   58,   58,   58,   58,   66,   58,
-       58,   58,   58,   58,   58,   58,   58,  -24
+      -24,  -24,  -24,  -24,  -24,  -24,  -24
 
     },
 
     {
-       11,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,
-      -25,  -25,  -25,   58,  -25,  -25,   58,   67,   58,   58,
-       58,   68,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -25
+       11,   51,   51,   52,   51,   51,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51
     },
 
     {
        11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
-      -26,  -26,  -26,   58,  -26,  -26,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       69,   58,   58,   58,   58,   58,   58,  -26
+      -26,  -26,  -26,  -26,  -26,  -26,  -26
     },
 
     {
        11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
-      -27,  -27,  -27,   58,  -27,  -27,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   70,   58,   58,   58,   58,  -27
+      -27,  -27,  -27,  -27,  -27,  -27,  -27
     },
 
     {
        11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
-      -28,  -28,  -28,   58,  -28,  -28,   58,   71,   58,   58,
-       58,   72,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -28
+      -28,  -28,  -28,  -28,   53,  -28,  -28
     },
 
     {
        11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
-      -29,  -29,  -29,   58,  -29,  -29,   58,   58,   58,   58,
-       58,   73,   58,   58,   58,   58,   58,   58,   58,   74,
-       58,   58,   58,   58,   75,   58,   58,  -29
+      -29,  -29,  -29,  -29,  -29,  -29,  -29
 
     },
 
     {
-       11,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,
-      -30,  -30,  -30,   58,  -30,  -30,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   76,   58,   58,   58,   58,  -30
+       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
     },
 
     {
-       11,   77,   77,  -31,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77
+       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31,
+      -31,  -31,  -31,  -31,  -31,  -31,  -31
     },
 
     {
-       11,  -32,   78,   79,  -32,  -32,  -32,  -32,  -32,  -32,
-      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
-
-      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
-      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32
+       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
+      -32,  -32,  -32,  -32,  -32,  -32,  -32
     },
 
     {
-       11,   80,  -33,  -33,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80
+       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,
+      -33,  -33,  -33,  -33,  -33,  -33,  -33
     },
 
     {
-       11,   81,   81,   82,   81,  -34,   81,   81,  -34,   81,
-       81,   81,   81,   81,   81,  -34,   81,   81,   81,   81,
-       81,   81,   81,   81,   81,   81,   81,   81,   81,   81,
-       81,   81,   81,   81,   81,   81,   81,   81
+       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
+      -34,   56,   57,   57,  -34,  -34,  -34
 
     },
 
     {
        11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
-      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
-      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
-      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35
+      -35,   57,   57,   57,  -35,  -35,  -35
     },
 
     {
        11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
-      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
-      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
-      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36
+      -36,  -36,  -36,  -36,  -36,  -36,  -36
     },
 
     {
-       11,   83,   83,   84,   83,   83,   83,   83,   83,   83,
-       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
-
-       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
-       83,   83,   83,   83,   83,   83,   83,   83
+       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37,
+      -37,  -37,  -37,  -37,  -37,  -37,  -37
     },
 
     {
        11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
-      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
-      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
-      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38
+      -38,  -38,  -38,  -38,  -38,  -38,   59
     },
 
     {
-       11,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,
-      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,
-      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,
-      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39
+       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39,
+      -39,  -39,  -39,  -39,  -39,  -39,  -39
 
     },
 
     {
        11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
-      -40,  -40,  -40,  -40,   85,  -40,  -40,  -40,  -40,  -40,
-      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
-      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40
+      -40,  -40,  -40,  -40,  -40,  -40,  -40
     },
 
     {
-       11,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,
-      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,
-      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,
-      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
     },
 
     {
-       11,   86,   86,  -42,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
-
-       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
     },
 
     {
-       11,  -43,  -43,  -43,  -43,  -43,  -43,   87,  -43,  -43,
-      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
-      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
-      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43
+       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
+      -43,  -43,  -43,  -43,  -43,  -43,  -43
     },
 
     {
        11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
-      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
-      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
-      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44
+      -44,  -44,  -44,   44,  -44,  -44,  -44
 
     },
 
     {
-       11,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,
-      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,
-      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,
-      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45
+       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
     },
 
     {
-       11,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,
-      -46,   88,   89,   89,  -46,  -46,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -46
+       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46,
+      -46,  -46,  -46,  -46,  -46,  -46,  -46
     },
 
     {
-       11,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,
-      -47,   89,   89,   89,  -47,  -47,   89,   89,   89,   89,
-
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -47
+       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
     },
 
     {
        11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
-      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
-      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
-      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48
+      -48,  -48,  -48,  -48,  -48,  -48,  -48
     },
 
     {
-       11,  -49,  -49,   90,  -49,  -49,  -49,  -49,  -49,  -49,
-      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,
-      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,
-      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49
+       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49,
+       49,   49,   49,   49,   49,  -49,   49
 
     },
 
     {
        11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
-      -50,   89,   89,   89,  -50,  -50,   89,   89,   89,   89,
-       89,   89,   91,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -50
+      -50,  -50,  -50,  -50,  -50,  -50,  -50
     },
 
     {
-       11,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,
-      -51,   89,   89,   89,  -51,  -51,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   92,   89,
-       89,   89,   89,   89,   89,   89,   89,  -51
+       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51,
+      -51,  -51,  -51,  -51,  -51,  -51,  -51
     },
 
     {
        11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
-      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
-
-      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
-      -52,  -52,  -52,  -52,  -52,  -52,  -52,   93
+      -52,  -52,  -52,  -52,  -52,  -52,  -52
     },
 
     {
-       11,  -53,   53,   54,  -53,  -53,   55,  -53,  -53,  -53,
-      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
-      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
-      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53
+       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
+      -53,  -53,  -53,  -53,  -53,  -53,  -53
     },
 
     {
-       11,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,
-      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,
-      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,
-      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54
+       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
 
     },
 
     {
-       11,   56,   56,   57,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56
+       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,
+      -55,  -55,  -55,  -55,  -55,  -55,  -55
     },
 
     {
-       11,   56,   56,   57,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56
+       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,
+      -56,   60,   57,   57,  -56,  -56,  -56
     },
 
     {
        11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
-      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
-
-      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
-      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57
+      -57,   57,   57,   57,  -57,  -57,  -57
     },
 
     {
        11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
-      -58,  -58,  -58,   58,  -58,  -58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -58
+      -58,  -58,  -58,  -58,  -58,  -58,  -58
     },
 
     {
        11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
-      -59,  -59,  -59,   58,  -59,  -59,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   94,
-       58,   58,   58,   58,   58,   58,   58,  -59
+      -59,  -59,  -59,  -59,  -59,  -59,  -59
 
     },
 
     {
        11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
-      -60,  -60,  -60,   58,  -60,  -60,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   95,
-       58,   58,   58,   58,   58,   58,   58,  -60
-    },
-
-    {
-       11,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,
-      -61,  -61,  -61,   58,  -61,  -61,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   96,   97,   58,
-       58,   58,   58,   58,   58,   58,   58,  -61
-    },
-
-    {
-       11,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,
-      -62,  -62,  -62,   58,  -62,  -62,   58,   58,   58,   58,
-
-       58,   58,   98,   58,   58,   58,   58,   58,   58,   58,
-       99,   58,   58,   58,   58,   58,   58,  -62
-    },
-
-    {
-       11,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,
-      -63,  -63,  -63,   58,  -63,  -63,   58,  100,   58,   58,
-      101,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -63
-    },
-
-    {
-       11,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,
-      -64,  -64,  -64,   58,  -64,  -64,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  102,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  103,  -64
-
-    },
-
-    {
-       11,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,
-      -65,  -65,  -65,   58,  -65,  -65,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -65
-    },
-
-    {
-       11,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,
-      -66,  -66,  -66,   58,  -66,  -66,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  104,   58,   58,  -66
-    },
-
-    {
-       11,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,
-      -67,  -67,  -67,   58,  -67,  -67,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,  105,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -67
-    },
-
-    {
-       11,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,
-      -68,  -68,  -68,   58,  -68,  -68,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  106,   58,
-       58,   58,   58,   58,   58,   58,   58,  -68
-    },
-
-    {
-       11,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,
-      -69,  -69,  -69,   58,  -69,  -69,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  107,   58,   58,  -69
-
-    },
-
-    {
-       11,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,
-      -70,  -70,  -70,   58,  -70,  -70,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  108,
-       58,   58,   58,   58,   58,   58,   58,  -70
-    },
-
-    {
-       11,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,
-      -71,  -71,  -71,   58,  -71,  -71,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  109,   58,
-       58,   58,   58,   58,   58,   58,   58,  -71
-    },
-
-    {
-       11,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,
-      -72,  -72,  -72,   58,  -72,  -72,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,  110,   58,   58,   58,   58,   58,  -72
-    },
-
-    {
-       11,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,
-      -73,  -73,  -73,   58,  -73,  -73,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  111,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -73
-    },
-
-    {
-       11,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,
-      -74,  -74,  -74,   58,  -74,  -74,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  112,   58,  -74
-
-    },
-
-    {
-       11,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,
-      -75,  -75,  -75,   58,  -75,  -75,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,  113,   58,   58,   58,   58,  -75
-    },
-
-    {
-       11,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,
-      -76,  -76,  -76,   58,  -76,  -76,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  114,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -76
-    },
-
-    {
-       11,   77,   77,  -77,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
-
-       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77
-    },
-
-    {
-       11,  -78,   78,   79,  -78,  -78,  -78,  -78,  -78,  -78,
-      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,
-      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,
-      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78
-    },
-
-    {
-       11,   80,  -79,  -79,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80
-
-    },
-
-    {
-       11,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,
-      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,
-      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,
-      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80
-    },
-
-    {
-       11,   81,   81,   82,   81,  -81,   81,   81,  -81,   81,
-       81,   81,   81,   81,   81,  -81,   81,   81,   81,   81,
-       81,   81,   81,   81,   81,   81,   81,   81,   81,   81,
-       81,   81,   81,   81,   81,   81,   81,   81
-    },
-
-    {
-       11,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,
-      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,
-
-      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,
-      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82
-    },
-
-    {
-       11,  -83,  -83,   84,  -83,  -83,  -83,  -83,  -83,  -83,
-      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,
-      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,
-      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83
-    },
-
-    {
-       11,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,
-      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,
-      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,
-      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84
-
-    },
-
-    {
-       11,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,
-      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,
-      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,
-      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85
-    },
-
-    {
-       11,   86,   86,  -86,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86
-    },
-
-    {
-       11,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,
-      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,
-
-      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,
-      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87
-    },
-
-    {
-       11,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,
-      -88,  115,   89,   89,  -88,  -88,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -88
-    },
-
-    {
-       11,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,
-      -89,   89,   89,   89,  -89,  -89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -89
-
-    },
-
-    {
-       11,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,
-      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,
-      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,
-      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90
-    },
-
-    {
-       11,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,
-      -91,   89,   89,   89,  -91,  -91,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -91
-    },
-
-    {
-       11,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,
-      -92,   89,   89,   89,  -92,  -92,   89,   89,   89,   89,
-
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -92
-    },
-
-    {
-       11,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,
-      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,
-      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,
-      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93
-    },
-
-    {
-       11,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,
-      -94,  -94,  -94,   58,  -94,  -94,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  116,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -94
-
-    },
-
-    {
-       11,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,
-      -95,  -95,  -95,   58,  -95,  -95,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  117,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -95
-    },
-
-    {
-       11,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,
-      -96,  -96,  -96,   58,  -96,  -96,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  118,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -96
-    },
-
-    {
-       11,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,
-      -97,  -97,  -97,   58,  -97,  -97,   58,   58,   58,   58,
-
-       58,   58,  119,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -97
-    },
-
-    {
-       11,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,
-      -98,  -98,  -98,   58,  -98,  -98,  120,  121,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -98
-    },
-
-    {
-       11,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,
-      -99,  -99,  -99,   58,  -99,  -99,   58,   58,   58,   58,
-       58,  122,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -99
-
-    },
-
-    {
-       11, -100, -100, -100, -100, -100, -100, -100, -100, -100,
-     -100, -100, -100,   58, -100, -100,   58,   58,  123,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -100
-    },
-
-    {
-       11, -101, -101, -101, -101, -101, -101, -101, -101, -101,
-     -101, -101, -101,   58, -101, -101,   58,   58,   58,  124,
-       58,   58,   58,   58,   58,  125,   58,  126,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -101
-    },
-
-    {
-       11, -102, -102, -102, -102, -102, -102, -102, -102, -102,
-     -102, -102, -102,   58, -102, -102,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-      127,   58,   58,   58,   58,   58,   58, -102
-    },
-
-    {
-       11, -103, -103, -103, -103, -103, -103, -103, -103, -103,
-     -103, -103, -103,   58, -103, -103,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -103
-    },
-
-    {
-       11, -104, -104, -104, -104, -104, -104, -104, -104, -104,
-     -104, -104, -104,   58, -104, -104,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -104
-
-    },
-
-    {
-       11, -105, -105, -105, -105, -105, -105, -105, -105, -105,
-     -105, -105, -105,   58, -105, -105,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  128,   58,
-       58,   58,   58,   58,   58,   58,   58, -105
-    },
-
-    {
-       11, -106, -106, -106, -106, -106, -106, -106, -106, -106,
-     -106, -106, -106,   58, -106, -106,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  129,   58, -106
-    },
-
-    {
-       11, -107, -107, -107, -107, -107, -107, -107, -107, -107,
-     -107, -107, -107,   58, -107, -107,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,  130,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -107
-    },
-
-    {
-       11, -108, -108, -108, -108, -108, -108, -108, -108, -108,
-     -108, -108, -108,   58, -108, -108,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  131,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -108
-    },
-
-    {
-       11, -109, -109, -109, -109, -109, -109, -109, -109, -109,
-     -109, -109, -109,   58, -109, -109,   58,   58,   58,   58,
-       58,   58,   58,  132,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -109
-
-    },
-
-    {
-       11, -110, -110, -110, -110, -110, -110, -110, -110, -110,
-     -110, -110, -110,   58, -110, -110,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  133,   58, -110
-    },
-
-    {
-       11, -111, -111, -111, -111, -111, -111, -111, -111, -111,
-     -111, -111, -111,   58, -111, -111,   58,   58,   58,   58,
-       58,  134,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -111
-    },
-
-    {
-       11, -112, -112, -112, -112, -112, -112, -112, -112, -112,
-     -112, -112, -112,   58, -112, -112,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,  135,   58,   58,   58,   58, -112
-    },
-
-    {
-       11, -113, -113, -113, -113, -113, -113, -113, -113, -113,
-     -113, -113, -113,   58, -113, -113,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  136,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -113
-    },
-
-    {
-       11, -114, -114, -114, -114, -114, -114, -114, -114, -114,
-     -114, -114, -114,   58, -114, -114,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,  137,   58,   58,   58, -114
-
-    },
-
-    {
-       11, -115, -115, -115, -115, -115, -115, -115, -115, -115,
-     -115,   89,   89,   89, -115, -115,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89, -115
-    },
-
-    {
-       11, -116, -116, -116, -116, -116, -116, -116, -116, -116,
-     -116, -116, -116,   58, -116, -116,   58,   58,   58,   58,
-       58,  138,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -116
-    },
-
-    {
-       11, -117, -117, -117, -117, -117, -117, -117, -117, -117,
-     -117, -117, -117,   58, -117, -117,   58,   58,   58,  139,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -117
-    },
-
-    {
-       11, -118, -118, -118, -118, -118, -118, -118, -118, -118,
-     -118, -118, -118,   58, -118, -118,   58,   58,   58,   58,
-       58,  140,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -118
-    },
-
-    {
-       11, -119, -119, -119, -119, -119, -119, -119, -119, -119,
-     -119, -119, -119,   58, -119, -119,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  141,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -119
-
-    },
-
-    {
-       11, -120, -120, -120, -120, -120, -120, -120, -120, -120,
-     -120, -120, -120,   58, -120, -120,   58,   58,  142,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  143,   58,   58, -120
-    },
-
-    {
-       11, -121, -121, -121, -121, -121, -121, -121, -121, -121,
-     -121, -121, -121,   58, -121, -121,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  144,   58, -121
-    },
-
-    {
-       11, -122, -122, -122, -122, -122, -122, -122, -122, -122,
-     -122, -122, -122,   58, -122, -122,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,  145,   58,
-       58,   58,   58,   58,   58,   58,   58, -122
-    },
-
-    {
-       11, -123, -123, -123, -123, -123, -123, -123, -123, -123,
-     -123, -123, -123,   58, -123, -123,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  146,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -123
-    },
-
-    {
-       11, -124, -124, -124, -124, -124, -124, -124, -124, -124,
-     -124, -124, -124,   58, -124, -124,   58,   58,   58,   58,
-       58,   58,   58,   58,  147,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -124
-
-    },
-
-    {
-       11, -125, -125, -125, -125, -125, -125, -125, -125, -125,
-     -125, -125, -125,   58, -125, -125,   58,   58,   58,   58,
-       58,   58,  148,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -125
-    },
-
-    {
-       11, -126, -126, -126, -126, -126, -126, -126, -126, -126,
-     -126, -126, -126,   58, -126, -126,   58,   58,   58,   58,
-       58,  149,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -126
-    },
-
-    {
-       11, -127, -127, -127, -127, -127, -127, -127, -127, -127,
-     -127, -127, -127,   58, -127, -127,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -127
-    },
-
-    {
-       11, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-     -128, -128, -128,   58, -128, -128,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  150,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -128
-    },
-
-    {
-       11, -129, -129, -129, -129, -129, -129, -129, -129, -129,
-     -129, -129, -129,   58, -129, -129,   58,   58,   58,  151,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -129
-
-    },
-
-    {
-       11, -130, -130, -130, -130, -130, -130, -130, -130, -130,
-     -130, -130, -130,   58, -130, -130,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  152,
-       58,   58,   58,   58,   58,   58,   58, -130
-    },
-
-    {
-       11, -131, -131, -131, -131, -131, -131, -131, -131, -131,
-     -131, -131, -131,   58, -131, -131,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-      153,   58,   58,   58,   58,   58,   58, -131
-    },
-
-    {
-       11, -132, -132, -132, -132, -132, -132, -132, -132, -132,
-     -132, -132, -132,   58, -132, -132,   58,   58,   58,   58,
-
-       58,  154,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -132
-    },
-
-    {
-       11, -133, -133, -133, -133, -133, -133, -133, -133, -133,
-     -133, -133, -133,   58, -133, -133,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  155,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -133
-    },
-
-    {
-       11, -134, -134, -134, -134, -134, -134, -134, -134, -134,
-     -134, -134, -134,   58, -134, -134,   58,   58,   58,  156,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -134
-
-    },
-
-    {
-       11, -135, -135, -135, -135, -135, -135, -135, -135, -135,
-     -135, -135, -135,   58, -135, -135,   58,   58,   58,  157,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -135
-    },
-
-    {
-       11, -136, -136, -136, -136, -136, -136, -136, -136, -136,
-     -136, -136, -136,   58, -136, -136,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  158,   58,
-       58,   58,   58,   58,   58,   58,   58, -136
-    },
-
-    {
-       11, -137, -137, -137, -137, -137, -137, -137, -137, -137,
-     -137, -137, -137,   58, -137, -137,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  159,   58,   58, -137
-    },
-
-    {
-       11, -138, -138, -138, -138, -138, -138, -138, -138, -138,
-     -138, -138, -138,   58, -138, -138,   58,  160,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -138
-    },
-
-    {
-       11, -139, -139, -139, -139, -139, -139, -139, -139, -139,
-     -139, -139, -139,   58, -139, -139,   58,   58,   58,   58,
-       58,  161,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -139
-
-    },
-
-    {
-       11, -140, -140, -140, -140, -140, -140, -140, -140, -140,
-     -140, -140, -140,   58, -140, -140,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  162,   58,
-       58,   58,   58,   58,   58,   58,   58, -140
-    },
-
-    {
-       11, -141, -141, -141, -141, -141, -141, -141, -141, -141,
-     -141, -141, -141,   58, -141, -141,   58,   58,   58,   58,
-       58,   58,   58,  163,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -141
-    },
-
-    {
-       11, -142, -142, -142, -142, -142, -142, -142, -142, -142,
-     -142, -142, -142,   58, -142, -142,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  164,
-       58,   58,   58,   58,   58,   58,   58, -142
-    },
-
-    {
-       11, -143, -143, -143, -143, -143, -143, -143, -143, -143,
-     -143, -143, -143,   58, -143, -143,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,  165,   58,   58,   58,   58, -143
-    },
-
-    {
-       11, -144, -144, -144, -144, -144, -144, -144, -144, -144,
-     -144, -144, -144,   58, -144, -144,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  166,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -144
-
-    },
-
-    {
-       11, -145, -145, -145, -145, -145, -145, -145, -145, -145,
-     -145, -145, -145,   58, -145, -145,   58,   58,   58,   58,
-      167,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -145
-    },
-
-    {
-       11, -146, -146, -146, -146, -146, -146, -146, -146, -146,
-     -146, -146, -146,   58, -146, -146,   58,   58,   58,   58,
-       58,  168,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -146
-    },
-
-    {
-       11, -147, -147, -147, -147, -147, -147, -147, -147, -147,
-     -147, -147, -147,   58, -147, -147,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  169,
-       58,   58,   58,   58,   58,   58,   58, -147
-    },
-
-    {
-       11, -148, -148, -148, -148, -148, -148, -148, -148, -148,
-     -148, -148, -148,   58, -148, -148,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -148
-    },
-
-    {
-       11, -149, -149, -149, -149, -149, -149, -149, -149, -149,
-     -149, -149, -149,   58, -149, -149,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  170,   58,
-       58,   58,   58,   58,   58,   58,   58, -149
-
-    },
-
-    {
-       11, -150, -150, -150, -150, -150, -150, -150, -150, -150,
-     -150, -150, -150,   58, -150, -150,   58,   58,   58,   58,
-       58,  171,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -150
-    },
-
-    {
-       11, -151, -151, -151, -151, -151, -151, -151, -151, -151,
-     -151, -151, -151,   58, -151, -151,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  172,
-       58,   58,   58,   58,   58,   58,   58, -151
-    },
-
-    {
-       11, -152, -152, -152, -152, -152, -152, -152, -152, -152,
-     -152, -152, -152,   58, -152, -152,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,  173,   58,
-       58,   58,   58,   58,   58,   58,   58, -152
-    },
-
-    {
-       11, -153, -153, -153, -153, -153, -153, -153, -153, -153,
-     -153, -153, -153,   58, -153, -153,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  174,   58,   58, -153
-    },
-
-    {
-       11, -154, -154, -154, -154, -154, -154, -154, -154, -154,
-     -154, -154, -154,   58, -154, -154,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -154
-
-    },
-
-    {
-       11, -155, -155, -155, -155, -155, -155, -155, -155, -155,
-     -155, -155, -155,   58, -155, -155,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,  175,   58,   58,   58,   58, -155
-    },
-
-    {
-       11, -156, -156, -156, -156, -156, -156, -156, -156, -156,
-     -156, -156, -156,   58, -156, -156,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  176,   58,   58, -156
-    },
-
-    {
-       11, -157, -157, -157, -157, -157, -157, -157, -157, -157,
-     -157, -157, -157,   58, -157, -157,   58,   58,   58,   58,
-
-       58,  177,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -157
-    },
-
-    {
-       11, -158, -158, -158, -158, -158, -158, -158, -158, -158,
-     -158, -158, -158,   58, -158, -158,   58,   58,   58,   58,
-       58,   58,   58,  178,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -158
-    },
-
-    {
-       11, -159, -159, -159, -159, -159, -159, -159, -159, -159,
-     -159, -159, -159,   58, -159, -159,   58,  179,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -159
-
-    },
-
-    {
-       11, -160, -160, -160, -160, -160, -160, -160, -160, -160,
-     -160, -160, -160,   58, -160, -160,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  180,   58,
-       58,   58,   58,   58,   58,   58,   58, -160
-    },
-
-    {
-       11, -161, -161, -161, -161, -161, -161, -161, -161, -161,
-     -161, -161, -161,   58, -161, -161,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -161
-    },
-
-    {
-       11, -162, -162, -162, -162, -162, -162, -162, -162, -162,
-     -162, -162, -162,   58, -162, -162,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  181,   58,   58, -162
-    },
-
-    {
-       11, -163, -163, -163, -163, -163, -163, -163, -163, -163,
-     -163, -163, -163,   58, -163, -163,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -163
-    },
-
-    {
-       11, -164, -164, -164, -164, -164, -164, -164, -164, -164,
-     -164, -164, -164,   58, -164, -164,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  182,
-       58,   58,   58,   58,   58,   58,   58, -164
-
-    },
-
-    {
-       11, -165, -165, -165, -165, -165, -165, -165, -165, -165,
-     -165, -165, -165,   58, -165, -165,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  183,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -165
-    },
-
-    {
-       11, -166, -166, -166, -166, -166, -166, -166, -166, -166,
-     -166, -166, -166,   58, -166, -166,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  184,   58,   58, -166
-    },
-
-    {
-       11, -167, -167, -167, -167, -167, -167, -167, -167, -167,
-     -167, -167, -167,   58, -167, -167,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,  185,   58,   58,   58, -167
-    },
-
-    {
-       11, -168, -168, -168, -168, -168, -168, -168, -168, -168,
-     -168, -168, -168,   58, -168, -168,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -168
-    },
-
-    {
-       11, -169, -169, -169, -169, -169, -169, -169, -169, -169,
-     -169, -169, -169,   58, -169, -169,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  186,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -169
-
-    },
-
-    {
-       11, -170, -170, -170, -170, -170, -170, -170, -170, -170,
-     -170, -170, -170,   58, -170, -170,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  187,   58, -170
-    },
-
-    {
-       11, -171, -171, -171, -171, -171, -171, -171, -171, -171,
-     -171, -171, -171,   58, -171, -171,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  188,   58,
-       58,   58,   58,   58,   58,   58,   58, -171
-    },
-
-    {
-       11, -172, -172, -172, -172, -172, -172, -172, -172, -172,
-     -172, -172, -172,   58, -172, -172,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,  189,   58,
-       58,   58,   58,   58,   58,   58,   58, -172
-    },
-
-    {
-       11, -173, -173, -173, -173, -173, -173, -173, -173, -173,
-     -173, -173, -173,   58, -173, -173,   58,  190,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -173
-    },
-
-    {
-       11, -174, -174, -174, -174, -174, -174, -174, -174, -174,
-     -174, -174, -174,   58, -174, -174,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -174
-
-    },
-
-    {
-       11, -175, -175, -175, -175, -175, -175, -175, -175, -175,
-     -175, -175, -175,   58, -175, -175,   58,   58,   58,   58,
-       58,  191,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -175
-    },
-
-    {
-       11, -176, -176, -176, -176, -176, -176, -176, -176, -176,
-     -176, -176, -176,   58, -176, -176,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -176
-    },
-
-    {
-       11, -177, -177, -177, -177, -177, -177, -177, -177, -177,
-     -177, -177, -177,   58, -177, -177,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -177
-    },
-
-    {
-       11, -178, -178, -178, -178, -178, -178, -178, -178, -178,
-     -178, -178, -178,   58, -178, -178,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -178
-    },
-
-    {
-       11, -179, -179, -179, -179, -179, -179, -179, -179, -179,
-     -179, -179, -179,   58, -179, -179,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  192,   58,   58, -179
-
-    },
-
-    {
-       11, -180, -180, -180, -180, -180, -180, -180, -180, -180,
-     -180, -180, -180,   58, -180, -180,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -180
-    },
-
-    {
-       11, -181, -181, -181, -181, -181, -181, -181, -181, -181,
-     -181, -181, -181,   58, -181, -181,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -181
-    },
-
-    {
-       11, -182, -182, -182, -182, -182, -182, -182, -182, -182,
-     -182, -182, -182,   58, -182, -182,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,  193,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -182
-    },
-
-    {
-       11, -183, -183, -183, -183, -183, -183, -183, -183, -183,
-     -183, -183, -183,   58, -183, -183,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,  194,   58,   58,   58, -183
-    },
-
-    {
-       11, -184, -184, -184, -184, -184, -184, -184, -184, -184,
-     -184, -184, -184,   58, -184, -184,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -184
-
-    },
-
-    {
-       11, -185, -185, -185, -185, -185, -185, -185, -185, -185,
-     -185, -185, -185,   58, -185, -185,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -185
-    },
-
-    {
-       11, -186, -186, -186, -186, -186, -186, -186, -186, -186,
-     -186, -186, -186,   58, -186, -186,   58,   58,   58,  195,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -186
-    },
-
-    {
-       11, -187, -187, -187, -187, -187, -187, -187, -187, -187,
-     -187, -187, -187,   58, -187, -187,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -187
-    },
-
-    {
-       11, -188, -188, -188, -188, -188, -188, -188, -188, -188,
-     -188, -188, -188,   58, -188, -188,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  196,   58, -188
-    },
-
-    {
-       11, -189, -189, -189, -189, -189, -189, -189, -189, -189,
-     -189, -189, -189,   58, -189, -189,   58,   58,   58,   58,
-       58,   58,  197,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -189
-
-    },
-
-    {
-       11, -190, -190, -190, -190, -190, -190, -190, -190, -190,
-     -190, -190, -190,   58, -190, -190,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  198,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -190
-    },
-
-    {
-       11, -191, -191, -191, -191, -191, -191, -191, -191, -191,
-     -191, -191, -191,   58, -191, -191,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,  199,   58,   58,   58, -191
-    },
-
-    {
-       11, -192, -192, -192, -192, -192, -192, -192, -192, -192,
-     -192, -192, -192,   58, -192, -192,   58,   58,   58,   58,
-
-       58,  200,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -192
-    },
-
-    {
-       11, -193, -193, -193, -193, -193, -193, -193, -193, -193,
-     -193, -193, -193,   58, -193, -193,   58,   58,   58,   58,
-       58,  201,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -193
-    },
-
-    {
-       11, -194, -194, -194, -194, -194, -194, -194, -194, -194,
-     -194, -194, -194,   58, -194, -194,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  202,   58,   58, -194
-
-    },
-
-    {
-       11, -195, -195, -195, -195, -195, -195, -195, -195, -195,
-     -195, -195, -195,   58, -195, -195,   58,   58,   58,   58,
-       58,  203,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -195
-    },
-
-    {
-       11, -196, -196, -196, -196, -196, -196, -196, -196, -196,
-     -196, -196, -196,   58, -196, -196,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -196
-    },
-
-    {
-       11, -197, -197, -197, -197, -197, -197, -197, -197, -197,
-     -197, -197, -197,   58, -197, -197,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,  204,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -197
-    },
-
-    {
-       11, -198, -198, -198, -198, -198, -198, -198, -198, -198,
-     -198, -198, -198,   58, -198, -198,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -198
-    },
-
-    {
-       11, -199, -199, -199, -199, -199, -199, -199, -199, -199,
-     -199, -199, -199,   58, -199, -199,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -199
-
-    },
-
-    {
-       11, -200, -200, -200, -200, -200, -200, -200, -200, -200,
-     -200, -200, -200,   58, -200, -200,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -200
-    },
-
-    {
-       11, -201, -201, -201, -201, -201, -201, -201, -201, -201,
-     -201, -201, -201,   58, -201, -201,   58,  205,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -201
-    },
-
-    {
-       11, -202, -202, -202, -202, -202, -202, -202, -202, -202,
-     -202, -202, -202,   58, -202, -202,   58,  206,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -202
-    },
-
-    {
-       11, -203, -203, -203, -203, -203, -203, -203, -203, -203,
-     -203, -203, -203,   58, -203, -203,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -203
-    },
-
-    {
-       11, -204, -204, -204, -204, -204, -204, -204, -204, -204,
-     -204, -204, -204,   58, -204, -204,   58,   58,   58,   58,
-       58,   58,   58,  207,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -204
-
-    },
-
-    {
-       11, -205, -205, -205, -205, -205, -205, -205, -205, -205,
-     -205, -205, -205,   58, -205, -205,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  208,   58,
-       58,   58,   58,   58,   58,   58,   58, -205
-    },
-
-    {
-       11, -206, -206, -206, -206, -206, -206, -206, -206, -206,
-     -206, -206, -206,   58, -206, -206,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  209,   58,   58, -206
-    },
-
-    {
-       11, -207, -207, -207, -207, -207, -207, -207, -207, -207,
-     -207, -207, -207,   58, -207, -207,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -207
-    },
-
-    {
-       11, -208, -208, -208, -208, -208, -208, -208, -208, -208,
-     -208, -208, -208,   58, -208, -208,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -208
-    },
-
-    {
-       11, -209, -209, -209, -209, -209, -209, -209, -209, -209,
-     -209, -209, -209,   58, -209, -209,   58,   58,   58,   58,
-       58,  210,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -209
-
-    },
-
-    {
-       11, -210, -210, -210, -210, -210, -210, -210, -210, -210,
-     -210, -210, -210,   58, -210, -210,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -210
+      -60,   57,   57,   57,  -60,  -60,  -60
     },
 
     } ;
@@ -1918,8 +674,8 @@
 	*yy_cp = '\0'; \
 	(yy_c_buf_p) = yy_cp;
 
-#define YY_NUM_RULES 64
-#define YY_END_OF_BUFFER 65
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -1927,31 +683,14 @@
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[211] =
+static yyconst flex_int16_t yy_accept[61] =
     {   0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-       65,    5,    4,    3,    2,   36,   37,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       63,   60,   62,   55,   59,   58,   57,   53,   48,   42,
-       47,   51,   53,   40,   41,   50,   50,   43,   53,   50,
-       50,   53,    4,    3,    2,    2,    1,   35,   35,   35,
-       35,   35,   35,   35,   16,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   63,   60,   62,   61,
-       55,   54,   57,   56,   44,   51,   38,   50,   50,   52,
-       45,   46,   39,   35,   35,   35,   35,   35,   35,   35,
-
-       35,   35,   30,   29,   35,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   49,   25,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   15,   35,    7,   35,
-       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   17,   35,   35,
-       35,   35,   35,   34,   35,   35,   35,   35,   35,   35,
-       10,   35,   13,   35,   35,   35,   35,   33,   35,   35,
-       35,   35,   35,   22,   35,   32,    9,   31,   35,   26,
-       12,   35,   35,   21,   18,   35,    8,   35,   35,   35,
-       35,   35,   27,   35,   35,    6,   35,   20,   19,   23,
-
-       35,   35,   11,   35,   35,   35,   14,   28,   35,   24
+       34,    5,    4,    2,    3,    7,    8,    6,   32,   29,
+       31,   24,   28,   27,   26,   22,   17,   13,   16,   20,
+       22,   11,   12,   19,   19,   14,   22,   22,    4,    2,
+        3,    3,    1,    6,   32,   29,   31,   30,   24,   23,
+       26,   25,   15,   20,    9,   19,   19,   21,   10,   18
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -1965,11 +704,11 @@
        14,    1,    1,    1,   13,   13,   13,   13,   13,   13,
        13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
        13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
-        1,   15,    1,    1,   16,    1,   17,   18,   19,   20,
+        1,   15,    1,    1,   13,    1,   13,   13,   13,   13,
 
-       21,   22,   23,   24,   25,   13,   13,   26,   27,   28,
-       29,   30,   31,   32,   33,   34,   35,   13,   13,   36,
-       13,   13,    1,   37,    1,    1,    1,    1,    1,    1,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,    1,   16,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -2014,8 +753,12 @@
 
 #define START_STRSIZE	16
 
-char *text;
-static char *text_ptr;
+static struct {
+	struct file *file;
+	int lineno;
+} current_pos;
+
+static char *text;
 static int text_size, text_asize;
 
 struct buffer {
@@ -2028,29 +771,28 @@
 static int last_ts, first_ts;
 
 static void zconf_endhelp(void);
-static struct buffer *zconf_endfile(void);
+static void zconf_endfile(void);
 
 void new_string(void)
 {
 	text = malloc(START_STRSIZE);
 	text_asize = START_STRSIZE;
-	text_ptr = text;
 	text_size = 0;
-	*text_ptr = 0;
+	*text = 0;
 }
 
 void append_string(const char *str, int size)
 {
 	int new_size = text_size + size + 1;
 	if (new_size > text_asize) {
+		new_size += START_STRSIZE - 1;
+		new_size &= -START_STRSIZE;
 		text = realloc(text, new_size);
 		text_asize = new_size;
-		text_ptr = text + text_size;
 	}
-	memcpy(text_ptr, str, size);
-	text_ptr += size;
+	memcpy(text + text_size, str, size);
 	text_size += size;
-	*text_ptr = 0;
+	text[text_size] = 0;
 }
 
 void alloc_string(const char *str, int size)
@@ -2066,11 +808,13 @@
 #define STRING 3
 #define PARAM 4
 
+#ifndef YY_NO_UNISTD_H
 /* Special case for "unistd.h", since it is non-ANSI. We include it way
  * down here because we want the user's section 1 to have been scanned first.
  * The user has a chance to override it with an option.
  */
 #include <unistd.h>
+#endif
 
 #ifndef YY_EXTRA_TYPE
 #define YY_EXTRA_TYPE void *
@@ -2254,17 +998,17 @@
 	{ /* beginning of action switch */
 case 1:
 /* rule 1 can match eol */
-YY_RULE_SETUP
-current_file->lineno++;
-	YY_BREAK
 case 2:
+/* rule 2 can match eol */
 YY_RULE_SETUP
-
+{
+	current_file->lineno++;
+	return T_EOL;
+}
 	YY_BREAK
 case 3:
-/* rule 3 can match eol */
 YY_RULE_SETUP
-current_file->lineno++; return T_EOL;
+
 	YY_BREAK
 case 4:
 YY_RULE_SETUP
@@ -2282,175 +1026,63 @@
 
 case 6:
 YY_RULE_SETUP
-BEGIN(PARAM); return T_MAINMENU;
-	YY_BREAK
-case 7:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_MENU;
-	YY_BREAK
-case 8:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_ENDMENU;
-	YY_BREAK
-case 9:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_SOURCE;
-	YY_BREAK
-case 10:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_CHOICE;
-	YY_BREAK
-case 11:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_ENDCHOICE;
-	YY_BREAK
-case 12:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_COMMENT;
-	YY_BREAK
-case 13:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_CONFIG;
-	YY_BREAK
-case 14:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_MENUCONFIG;
-	YY_BREAK
-case 15:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_HELP;
-	YY_BREAK
-case 16:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_IF;
-	YY_BREAK
-case 17:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_ENDIF;
-	YY_BREAK
-case 18:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEPENDS;
-	YY_BREAK
-case 19:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_REQUIRES;
-	YY_BREAK
-case 20:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_OPTIONAL;
-	YY_BREAK
-case 21:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEFAULT;
-	YY_BREAK
-case 22:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_PROMPT;
-	YY_BREAK
-case 23:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_TRISTATE;
-	YY_BREAK
-case 24:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEF_TRISTATE;
-	YY_BREAK
-case 25:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_BOOLEAN;
-	YY_BREAK
-case 26:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_BOOLEAN;
-	YY_BREAK
-case 27:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEF_BOOLEAN;
-	YY_BREAK
-case 28:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEF_BOOLEAN;
-	YY_BREAK
-case 29:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_INT;
-	YY_BREAK
-case 30:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_HEX;
-	YY_BREAK
-case 31:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_STRING;
-	YY_BREAK
-case 32:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_SELECT;
-	YY_BREAK
-case 33:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_SELECT;
-	YY_BREAK
-case 34:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_RANGE;
-	YY_BREAK
-case 35:
-YY_RULE_SETUP
 {
+		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		BEGIN(PARAM);
+		current_pos.file = current_file;
+		current_pos.lineno = current_file->lineno;
+		if (id && id->flags & TF_COMMAND) {
+			zconflval.id = id;
+			return id->token;
+		}
 		alloc_string(zconftext, zconfleng);
 		zconflval.string = text;
 		return T_WORD;
 	}
 	YY_BREAK
-case 36:
+case 7:
 YY_RULE_SETUP
 
 	YY_BREAK
-case 37:
-/* rule 37 can match eol */
+case 8:
+/* rule 8 can match eol */
 YY_RULE_SETUP
-current_file->lineno++; BEGIN(INITIAL);
+{
+		BEGIN(INITIAL);
+		current_file->lineno++;
+		return T_EOL;
+	}
 	YY_BREAK
 
-case 38:
+case 9:
 YY_RULE_SETUP
 return T_AND;
 	YY_BREAK
-case 39:
+case 10:
 YY_RULE_SETUP
 return T_OR;
 	YY_BREAK
-case 40:
+case 11:
 YY_RULE_SETUP
 return T_OPEN_PAREN;
 	YY_BREAK
-case 41:
+case 12:
 YY_RULE_SETUP
 return T_CLOSE_PAREN;
 	YY_BREAK
-case 42:
+case 13:
 YY_RULE_SETUP
 return T_NOT;
 	YY_BREAK
-case 43:
+case 14:
 YY_RULE_SETUP
 return T_EQUAL;
 	YY_BREAK
-case 44:
+case 15:
 YY_RULE_SETUP
 return T_UNEQUAL;
 	YY_BREAK
-case 45:
-YY_RULE_SETUP
-return T_IF;
-	YY_BREAK
-case 46:
-YY_RULE_SETUP
-return T_ON;
-	YY_BREAK
-case 47:
+case 16:
 YY_RULE_SETUP
 {
 		str = zconftext[0];
@@ -2458,33 +1090,38 @@
 		BEGIN(STRING);
 	}
 	YY_BREAK
-case 48:
-/* rule 48 can match eol */
+case 17:
+/* rule 17 can match eol */
 YY_RULE_SETUP
 BEGIN(INITIAL); current_file->lineno++; return T_EOL;
 	YY_BREAK
-case 49:
+case 18:
 YY_RULE_SETUP
 /* ignore */
 	YY_BREAK
-case 50:
+case 19:
 YY_RULE_SETUP
 {
+		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		if (id && id->flags & TF_PARAM) {
+			zconflval.id = id;
+			return id->token;
+		}
 		alloc_string(zconftext, zconfleng);
 		zconflval.string = text;
 		return T_WORD;
 	}
 	YY_BREAK
-case 51:
+case 20:
 YY_RULE_SETUP
 /* comment */
 	YY_BREAK
-case 52:
-/* rule 52 can match eol */
+case 21:
+/* rule 21 can match eol */
 YY_RULE_SETUP
 current_file->lineno++;
 	YY_BREAK
-case 53:
+case 22:
 YY_RULE_SETUP
 
 	YY_BREAK
@@ -2494,8 +1131,8 @@
 	}
 	YY_BREAK
 
-case 54:
-/* rule 54 can match eol */
+case 23:
+/* rule 23 can match eol */
 *yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
 (yy_c_buf_p) = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up zconftext again */
@@ -2506,14 +1143,14 @@
 		return T_WORD_QUOTE;
 	}
 	YY_BREAK
-case 55:
+case 24:
 YY_RULE_SETUP
 {
 		append_string(zconftext, zconfleng);
 	}
 	YY_BREAK
-case 56:
-/* rule 56 can match eol */
+case 25:
+/* rule 25 can match eol */
 *yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
 (yy_c_buf_p) = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up zconftext again */
@@ -2524,13 +1161,13 @@
 		return T_WORD_QUOTE;
 	}
 	YY_BREAK
-case 57:
+case 26:
 YY_RULE_SETUP
 {
 		append_string(zconftext + 1, zconfleng - 1);
 	}
 	YY_BREAK
-case 58:
+case 27:
 YY_RULE_SETUP
 {
 		if (str == zconftext[0]) {
@@ -2541,8 +1178,8 @@
 			append_string(zconftext, 1);
 	}
 	YY_BREAK
-case 59:
-/* rule 59 can match eol */
+case 28:
+/* rule 28 can match eol */
 YY_RULE_SETUP
 {
 		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
@@ -2557,7 +1194,7 @@
 	}
 	YY_BREAK
 
-case 60:
+case 29:
 YY_RULE_SETUP
 {
 		ts = 0;
@@ -2582,8 +1219,8 @@
 		}
 	}
 	YY_BREAK
-case 61:
-/* rule 61 can match eol */
+case 30:
+/* rule 30 can match eol */
 *yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
 (yy_c_buf_p) = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up zconftext again */
@@ -2594,15 +1231,15 @@
 		return T_HELPTEXT;
 	}
 	YY_BREAK
-case 62:
-/* rule 62 can match eol */
+case 31:
+/* rule 31 can match eol */
 YY_RULE_SETUP
 {
 		current_file->lineno++;
 		append_string("\n", 1);
 	}
 	YY_BREAK
-case 63:
+case 32:
 YY_RULE_SETUP
 {
 		append_string(zconftext, zconfleng);
@@ -2620,15 +1257,15 @@
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(COMMAND):
 {
-	if (current_buf) {
+	if (current_file) {
 		zconf_endfile();
-		return T_EOF;
+		return T_EOL;
 	}
 	fclose(zconfin);
 	yyterminate();
 }
 	YY_BREAK
-case 64:
+case 33:
 YY_RULE_SETUP
 YY_FATAL_ERROR( "flex scanner jammed" );
 	YY_BREAK
@@ -3332,16 +1969,16 @@
 
 /** Setup the input buffer state to scan a string. The next call to zconflex() will
  * scan from a @e copy of @a str.
- * @param str a NUL-terminated string to scan
+ * @param yy_str a NUL-terminated string to scan
  * 
  * @return the newly allocated buffer state object.
  * @note If you want to scan bytes that may contain NUL values, then use
  *       zconf_scan_bytes() instead.
  */
-YY_BUFFER_STATE zconf_scan_string (yyconst char * str )
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yy_str )
 {
     
-	return zconf_scan_bytes(str,strlen(str) );
+	return zconf_scan_bytes(yy_str,strlen(yy_str) );
 }
 
 /** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
@@ -3650,7 +2287,7 @@
 	current_file = file;
 }
 
-static struct buffer *zconf_endfile(void)
+static void zconf_endfile(void)
 {
 	struct buffer *parent;
 
@@ -3666,23 +2303,15 @@
 	}
 	free(current_buf);
 	current_buf = parent;
-
-	return parent;
 }
 
 int zconf_lineno(void)
 {
-	if (current_buf)
-		return current_file->lineno - 1;
-	else
-		return 0;
+	return current_pos.lineno;
 }
 
 char *zconf_curname(void)
 {
-	if (current_buf)
-		return current_file->name;
-	else
-		return "<none>";
+	return current_pos.file ? current_pos.file->name : "<none>";
 }
 
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 5fba1fe..527f60c 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -37,6 +37,17 @@
 #define _(text) gettext(text)
 #define N_(text) (text)
 
+
+#define TF_COMMAND	0x0001
+#define TF_PARAM	0x0002
+
+struct kconf_id {
+	int name;
+	int token;
+	unsigned int flags;
+	enum symbol_type stype;
+};
+
 int zconfparse(void);
 void zconfdump(FILE *out);
 
@@ -50,7 +61,6 @@
 
 /* confdata.c */
 extern const char conf_def_filename[];
-extern char conf_filename[];
 
 char *conf_get_default_confname(void);
 
@@ -59,7 +69,7 @@
 
 /* menu.c */
 void menu_init(void);
-void menu_add_menu(void);
+struct menu *menu_add_menu(void);
 void menu_end_menu(void);
 void menu_add_entry(struct symbol *sym);
 void menu_end_entry(void);
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 6dc6d0c..b6a389c 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -2,6 +2,7 @@
 /* confdata.c */
 P(conf_parse,void,(const char *name));
 P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name));
 P(conf_write,int,(const char *name));
 
 /* menu.c */
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 5cfa6c4..0fce20c 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -61,10 +61,11 @@
 {
 }
 
-void menu_add_menu(void)
+struct menu *menu_add_menu(void)
 {
-	current_menu = current_entry;
+	menu_end_entry();
 	last_entry_ptr = &current_entry->list;
+	return current_menu = current_entry;
 }
 
 void menu_end_menu(void)
@@ -151,6 +152,12 @@
 	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
 }
 
+static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
+{
+	return sym2->type == S_INT || sym2->type == S_HEX ||
+	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
 void sym_check_prop(struct symbol *sym)
 {
 	struct property *prop;
@@ -185,8 +192,8 @@
 			if (sym->type != S_INT && sym->type != S_HEX)
 				prop_warn(prop, "range is only allowed "
 				                "for int or hex symbols");
-			if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
-			    !sym_string_valid(sym, prop->expr->right.sym->name))
+			if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
+			    !menu_range_valid_sym(sym, prop->expr->right.sym))
 				prop_warn(prop, "range is invalid");
 			break;
 		default:
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index affa52f..69c2549 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -141,6 +141,55 @@
 	return NULL;
 }
 
+static int sym_get_range_val(struct symbol *sym, int base)
+{
+	sym_calc_value(sym);
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		break;
+	}
+	return strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+	struct property *prop;
+	int base, val, val2;
+	char str[64];
+
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		return;
+	}
+	prop = sym_get_range_prop(sym);
+	if (!prop)
+		return;
+	val = strtol(sym->curr.val, NULL, base);
+	val2 = sym_get_range_val(prop->expr->left.sym, base);
+	if (val >= val2) {
+		val2 = sym_get_range_val(prop->expr->right.sym, base);
+		if (val <= val2)
+			return;
+	}
+	if (sym->type == S_INT)
+		sprintf(str, "%d", val2);
+	else
+		sprintf(str, "0x%x", val2);
+	sym->curr.val = strdup(str);
+}
+
 static void sym_calc_visibility(struct symbol *sym)
 {
 	struct property *prop;
@@ -301,6 +350,7 @@
 	sym->curr = newval;
 	if (sym_is_choice(sym) && newval.tri == yes)
 		sym->curr.val = sym_calc_choice(sym);
+	sym_validate_range(sym);
 
 	if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
 		sym_set_changed(sym);
@@ -380,11 +430,22 @@
 		sym->flags &= ~SYMBOL_NEW;
 		sym_set_changed(sym);
 	}
+	/*
+	 * setting a choice value also resets the new flag of the choice
+	 * symbol and all other choice values.
+	 */
 	if (sym_is_choice_value(sym) && val == yes) {
 		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+		struct property *prop;
+		struct expr *e;
 
 		cs->user.val = sym;
 		cs->flags &= ~SYMBOL_NEW;
+		prop = sym_get_choice_prop(cs);
+		for (e = prop->expr; e; e = e->left.expr) {
+			if (e->right.sym->visible != no)
+				e->right.sym->flags &= ~SYMBOL_NEW;
+		}
 	}
 
 	sym->user.tri = val;
@@ -478,8 +539,8 @@
 		if (!prop)
 			return true;
 		val = strtol(str, NULL, 10);
-		return val >= strtol(prop->expr->left.sym->name, NULL, 10) &&
-		       val <= strtol(prop->expr->right.sym->name, NULL, 10);
+		return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 10);
 	case S_HEX:
 		if (!sym_string_valid(sym, str))
 			return false;
@@ -487,8 +548,8 @@
 		if (!prop)
 			return true;
 		val = strtol(str, NULL, 16);
-		return val >= strtol(prop->expr->left.sym->name, NULL, 16) &&
-		       val <= strtol(prop->expr->right.sym->name, NULL, 16);
+		return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 16);
 	case S_BOOLEAN:
 	case S_TRISTATE:
 		switch (str[0]) {
@@ -731,12 +792,12 @@
 	struct symbol *sym2;
 	struct property *prop;
 
-	if (sym->flags & SYMBOL_CHECK_DONE)
-		return NULL;
 	if (sym->flags & SYMBOL_CHECK) {
 		printf("Warning! Found recursive dependency: %s", sym->name);
 		return sym;
 	}
+	if (sym->flags & SYMBOL_CHECKED)
+		return NULL;
 
 	sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
 	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
@@ -756,8 +817,13 @@
 			goto out;
 	}
 out:
-	if (sym2)
+	if (sym2) {
 		printf(" %s", sym->name);
+		if (sym2 == sym) {
+			printf("\n");
+			sym2 = NULL;
+		}
+	}
 	sym->flags &= ~SYMBOL_CHECK;
 	return sym2;
 }
diff --git a/scripts/kconfig/zconf.gperf b/scripts/kconfig/zconf.gperf
new file mode 100644
index 0000000..b032206
--- /dev/null
+++ b/scripts/kconfig/zconf.gperf
@@ -0,0 +1,43 @@
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+%%
+mainmenu,	T_MAINMENU,	TF_COMMAND
+menu,		T_MENU,		TF_COMMAND
+endmenu,	T_ENDMENU,	TF_COMMAND
+source,		T_SOURCE,	TF_COMMAND
+choice,		T_CHOICE,	TF_COMMAND
+endchoice,	T_ENDCHOICE,	TF_COMMAND
+comment,	T_COMMENT,	TF_COMMAND
+config,		T_CONFIG,	TF_COMMAND
+menuconfig,	T_MENUCONFIG,	TF_COMMAND
+help,		T_HELP,		TF_COMMAND
+if,		T_IF,		TF_COMMAND|TF_PARAM
+endif,		T_ENDIF,	TF_COMMAND
+depends,	T_DEPENDS,	TF_COMMAND
+requires,	T_REQUIRES,	TF_COMMAND
+optional,	T_OPTIONAL,	TF_COMMAND
+default,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN
+prompt,		T_PROMPT,	TF_COMMAND
+tristate,	T_TYPE,		TF_COMMAND, S_TRISTATE
+def_tristate,	T_DEFAULT,	TF_COMMAND, S_TRISTATE
+bool,		T_TYPE,		TF_COMMAND, S_BOOLEAN
+boolean,	T_TYPE,		TF_COMMAND, S_BOOLEAN
+def_bool,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN
+def_boolean,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN
+int,		T_TYPE,		TF_COMMAND, S_INT
+hex,		T_TYPE,		TF_COMMAND, S_HEX
+string,		T_TYPE,		TF_COMMAND, S_STRING
+select,		T_SELECT,	TF_COMMAND
+enable,		T_SELECT,	TF_COMMAND
+range,		T_RANGE,	TF_COMMAND
+on,		T_ON,		TF_PARAM
+%%
diff --git a/scripts/kconfig/zconf.hash.c_shipped b/scripts/kconfig/zconf.hash.c_shipped
new file mode 100644
index 0000000..345f0fc
--- /dev/null
+++ b/scripts/kconfig/zconf.hash.c_shipped
@@ -0,0 +1,231 @@
+/* ANSI-C code produced by gperf version 3.0.1 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+struct kconf_id;
+/* maximum key range = 45, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+  static unsigned char asso_values[] =
+    {
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 25, 10, 15,
+       0,  0,  5, 47,  0,  0, 47, 47,  0, 10,
+       0, 20, 20, 20,  5,  0,  0, 20, 47, 47,
+      20, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[2]];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("if")];
+    char kconf_id_strings_str3[sizeof("int")];
+    char kconf_id_strings_str4[sizeof("help")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("select")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
+    char kconf_id_strings_str8[sizeof("tristate")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("string")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("menu")];
+    char kconf_id_strings_str16[sizeof("def_boolean")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("mainmenu")];
+    char kconf_id_strings_str20[sizeof("menuconfig")];
+    char kconf_id_strings_str21[sizeof("config")];
+    char kconf_id_strings_str22[sizeof("on")];
+    char kconf_id_strings_str23[sizeof("hex")];
+    char kconf_id_strings_str26[sizeof("source")];
+    char kconf_id_strings_str27[sizeof("depends")];
+    char kconf_id_strings_str28[sizeof("optional")];
+    char kconf_id_strings_str31[sizeof("enable")];
+    char kconf_id_strings_str32[sizeof("comment")];
+    char kconf_id_strings_str33[sizeof("requires")];
+    char kconf_id_strings_str34[sizeof("bool")];
+    char kconf_id_strings_str37[sizeof("boolean")];
+    char kconf_id_strings_str41[sizeof("choice")];
+    char kconf_id_strings_str46[sizeof("prompt")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "if",
+    "int",
+    "help",
+    "endif",
+    "select",
+    "endmenu",
+    "tristate",
+    "endchoice",
+    "range",
+    "string",
+    "default",
+    "def_bool",
+    "menu",
+    "def_boolean",
+    "def_tristate",
+    "mainmenu",
+    "menuconfig",
+    "config",
+    "on",
+    "hex",
+    "source",
+    "depends",
+    "optional",
+    "enable",
+    "comment",
+    "requires",
+    "bool",
+    "boolean",
+    "choice",
+    "prompt"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 30,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 12,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 46
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_IF,		TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,		T_TYPE,		TF_COMMAND, S_INT},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4,		T_HELP,		TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,		T_ENDIF,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,		T_SELECT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_ENDMENU,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_TYPE,		TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,	T_ENDCHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,		T_RANGE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,		T_TYPE,		TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,		T_MENU,		TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,	T_MAINMENU,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20,	T_MENUCONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,		T_CONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,		T_ON,		TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,		T_TYPE,		TF_COMMAND, S_HEX},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,		T_SOURCE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_DEPENDS,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,	T_OPTIONAL,	TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_SELECT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_COMMENT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,	T_REQUIRES,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,		T_CHOICE,	TF_COMMAND},
+      {-1}, {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46,		T_PROMPT,	TF_COMMAND}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = kconf_id_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int o = wordlist[key].name;
+          if (o >= 0)
+            {
+              register const char *s = o + kconf_id_strings;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[key];
+            }
+        }
+    }
+  return 0;
+}
+
diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l
index 55517b2..cfa4607 100644
--- a/scripts/kconfig/zconf.l
+++ b/scripts/kconfig/zconf.l
@@ -18,8 +18,12 @@
 
 #define START_STRSIZE	16
 
-char *text;
-static char *text_ptr;
+static struct {
+	struct file *file;
+	int lineno;
+} current_pos;
+
+static char *text;
 static int text_size, text_asize;
 
 struct buffer {
@@ -32,29 +36,28 @@
 static int last_ts, first_ts;
 
 static void zconf_endhelp(void);
-static struct buffer *zconf_endfile(void);
+static void zconf_endfile(void);
 
 void new_string(void)
 {
 	text = malloc(START_STRSIZE);
 	text_asize = START_STRSIZE;
-	text_ptr = text;
 	text_size = 0;
-	*text_ptr = 0;
+	*text = 0;
 }
 
 void append_string(const char *str, int size)
 {
 	int new_size = text_size + size + 1;
 	if (new_size > text_asize) {
+		new_size += START_STRSIZE - 1;
+		new_size &= -START_STRSIZE;
 		text = realloc(text, new_size);
 		text_asize = new_size;
-		text_ptr = text + text_size;
 	}
-	memcpy(text_ptr, str, size);
-	text_ptr += size;
+	memcpy(text + text_size, str, size);
 	text_size += size;
-	*text_ptr = 0;
+	text[text_size] = 0;
 }
 
 void alloc_string(const char *str, int size)
@@ -72,10 +75,13 @@
 	int str = 0;
 	int ts, i;
 
-[ \t]*#.*\n	current_file->lineno++;
+[ \t]*#.*\n	|
+[ \t]*\n	{
+	current_file->lineno++;
+	return T_EOL;
+}
 [ \t]*#.*
 
-[ \t]*\n	current_file->lineno++; return T_EOL;
 
 [ \t]+	{
 	BEGIN(COMMAND);
@@ -88,42 +94,25 @@
 
 
 <COMMAND>{
-	"mainmenu"		BEGIN(PARAM); return T_MAINMENU;
-	"menu"			BEGIN(PARAM); return T_MENU;
-	"endmenu"		BEGIN(PARAM); return T_ENDMENU;
-	"source"		BEGIN(PARAM); return T_SOURCE;
-	"choice"		BEGIN(PARAM); return T_CHOICE;
-	"endchoice"		BEGIN(PARAM); return T_ENDCHOICE;
-	"comment"		BEGIN(PARAM); return T_COMMENT;
-	"config"		BEGIN(PARAM); return T_CONFIG;
-	"menuconfig"		BEGIN(PARAM); return T_MENUCONFIG;
-	"help"			BEGIN(PARAM); return T_HELP;
-	"if"			BEGIN(PARAM); return T_IF;
-	"endif"			BEGIN(PARAM); return T_ENDIF;
-	"depends"		BEGIN(PARAM); return T_DEPENDS;
-	"requires"		BEGIN(PARAM); return T_REQUIRES;
-	"optional"		BEGIN(PARAM); return T_OPTIONAL;
-	"default"		BEGIN(PARAM); return T_DEFAULT;
-	"prompt"		BEGIN(PARAM); return T_PROMPT;
-	"tristate"		BEGIN(PARAM); return T_TRISTATE;
-	"def_tristate"		BEGIN(PARAM); return T_DEF_TRISTATE;
-	"bool"			BEGIN(PARAM); return T_BOOLEAN;
-	"boolean"		BEGIN(PARAM); return T_BOOLEAN;
-	"def_bool"		BEGIN(PARAM); return T_DEF_BOOLEAN;
-	"def_boolean"		BEGIN(PARAM); return T_DEF_BOOLEAN;
-	"int"			BEGIN(PARAM); return T_INT;
-	"hex"			BEGIN(PARAM); return T_HEX;
-	"string"		BEGIN(PARAM); return T_STRING;
-	"select"		BEGIN(PARAM); return T_SELECT;
-	"enable"		BEGIN(PARAM); return T_SELECT;
-	"range"			BEGIN(PARAM); return T_RANGE;
 	{n}+	{
+		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		BEGIN(PARAM);
+		current_pos.file = current_file;
+		current_pos.lineno = current_file->lineno;
+		if (id && id->flags & TF_COMMAND) {
+			zconflval.id = id;
+			return id->token;
+		}
 		alloc_string(yytext, yyleng);
 		zconflval.string = text;
 		return T_WORD;
 	}
 	.
-	\n	current_file->lineno++; BEGIN(INITIAL);
+	\n	{
+		BEGIN(INITIAL);
+		current_file->lineno++;
+		return T_EOL;
+	}
 }
 
 <PARAM>{
@@ -134,8 +123,6 @@
 	"!"	return T_NOT;
 	"="	return T_EQUAL;
 	"!="	return T_UNEQUAL;
-	"if"	return T_IF;
-	"on"	return T_ON;
 	\"|\'	{
 		str = yytext[0];
 		new_string();
@@ -144,6 +131,11 @@
 	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
 	---	/* ignore */
 	({n}|[-/.])+	{
+		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		if (id && id->flags & TF_PARAM) {
+			zconflval.id = id;
+			return id->token;
+		}
 		alloc_string(yytext, yyleng);
 		zconflval.string = text;
 		return T_WORD;
@@ -236,9 +228,9 @@
 }
 
 <<EOF>>	{
-	if (current_buf) {
+	if (current_file) {
 		zconf_endfile();
-		return T_EOF;
+		return T_EOL;
 	}
 	fclose(yyin);
 	yyterminate();
@@ -329,7 +321,7 @@
 	current_file = file;
 }
 
-static struct buffer *zconf_endfile(void)
+static void zconf_endfile(void)
 {
 	struct buffer *parent;
 
@@ -345,22 +337,14 @@
 	}
 	free(current_buf);
 	current_buf = parent;
-
-	return parent;
 }
 
 int zconf_lineno(void)
 {
-	if (current_buf)
-		return current_file->lineno - 1;
-	else
-		return 0;
+	return current_pos.lineno;
 }
 
 char *zconf_curname(void)
 {
-	if (current_buf)
-		return current_file->name;
-	else
-		return "<none>";
+	return current_pos.file ? current_pos.file->name : "<none>";
 }
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index ff4fcc0..ea7755d 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -1,7 +1,7 @@
-/* A Bison parser, made by GNU Bison 1.875a.  */
+/* A Bison parser, made by GNU Bison 2.0.  */
 
 /* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, 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
@@ -45,8 +45,7 @@
 /* Using locations.  */
 #define YYLSP_NEEDED 0
 
-/* If NAME_PREFIX is specified substitute the variables and functions
-   names.  */
+/* Substitute the variable and function names.  */
 #define yyparse zconfparse
 #define yylex   zconflex
 #define yyerror zconferror
@@ -79,28 +78,21 @@
      T_REQUIRES = 272,
      T_OPTIONAL = 273,
      T_PROMPT = 274,
-     T_DEFAULT = 275,
-     T_TRISTATE = 276,
-     T_DEF_TRISTATE = 277,
-     T_BOOLEAN = 278,
-     T_DEF_BOOLEAN = 279,
-     T_STRING = 280,
-     T_INT = 281,
-     T_HEX = 282,
-     T_WORD = 283,
-     T_WORD_QUOTE = 284,
-     T_UNEQUAL = 285,
-     T_EOF = 286,
-     T_EOL = 287,
-     T_CLOSE_PAREN = 288,
-     T_OPEN_PAREN = 289,
-     T_ON = 290,
-     T_SELECT = 291,
-     T_RANGE = 292,
-     T_OR = 293,
-     T_AND = 294,
-     T_EQUAL = 295,
-     T_NOT = 296
+     T_TYPE = 275,
+     T_DEFAULT = 276,
+     T_SELECT = 277,
+     T_RANGE = 278,
+     T_ON = 279,
+     T_WORD = 280,
+     T_WORD_QUOTE = 281,
+     T_UNEQUAL = 282,
+     T_CLOSE_PAREN = 283,
+     T_OPEN_PAREN = 284,
+     T_EOL = 285,
+     T_OR = 286,
+     T_AND = 287,
+     T_EQUAL = 288,
+     T_NOT = 289
    };
 #endif
 #define T_MAINMENU 258
@@ -120,28 +112,21 @@
 #define T_REQUIRES 272
 #define T_OPTIONAL 273
 #define T_PROMPT 274
-#define T_DEFAULT 275
-#define T_TRISTATE 276
-#define T_DEF_TRISTATE 277
-#define T_BOOLEAN 278
-#define T_DEF_BOOLEAN 279
-#define T_STRING 280
-#define T_INT 281
-#define T_HEX 282
-#define T_WORD 283
-#define T_WORD_QUOTE 284
-#define T_UNEQUAL 285
-#define T_EOF 286
-#define T_EOL 287
-#define T_CLOSE_PAREN 288
-#define T_OPEN_PAREN 289
-#define T_ON 290
-#define T_SELECT 291
-#define T_RANGE 292
-#define T_OR 293
-#define T_AND 294
-#define T_EQUAL 295
-#define T_NOT 296
+#define T_TYPE 275
+#define T_DEFAULT 276
+#define T_SELECT 277
+#define T_RANGE 278
+#define T_ON 279
+#define T_WORD 280
+#define T_WORD_QUOTE 281
+#define T_UNEQUAL 282
+#define T_CLOSE_PAREN 283
+#define T_OPEN_PAREN 284
+#define T_EOL 285
+#define T_OR 286
+#define T_AND 287
+#define T_EQUAL 288
+#define T_NOT 289
 
 
 
@@ -161,6 +146,11 @@
 #include <string.h>
 #include <stdbool.h>
 
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
 
 #define PRINTD		0x0001
@@ -170,14 +160,18 @@
 
 extern int zconflex(void);
 static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
 static void zconferror(const char *err);
-static bool zconf_endtoken(int token, int starttoken, int endtoken);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
 
 struct symbol *symbol_hash[257];
 
 static struct menu *current_menu, *current_entry;
 
+#define YYDEBUG 0
+#if YYDEBUG
 #define YYERROR_VERBOSE
+#endif
 
 
 /* Enabling traces.  */
@@ -196,13 +190,14 @@
 #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
 
 typedef union YYSTYPE {
-	int token;
 	char *string;
+	struct file *file;
 	struct symbol *symbol;
 	struct expr *expr;
 	struct menu *menu;
+	struct kconf_id *id;
 } YYSTYPE;
-/* Line 191 of yacc.c.  */
+/* Line 190 of yacc.c.  */
 
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -214,27 +209,26 @@
 /* Copy the second part of user declarations.  */
 
 
-#define LKC_DIRECT_LINK
-#include "lkc.h"
-
-
-/* Line 214 of yacc.c.  */
+/* Line 213 of yacc.c.  */
 
 
 #if ! defined (yyoverflow) || YYERROR_VERBOSE
 
+# ifndef YYFREE
+#  define YYFREE free
+# endif
+# ifndef YYMALLOC
+#  define YYMALLOC malloc
+# endif
+
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
-# if YYSTACK_USE_ALLOCA
-#  define YYSTACK_ALLOC alloca
-# else
-#  ifndef YYSTACK_USE_ALLOCA
-#   if defined (alloca) || defined (_ALLOCA_H)
-#    define YYSTACK_ALLOC alloca
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
 #   else
-#    ifdef __GNUC__
-#     define YYSTACK_ALLOC __builtin_alloca
-#    endif
+#    define YYSTACK_ALLOC alloca
 #   endif
 #  endif
 # endif
@@ -247,20 +241,20 @@
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
 #   define YYSIZE_T size_t
 #  endif
-#  define YYSTACK_ALLOC malloc
-#  define YYSTACK_FREE free
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
 # endif
 #endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
 
 
 #if (! defined (yyoverflow) \
      && (! defined (__cplusplus) \
-	 || (YYSTYPE_IS_TRIVIAL)))
+	 || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
 
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  short yyss;
+  short int yyss;
   YYSTYPE yyvs;
   };
 
@@ -270,13 +264,13 @@
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (short) + sizeof (YYSTYPE))				\
+     ((N) * (sizeof (short int) + sizeof (YYSTYPE))			\
       + YYSTACK_GAP_MAXIMUM)
 
 /* Copy COUNT objects from FROM to TO.  The source and destination do
    not overlap.  */
 # ifndef YYCOPY
-#  if 1 < __GNUC__
+#  if defined (__GNUC__) && 1 < __GNUC__
 #   define YYCOPY(To, From, Count) \
       __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
 #  else
@@ -312,26 +306,26 @@
 #if defined (__STDC__) || defined (__cplusplus)
    typedef signed char yysigned_char;
 #else
-   typedef short yysigned_char;
+   typedef short int yysigned_char;
 #endif
 
 /* YYFINAL -- State number of the termination state. */
-#define YYFINAL  2
+#define YYFINAL  3
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   201
+#define YYLAST   264
 
 /* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS  42
+#define YYNTOKENS  35
 /* YYNNTS -- Number of nonterminals. */
-#define YYNNTS  41
+#define YYNNTS  42
 /* YYNRULES -- Number of rules. */
 #define YYNRULES  104
 /* YYNRULES -- Number of states. */
-#define YYNSTATES  182
+#define YYNSTATES  175
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   296
+#define YYMAXUTOK   289
 
 #define YYTRANSLATE(YYX) 						\
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -367,79 +361,78 @@
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
        5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,    38,    39,    40,    41
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34
 };
 
 #if YYDEBUG
 /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
    YYRHS.  */
-static const unsigned short yyprhs[] =
+static const unsigned short int yyprhs[] =
 {
-       0,     0,     3,     4,     7,     9,    11,    13,    17,    19,
-      21,    23,    26,    28,    30,    32,    34,    36,    38,    42,
-      45,    49,    52,    53,    56,    59,    62,    65,    69,    74,
-      78,    83,    87,    91,    95,   100,   105,   110,   116,   119,
-     122,   124,   128,   131,   132,   135,   138,   141,   144,   149,
-     153,   157,   160,   165,   166,   169,   173,   175,   179,   182,
-     183,   186,   189,   192,   196,   199,   201,   205,   208,   209,
-     212,   215,   218,   222,   226,   228,   232,   235,   238,   241,
-     242,   245,   248,   253,   257,   261,   262,   265,   267,   269,
-     272,   275,   278,   280,   282,   283,   286,   288,   292,   296,
-     300,   303,   307,   311,   313
+       0,     0,     3,     5,     6,     9,    12,    15,    20,    23,
+      28,    33,    37,    39,    41,    43,    45,    47,    49,    51,
+      53,    55,    57,    59,    61,    63,    67,    70,    74,    77,
+      81,    84,    85,    88,    91,    94,    97,   100,   104,   109,
+     114,   119,   125,   128,   131,   133,   137,   138,   141,   144,
+     147,   150,   153,   158,   162,   165,   170,   171,   174,   178,
+     180,   184,   185,   188,   191,   194,   198,   201,   203,   207,
+     208,   211,   214,   217,   221,   225,   228,   231,   234,   235,
+     238,   241,   244,   249,   253,   257,   258,   261,   263,   265,
+     268,   271,   274,   276,   279,   280,   283,   285,   289,   293,
+     297,   300,   304,   308,   310
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS. */
 static const yysigned_char yyrhs[] =
 {
-      43,     0,    -1,    -1,    43,    44,    -1,    45,    -1,    55,
-      -1,    66,    -1,     3,    77,    79,    -1,     5,    -1,    15,
-      -1,     8,    -1,     1,    79,    -1,    61,    -1,    71,    -1,
-      47,    -1,    49,    -1,    69,    -1,    79,    -1,    10,    28,
-      32,    -1,    46,    50,    -1,    11,    28,    32,    -1,    48,
-      50,    -1,    -1,    50,    51,    -1,    50,    75,    -1,    50,
-      73,    -1,    50,    32,    -1,    21,    76,    32,    -1,    22,
-      81,    80,    32,    -1,    23,    76,    32,    -1,    24,    81,
-      80,    32,    -1,    26,    76,    32,    -1,    27,    76,    32,
-      -1,    25,    76,    32,    -1,    19,    77,    80,    32,    -1,
-      20,    81,    80,    32,    -1,    36,    28,    80,    32,    -1,
-      37,    82,    82,    80,    32,    -1,     7,    32,    -1,    52,
-      56,    -1,    78,    -1,    53,    58,    54,    -1,    53,    58,
-      -1,    -1,    56,    57,    -1,    56,    75,    -1,    56,    73,
-      -1,    56,    32,    -1,    19,    77,    80,    32,    -1,    21,
-      76,    32,    -1,    23,    76,    32,    -1,    18,    32,    -1,
-      20,    28,    80,    32,    -1,    -1,    58,    45,    -1,    14,
-      81,    32,    -1,    78,    -1,    59,    62,    60,    -1,    59,
-      62,    -1,    -1,    62,    45,    -1,    62,    66,    -1,    62,
-      55,    -1,     4,    77,    32,    -1,    63,    74,    -1,    78,
-      -1,    64,    67,    65,    -1,    64,    67,    -1,    -1,    67,
-      45,    -1,    67,    66,    -1,    67,    55,    -1,    67,     1,
-      32,    -1,     6,    77,    32,    -1,    68,    -1,     9,    77,
-      32,    -1,    70,    74,    -1,    12,    32,    -1,    72,    13,
-      -1,    -1,    74,    75,    -1,    74,    32,    -1,    16,    35,
-      81,    32,    -1,    16,    81,    32,    -1,    17,    81,    32,
-      -1,    -1,    77,    80,    -1,    28,    -1,    29,    -1,     5,
-      79,    -1,     8,    79,    -1,    15,    79,    -1,    32,    -1,
-      31,    -1,    -1,    14,    81,    -1,    82,    -1,    82,    40,
-      82,    -1,    82,    30,    82,    -1,    34,    81,    33,    -1,
-      41,    81,    -1,    81,    38,    81,    -1,    81,    39,    81,
-      -1,    28,    -1,    29,    -1
+      36,     0,    -1,    37,    -1,    -1,    37,    39,    -1,    37,
+      50,    -1,    37,    61,    -1,    37,     3,    71,    73,    -1,
+      37,    72,    -1,    37,    25,     1,    30,    -1,    37,    38,
+       1,    30,    -1,    37,     1,    30,    -1,    16,    -1,    19,
+      -1,    20,    -1,    22,    -1,    18,    -1,    23,    -1,    21,
+      -1,    30,    -1,    56,    -1,    65,    -1,    42,    -1,    44,
+      -1,    63,    -1,    25,     1,    30,    -1,     1,    30,    -1,
+      10,    25,    30,    -1,    41,    45,    -1,    11,    25,    30,
+      -1,    43,    45,    -1,    -1,    45,    46,    -1,    45,    69,
+      -1,    45,    67,    -1,    45,    40,    -1,    45,    30,    -1,
+      20,    70,    30,    -1,    19,    71,    74,    30,    -1,    21,
+      75,    74,    30,    -1,    22,    25,    74,    30,    -1,    23,
+      76,    76,    74,    30,    -1,     7,    30,    -1,    47,    51,
+      -1,    72,    -1,    48,    53,    49,    -1,    -1,    51,    52,
+      -1,    51,    69,    -1,    51,    67,    -1,    51,    30,    -1,
+      51,    40,    -1,    19,    71,    74,    30,    -1,    20,    70,
+      30,    -1,    18,    30,    -1,    21,    25,    74,    30,    -1,
+      -1,    53,    39,    -1,    14,    75,    73,    -1,    72,    -1,
+      54,    57,    55,    -1,    -1,    57,    39,    -1,    57,    61,
+      -1,    57,    50,    -1,     4,    71,    30,    -1,    58,    68,
+      -1,    72,    -1,    59,    62,    60,    -1,    -1,    62,    39,
+      -1,    62,    61,    -1,    62,    50,    -1,     6,    71,    30,
+      -1,     9,    71,    30,    -1,    64,    68,    -1,    12,    30,
+      -1,    66,    13,    -1,    -1,    68,    69,    -1,    68,    30,
+      -1,    68,    40,    -1,    16,    24,    75,    30,    -1,    16,
+      75,    30,    -1,    17,    75,    30,    -1,    -1,    71,    74,
+      -1,    25,    -1,    26,    -1,     5,    30,    -1,     8,    30,
+      -1,    15,    30,    -1,    30,    -1,    73,    30,    -1,    -1,
+      14,    75,    -1,    76,    -1,    76,    33,    76,    -1,    76,
+      27,    76,    -1,    29,    75,    28,    -1,    34,    75,    -1,
+      75,    31,    75,    -1,    75,    32,    75,    -1,    25,    -1,
+      26,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const unsigned short yyrline[] =
+static const unsigned short int yyrline[] =
 {
-       0,    94,    94,    95,    98,    99,   100,   101,   102,   103,
-     104,   105,   109,   110,   111,   112,   113,   114,   120,   128,
-     134,   142,   152,   154,   155,   156,   157,   160,   166,   173,
-     179,   186,   192,   198,   204,   210,   216,   222,   230,   239,
-     245,   254,   255,   261,   263,   264,   265,   266,   269,   275,
-     281,   287,   293,   299,   301,   306,   315,   324,   325,   331,
-     333,   334,   335,   340,   347,   353,   362,   363,   369,   371,
-     372,   373,   374,   377,   383,   390,   397,   404,   410,   417,
-     418,   419,   422,   427,   432,   440,   442,   447,   448,   451,
-     452,   453,   457,   457,   459,   460,   463,   464,   465,   466,
-     467,   468,   469,   472,   473
+       0,   103,   103,   105,   107,   108,   109,   110,   111,   112,
+     113,   117,   121,   121,   121,   121,   121,   121,   121,   125,
+     126,   127,   128,   129,   130,   134,   135,   141,   149,   155,
+     163,   173,   175,   176,   177,   178,   179,   182,   190,   196,
+     206,   212,   220,   229,   234,   242,   245,   247,   248,   249,
+     250,   251,   254,   260,   271,   277,   287,   289,   294,   302,
+     310,   313,   315,   316,   317,   322,   329,   334,   342,   345,
+     347,   348,   349,   352,   360,   367,   374,   380,   387,   389,
+     390,   391,   394,   399,   404,   412,   414,   419,   420,   423,
+     424,   425,   429,   430,   433,   434,   437,   438,   439,   440,
+     441,   442,   443,   446,   447
 };
 #endif
 
@@ -448,67 +441,65 @@
    First, the terminals, then, starting at YYNTOKENS, nonterminals. */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", 
-  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", 
-  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", 
-  "T_REQUIRES", "T_OPTIONAL", "T_PROMPT", "T_DEFAULT", "T_TRISTATE", 
-  "T_DEF_TRISTATE", "T_BOOLEAN", "T_DEF_BOOLEAN", "T_STRING", "T_INT", 
-  "T_HEX", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", "T_EOF", "T_EOL", 
-  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_ON", "T_SELECT", "T_RANGE", "T_OR", 
-  "T_AND", "T_EQUAL", "T_NOT", "$accept", "input", "block", 
-  "common_block", "config_entry_start", "config_stmt", 
-  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", 
-  "config_option", "choice", "choice_entry", "choice_end", "choice_stmt", 
-  "choice_option_list", "choice_option", "choice_block", "if", "if_end", 
-  "if_stmt", "if_block", "menu", "menu_entry", "menu_end", "menu_stmt", 
-  "menu_block", "source", "source_stmt", "comment", "comment_stmt", 
-  "help_start", "help", "depends_list", "depends", "prompt_stmt_opt", 
-  "prompt", "end", "nl_or_eof", "if_expr", "expr", "symbol", 0
+  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+  "T_REQUIRES", "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT",
+  "T_SELECT", "T_RANGE", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+  "T_NOT", "$accept", "input", "stmt_list", "option_name", "common_stmt",
+  "option_error", "config_entry_start", "config_stmt",
+  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+  "config_option", "choice", "choice_entry", "choice_end", "choice_stmt",
+  "choice_option_list", "choice_option", "choice_block", "if_entry",
+  "if_end", "if_stmt", "if_block", "menu", "menu_entry", "menu_end",
+  "menu_stmt", "menu_block", "source_stmt", "comment", "comment_stmt",
+  "help_start", "help", "depends_list", "depends", "prompt_stmt_opt",
+  "prompt", "end", "nl", "if_expr", "expr", "symbol", 0
 };
 #endif
 
 # ifdef YYPRINT
 /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
    token YYLEX-NUM.  */
-static const unsigned short yytoknum[] =
+static const unsigned short int yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
-     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
-     295,   296
+     285,   286,   287,   288,   289
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const unsigned char yyr1[] =
 {
-       0,    42,    43,    43,    44,    44,    44,    44,    44,    44,
-      44,    44,    45,    45,    45,    45,    45,    45,    46,    47,
-      48,    49,    50,    50,    50,    50,    50,    51,    51,    51,
-      51,    51,    51,    51,    51,    51,    51,    51,    52,    53,
-      54,    55,    55,    56,    56,    56,    56,    56,    57,    57,
-      57,    57,    57,    58,    58,    59,    60,    61,    61,    62,
-      62,    62,    62,    63,    64,    65,    66,    66,    67,    67,
-      67,    67,    67,    68,    69,    70,    71,    72,    73,    74,
-      74,    74,    75,    75,    75,    76,    76,    77,    77,    78,
-      78,    78,    79,    79,    80,    80,    81,    81,    81,    81,
-      81,    81,    81,    82,    82
+       0,    35,    36,    37,    37,    37,    37,    37,    37,    37,
+      37,    37,    38,    38,    38,    38,    38,    38,    38,    39,
+      39,    39,    39,    39,    39,    40,    40,    41,    42,    43,
+      44,    45,    45,    45,    45,    45,    45,    46,    46,    46,
+      46,    46,    47,    48,    49,    50,    51,    51,    51,    51,
+      51,    51,    52,    52,    52,    52,    53,    53,    54,    55,
+      56,    57,    57,    57,    57,    58,    59,    60,    61,    62,
+      62,    62,    62,    63,    64,    65,    66,    67,    68,    68,
+      68,    68,    69,    69,    69,    70,    70,    71,    71,    72,
+      72,    72,    73,    73,    74,    74,    75,    75,    75,    75,
+      75,    75,    75,    76,    76
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const unsigned char yyr2[] =
 {
-       0,     2,     0,     2,     1,     1,     1,     3,     1,     1,
-       1,     2,     1,     1,     1,     1,     1,     1,     3,     2,
-       3,     2,     0,     2,     2,     2,     2,     3,     4,     3,
-       4,     3,     3,     3,     4,     4,     4,     5,     2,     2,
-       1,     3,     2,     0,     2,     2,     2,     2,     4,     3,
-       3,     2,     4,     0,     2,     3,     1,     3,     2,     0,
-       2,     2,     2,     3,     2,     1,     3,     2,     0,     2,
-       2,     2,     3,     3,     1,     3,     2,     2,     2,     0,
+       0,     2,     1,     0,     2,     2,     2,     4,     2,     4,
+       4,     3,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     3,     2,     3,     2,     3,
+       2,     0,     2,     2,     2,     2,     2,     3,     4,     4,
+       4,     5,     2,     2,     1,     3,     0,     2,     2,     2,
+       2,     2,     4,     3,     2,     4,     0,     2,     3,     1,
+       3,     0,     2,     2,     2,     3,     2,     1,     3,     0,
+       2,     2,     2,     3,     3,     2,     2,     2,     0,     2,
        2,     2,     4,     3,     3,     0,     2,     1,     1,     2,
-       2,     2,     1,     1,     0,     2,     1,     3,     3,     3,
+       2,     2,     1,     2,     0,     2,     1,     3,     3,     3,
        2,     3,     3,     1,     1
 };
 
@@ -517,151 +508,160 @@
    means the default is an error.  */
 static const unsigned char yydefact[] =
 {
-       2,     0,     1,     0,     0,     0,     8,     0,     0,    10,
-       0,     0,     0,     0,     9,    93,    92,     3,     4,    22,
-      14,    22,    15,    43,    53,     5,    59,    12,    79,    68,
-       6,    74,    16,    79,    13,    17,    11,    87,    88,     0,
-       0,     0,    38,     0,     0,     0,   103,   104,     0,     0,
-       0,    96,    19,    21,    39,    42,    58,    64,     0,    76,
-       7,    63,    73,    75,    18,    20,     0,   100,    55,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    85,     0,
-      85,     0,    85,    85,    85,    26,     0,     0,    23,     0,
-      25,    24,     0,     0,     0,    85,    85,    47,    44,    46,
-      45,     0,     0,     0,    54,    41,    40,    60,    62,    57,
-      61,    56,    81,    80,     0,    69,    71,    66,    70,    65,
-      99,   101,   102,    98,    97,    77,     0,     0,     0,    94,
-      94,     0,    94,    94,     0,    94,     0,     0,     0,    94,
-       0,    78,    51,    94,    94,     0,     0,    89,    90,    91,
-      72,     0,    83,    84,     0,     0,     0,    27,    86,     0,
-      29,     0,    33,    31,    32,     0,    94,     0,     0,    49,
-      50,    82,    95,    34,    35,    28,    30,    36,     0,    48,
-      52,    37
+       3,     0,     0,     1,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    12,    16,    13,    14,
+      18,    15,    17,     0,    19,     0,     4,    31,    22,    31,
+      23,    46,    56,     5,    61,    20,    78,    69,     6,    24,
+      78,    21,     8,    11,    87,    88,     0,     0,    89,     0,
+      42,    90,     0,     0,     0,   103,   104,     0,     0,     0,
+      96,    91,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    92,     7,    65,    73,    74,    27,    29,     0,
+     100,     0,     0,    58,     0,     0,     9,    10,     0,     0,
+       0,     0,     0,    85,     0,     0,     0,     0,    36,    35,
+      32,     0,    34,    33,     0,     0,    85,     0,    50,    51,
+      47,    49,    48,    57,    45,    44,    62,    64,    60,    63,
+      59,    80,    81,    79,    70,    72,    68,    71,    67,    93,
+      99,   101,   102,    98,    97,    26,    76,     0,     0,     0,
+      94,     0,    94,    94,    94,     0,     0,    77,    54,    94,
+       0,    94,     0,    83,    84,     0,     0,    37,    86,     0,
+       0,    94,    25,     0,    53,     0,    82,    95,    38,    39,
+      40,     0,    52,    55,    41
 };
 
 /* YYDEFGOTO[NTERM-NUM]. */
-static const short yydefgoto[] =
+static const short int yydefgoto[] =
 {
-      -1,     1,    17,    18,    19,    20,    21,    22,    52,    88,
-      23,    24,   105,    25,    54,    98,    55,    26,   109,    27,
-      56,    28,    29,   117,    30,    58,    31,    32,    33,    34,
-      89,    90,    57,    91,   131,   132,   106,    35,   155,    50,
-      51
+      -1,     1,     2,    25,    26,    99,    27,    28,    29,    30,
+      64,   100,    31,    32,   114,    33,    66,   110,    67,    34,
+     118,    35,    68,    36,    37,   126,    38,    70,    39,    40,
+      41,   101,   102,    69,   103,   141,   142,    42,    73,   156,
+      59,    60
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -99
-static const short yypact[] =
+#define YYPACT_NINF -78
+static const short int yypact[] =
 {
-     -99,    48,   -99,    38,    46,    46,   -99,    46,   -29,   -99,
-      46,   -17,    -3,   -11,   -99,   -99,   -99,   -99,   -99,   -99,
-     -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,
-     -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,    38,
-      12,    15,   -99,    18,    51,    62,   -99,   -99,   -11,   -11,
-       4,   -24,   138,   138,   160,   121,   110,    -4,    81,    -4,
-     -99,   -99,   -99,   -99,   -99,   -99,   -19,   -99,   -99,   -11,
-     -11,    70,    70,    73,    32,   -11,    46,   -11,    46,   -11,
-      46,   -11,    46,    46,    46,   -99,    36,    70,   -99,    95,
-     -99,   -99,    96,    46,   106,    46,    46,   -99,   -99,   -99,
-     -99,    38,    38,    38,   -99,   -99,   -99,   -99,   -99,   -99,
-     -99,   -99,   -99,   -99,   112,   -99,   -99,   -99,   -99,   -99,
-     -99,   117,   -99,   -99,   -99,   -99,   -11,    33,    65,   131,
-       1,   119,   131,     1,   136,     1,   153,   154,   155,   131,
-      70,   -99,   -99,   131,   131,   156,   157,   -99,   -99,   -99,
-     -99,   101,   -99,   -99,   -11,   158,   159,   -99,   -99,   161,
-     -99,   162,   -99,   -99,   -99,   163,   131,   164,   165,   -99,
-     -99,   -99,    99,   -99,   -99,   -99,   -99,   -99,   166,   -99,
-     -99,   -99
+     -78,     2,   159,   -78,   -21,     0,     0,   -12,     0,     1,
+       4,     0,    27,    38,    60,    58,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   100,   -78,   104,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,    86,   113,   -78,   114,
+     -78,   -78,   125,   127,   128,   -78,   -78,    60,    60,   210,
+      65,   -78,   141,   142,    39,   103,   182,   200,     6,    66,
+       6,   131,   -78,   146,   -78,   -78,   -78,   -78,   -78,   196,
+     -78,    60,    60,   146,    40,    40,   -78,   -78,   155,   156,
+      -2,    60,     0,     0,    60,   105,    40,   194,   -78,   -78,
+     -78,   206,   -78,   -78,   183,     0,     0,   195,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   197,   -78,   -78,   -78,   -78,   -78,    60,   213,   216,
+     212,   203,   212,   190,   212,    40,   208,   -78,   -78,   212,
+     222,   212,   219,   -78,   -78,    60,   223,   -78,   -78,   224,
+     225,   212,   -78,   226,   -78,   227,   -78,    47,   -78,   -78,
+     -78,   228,   -78,   -78,   -78
 };
 
 /* YYPGOTO[NTERM-NUM].  */
-static const short yypgoto[] =
+static const short int yypgoto[] =
 {
-     -99,   -99,   -99,   111,   -99,   -99,   -99,   -99,   178,   -99,
-     -99,   -99,   -99,    91,   -99,   -99,   -99,   -99,   -99,   -99,
-     -99,   -99,   -99,   -99,   115,   -99,   -99,   -99,   -99,   -99,
-     -99,   146,   168,    89,    27,     0,   126,    -1,   -98,   -48,
-     -63
+     -78,   -78,   -78,   -78,   164,   -36,   -78,   -78,   -78,   -78,
+     230,   -78,   -78,   -78,   -78,    29,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,    59,   -78,   -78,   -78,
+     -78,   -78,   198,   220,    24,   157,    -5,   169,   202,    74,
+     -53,   -77
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If zero, do what YYDEFACT says.
    If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -68
-static const short yytable[] =
+#define YYTABLE_NINF -76
+static const short int yytable[] =
 {
-      66,    67,    36,    42,    39,    40,    71,    41,   123,   124,
-      43,    44,    74,    75,   120,   154,    72,    46,    47,    69,
-      70,   121,   122,    48,   140,    45,   127,   128,   112,   130,
-      49,   133,   156,   135,   158,   159,    68,   161,    60,    69,
-      70,   165,    69,    70,    61,   167,   168,    62,     2,     3,
-      63,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-      46,    47,    13,    14,   139,   152,    48,   126,   178,    15,
-      16,    69,    70,    49,    37,    38,   129,   166,   151,    15,
-      16,   -67,   114,    64,   -67,     5,   101,     7,     8,   102,
-      10,    11,    12,   143,    65,    13,   103,   153,    46,    47,
-     147,   148,   149,    69,    70,   125,   172,   134,   141,   136,
-     137,   138,    15,    16,     5,   101,     7,     8,   102,    10,
-      11,    12,   145,   146,    13,   103,   101,     7,   142,   102,
-      10,    11,    12,   171,   144,    13,   103,    69,    70,    69,
-      70,    15,    16,   100,   150,   154,   113,   108,   113,   116,
-      73,   157,    15,    16,    74,    75,    70,    76,    77,    78,
-      79,    80,    81,    82,    83,    84,   104,   107,   160,   115,
-      85,   110,    73,   118,    86,    87,    74,    75,    92,    93,
-      94,    95,   111,    96,   119,   162,   163,   164,   169,   170,
-     173,   174,    97,   175,   176,   177,   179,   180,   181,    53,
-      99,    59
+      46,    47,     3,    49,    79,    80,    52,   133,   134,    43,
+       6,     7,     8,     9,    10,    11,    12,    13,    48,   145,
+      14,    15,   137,    55,    56,    44,    45,    57,   131,   132,
+     109,    50,    58,   122,    51,   122,    24,   138,   139,   -28,
+      88,   143,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,
+     -28,    89,    53,   -28,   -28,    90,    91,   -28,    92,    93,
+      94,    95,    96,    54,    97,    55,    56,    88,   161,    98,
+     -66,   -66,   -66,   -66,   -66,   -66,   -66,   -66,    81,    82,
+     -66,   -66,    90,    91,   152,    55,    56,   140,    61,    57,
+     112,    97,    84,   123,    58,   123,   121,   117,    85,   125,
+     149,    62,   167,   -30,    88,    63,   -30,   -30,   -30,   -30,
+     -30,   -30,   -30,   -30,   -30,    89,    72,   -30,   -30,    90,
+      91,   -30,    92,    93,    94,    95,    96,   119,    97,   127,
+     144,   -75,    88,    98,   -75,   -75,   -75,   -75,   -75,   -75,
+     -75,   -75,   -75,    74,    75,   -75,   -75,    90,    91,   -75,
+     -75,   -75,   -75,   -75,   -75,    76,    97,    77,    78,    -2,
+       4,   121,     5,     6,     7,     8,     9,    10,    11,    12,
+      13,    86,    87,    14,    15,    16,   129,    17,    18,    19,
+      20,    21,    22,    88,    23,   135,   136,   -43,   -43,    24,
+     -43,   -43,   -43,   -43,    89,   146,   -43,   -43,    90,    91,
+     104,   105,   106,   107,   155,     7,     8,    97,    10,    11,
+      12,    13,   108,   148,    14,    15,   158,   159,   160,   147,
+     151,    81,    82,   163,   130,   165,   155,    81,    82,    82,
+      24,   113,   116,   157,   124,   171,   115,   120,   162,   128,
+      72,    81,    82,   153,    81,    82,   154,    81,    82,   166,
+      81,    82,   164,   168,   169,   170,   172,   173,   174,    65,
+      71,    83,     0,   150,   111
 };
 
-static const unsigned char yycheck[] =
+static const short int yycheck[] =
 {
-      48,    49,     3,    32,     4,     5,    30,     7,    71,    72,
-      10,    28,    16,    17,    33,    14,    40,    28,    29,    38,
-      39,    69,    70,    34,    87,    28,    74,    75,    32,    77,
-      41,    79,   130,    81,   132,   133,    32,   135,    39,    38,
-      39,   139,    38,    39,    32,   143,   144,    32,     0,     1,
-      32,     3,     4,     5,     6,     7,     8,     9,    10,    11,
-      28,    29,    14,    15,    28,    32,    34,    35,   166,    31,
-      32,    38,    39,    41,    28,    29,    76,   140,   126,    31,
-      32,     0,     1,    32,     3,     4,     5,     6,     7,     8,
-       9,    10,    11,    93,    32,    14,    15,    32,    28,    29,
-     101,   102,   103,    38,    39,    32,   154,    80,    13,    82,
-      83,    84,    31,    32,     4,     5,     6,     7,     8,     9,
-      10,    11,    95,    96,    14,    15,     5,     6,    32,     8,
-       9,    10,    11,    32,    28,    14,    15,    38,    39,    38,
-      39,    31,    32,    54,    32,    14,    57,    56,    59,    58,
-      12,    32,    31,    32,    16,    17,    39,    19,    20,    21,
-      22,    23,    24,    25,    26,    27,    55,    56,    32,    58,
-      32,    56,    12,    58,    36,    37,    16,    17,    18,    19,
-      20,    21,    56,    23,    58,    32,    32,    32,    32,    32,
-      32,    32,    32,    32,    32,    32,    32,    32,    32,    21,
-      54,    33
+       5,     6,     0,     8,    57,    58,    11,    84,    85,    30,
+       4,     5,     6,     7,     8,     9,    10,    11,    30,    96,
+      14,    15,    24,    25,    26,    25,    26,    29,    81,    82,
+      66,    30,    34,    69,    30,    71,    30,    90,    91,     0,
+       1,    94,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    25,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    25,    25,    25,    26,     1,   145,    30,
+       4,     5,     6,     7,     8,     9,    10,    11,    31,    32,
+      14,    15,    16,    17,   137,    25,    26,    92,    30,    29,
+      66,    25,    27,    69,    34,    71,    30,    68,    33,    70,
+     105,     1,   155,     0,     1,     1,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    30,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    68,    25,    70,
+      25,     0,     1,    30,     3,     4,     5,     6,     7,     8,
+       9,    10,    11,    30,    30,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    30,    25,    30,    30,     0,
+       1,    30,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    30,    30,    14,    15,    16,    30,    18,    19,    20,
+      21,    22,    23,     1,    25,    30,    30,     5,     6,    30,
+       8,     9,    10,    11,    12,     1,    14,    15,    16,    17,
+      18,    19,    20,    21,    14,     5,     6,    25,     8,     9,
+      10,    11,    30,    30,    14,    15,   142,   143,   144,    13,
+      25,    31,    32,   149,    28,   151,    14,    31,    32,    32,
+      30,    67,    68,    30,    70,   161,    67,    68,    30,    70,
+      30,    31,    32,    30,    31,    32,    30,    31,    32,    30,
+      31,    32,    30,    30,    30,    30,    30,    30,    30,    29,
+      40,    59,    -1,   106,    66
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const unsigned char yystos[] =
 {
-       0,    43,     0,     1,     3,     4,     5,     6,     7,     8,
-       9,    10,    11,    14,    15,    31,    32,    44,    45,    46,
-      47,    48,    49,    52,    53,    55,    59,    61,    63,    64,
-      66,    68,    69,    70,    71,    79,    79,    28,    29,    77,
-      77,    77,    32,    77,    28,    28,    28,    29,    34,    41,
-      81,    82,    50,    50,    56,    58,    62,    74,    67,    74,
-      79,    32,    32,    32,    32,    32,    81,    81,    32,    38,
-      39,    30,    40,    12,    16,    17,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    32,    36,    37,    51,    72,
-      73,    75,    18,    19,    20,    21,    23,    32,    57,    73,
-      75,     5,     8,    15,    45,    54,    78,    45,    55,    60,
-      66,    78,    32,    75,     1,    45,    55,    65,    66,    78,
-      33,    81,    81,    82,    82,    32,    35,    81,    81,    77,
-      81,    76,    77,    81,    76,    81,    76,    76,    76,    28,
-      82,    13,    32,    77,    28,    76,    76,    79,    79,    79,
-      32,    81,    32,    32,    14,    80,    80,    32,    80,    80,
-      32,    80,    32,    32,    32,    80,    82,    80,    80,    32,
-      32,    32,    81,    32,    32,    32,    32,    32,    80,    32,
-      32,    32
+       0,    36,    37,     0,     1,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    14,    15,    16,    18,    19,    20,
+      21,    22,    23,    25,    30,    38,    39,    41,    42,    43,
+      44,    47,    48,    50,    54,    56,    58,    59,    61,    63,
+      64,    65,    72,    30,    25,    26,    71,    71,    30,    71,
+      30,    30,    71,    25,    25,    25,    26,    29,    34,    75,
+      76,    30,     1,     1,    45,    45,    51,    53,    57,    68,
+      62,    68,    30,    73,    30,    30,    30,    30,    30,    75,
+      75,    31,    32,    73,    27,    33,    30,    30,     1,    12,
+      16,    17,    19,    20,    21,    22,    23,    25,    30,    40,
+      46,    66,    67,    69,    18,    19,    20,    21,    30,    40,
+      52,    67,    69,    39,    49,    72,    39,    50,    55,    61,
+      72,    30,    40,    69,    39,    50,    60,    61,    72,    30,
+      28,    75,    75,    76,    76,    30,    30,    24,    75,    75,
+      71,    70,    71,    75,    25,    76,     1,    13,    30,    71,
+      70,    25,    75,    30,    30,    14,    74,    30,    74,    74,
+      74,    76,    30,    74,    30,    74,    30,    75,    30,    30,
+      30,    74,    30,    30,    30
 };
 
 #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
@@ -687,7 +687,7 @@
 
 #define YYACCEPT	goto yyacceptlab
 #define YYABORT		goto yyabortlab
-#define YYERROR		goto yyerrlab1
+#define YYERROR		goto yyerrorlab
 
 
 /* Like YYERROR except do call yyerror.  This remains here temporarily
@@ -715,20 +715,53 @@
     }								\
 while (0)
 
+
 #define YYTERROR	1
 #define YYERRCODE	256
 
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions
-   are run).  */
 
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)         \
-  Current.first_line   = Rhs[1].first_line;      \
-  Current.first_column = Rhs[1].first_column;    \
-  Current.last_line    = Rhs[N].last_line;       \
-  Current.last_column  = Rhs[N].last_column;
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (N)								\
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (0)
 #endif
 
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+              (Loc).first_line, (Loc).first_column,	\
+              (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
 /* YYLEX -- calling `yylex' with the right arguments.  */
 
 #ifdef YYLEX_PARAM
@@ -751,36 +784,30 @@
     YYFPRINTF Args;				\
 } while (0)
 
-# define YYDSYMPRINT(Args)			\
-do {						\
-  if (yydebug)					\
-    yysymprint Args;				\
-} while (0)
-
-# define YYDSYMPRINTF(Title, Token, Value, Location)		\
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)		\
 do {								\
   if (yydebug)							\
     {								\
       YYFPRINTF (stderr, "%s ", Title);				\
       yysymprint (stderr, 					\
-                  Token, Value);	\
+                  Type, Value);	\
       YYFPRINTF (stderr, "\n");					\
     }								\
 } while (0)
 
 /*------------------------------------------------------------------.
 | yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (cinluded).                                                   |
+| TOP (included).                                                   |
 `------------------------------------------------------------------*/
 
 #if defined (__STDC__) || defined (__cplusplus)
 static void
-yy_stack_print (short *bottom, short *top)
+yy_stack_print (short int *bottom, short int *top)
 #else
 static void
 yy_stack_print (bottom, top)
-    short *bottom;
-    short *top;
+    short int *bottom;
+    short int *top;
 #endif
 {
   YYFPRINTF (stderr, "Stack now");
@@ -810,9 +837,9 @@
 #endif
 {
   int yyi;
-  unsigned int yylineno = yyrline[yyrule];
+  unsigned int yylno = yyrline[yyrule];
   YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
-             yyrule - 1, yylineno);
+             yyrule - 1, yylno);
   /* Print the symbols being reduced, and their result.  */
   for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
     YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
@@ -830,8 +857,7 @@
 int yydebug;
 #else /* !YYDEBUG */
 # define YYDPRINTF(Args)
-# define YYDSYMPRINT(Args)
-# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
 # define YY_STACK_PRINT(Bottom, Top)
 # define YY_REDUCE_PRINT(Rule)
 #endif /* !YYDEBUG */
@@ -849,10 +875,6 @@
    SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
    evaluated with infinite-precision integer arithmetic.  */
 
-#if YYMAXDEPTH == 0
-# undef YYMAXDEPTH
-#endif
-
 #ifndef YYMAXDEPTH
 # define YYMAXDEPTH 10000
 #endif
@@ -934,15 +956,15 @@
   (void) yyvaluep;
 
   if (yytype < YYNTOKENS)
-    {
-      YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-# ifdef YYPRINT
-      YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# endif
-    }
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
   else
     YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
 
+
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
   switch (yytype)
     {
       default:
@@ -958,10 +980,11 @@
 
 #if defined (__STDC__) || defined (__cplusplus)
 static void
-yydestruct (int yytype, YYSTYPE *yyvaluep)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
 #else
 static void
-yydestruct (yytype, yyvaluep)
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
     int yytype;
     YYSTYPE *yyvaluep;
 #endif
@@ -969,8 +992,42 @@
   /* Pacify ``unused variable'' warnings.  */
   (void) yyvaluep;
 
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
   switch (yytype)
     {
+      case 48: /* choice_entry */
+
+        {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+        break;
+      case 54: /* if_entry */
+
+        {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+        break;
+      case 59: /* menu_entry */
+
+        {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+        break;
 
       default:
         break;
@@ -996,10 +1053,10 @@
 
 
 
-/* The lookahead symbol.  */
+/* The look-ahead symbol.  */
 int yychar;
 
-/* The semantic value of the lookahead symbol.  */
+/* The semantic value of the look-ahead symbol.  */
 YYSTYPE yylval;
 
 /* Number of syntax errors so far.  */
@@ -1035,7 +1092,7 @@
   int yyresult;
   /* Number of tokens to shift before error messages enabled.  */
   int yyerrstatus;
-  /* Lookahead token as an internal (translated) token number.  */
+  /* Look-ahead token as an internal (translated) token number.  */
   int yytoken = 0;
 
   /* Three stacks and their tools:
@@ -1047,9 +1104,9 @@
      to reallocate them elsewhere.  */
 
   /* The state stack.  */
-  short	yyssa[YYINITDEPTH];
-  short *yyss = yyssa;
-  register short *yyssp;
+  short int yyssa[YYINITDEPTH];
+  short int *yyss = yyssa;
+  register short int *yyssp;
 
   /* The semantic value stack.  */
   YYSTYPE yyvsa[YYINITDEPTH];
@@ -1086,6 +1143,9 @@
   yyssp = yyss;
   yyvsp = yyvs;
 
+
+  yyvsp[0] = yylval;
+
   goto yysetstate;
 
 /*------------------------------------------------------------.
@@ -1111,7 +1171,7 @@
 	   these so that the &'s don't force the real ones into
 	   memory.  */
 	YYSTYPE *yyvs1 = yyvs;
-	short *yyss1 = yyss;
+	short int *yyss1 = yyss;
 
 
 	/* Each stack pointer address is followed by the size of the
@@ -1139,7 +1199,7 @@
 	yystacksize = YYMAXDEPTH;
 
       {
-	short *yyss1 = yyss;
+	short int *yyss1 = yyss;
 	union yyalloc *yyptr =
 	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
 	if (! yyptr)
@@ -1175,18 +1235,18 @@
 yybackup:
 
 /* Do appropriate processing given the current state.  */
-/* Read a lookahead token if we need one and don't already have one.  */
+/* Read a look-ahead token if we need one and don't already have one.  */
 /* yyresume: */
 
-  /* First try to decide what to do without reference to lookahead token.  */
+  /* First try to decide what to do without reference to look-ahead token.  */
 
   yyn = yypact[yystate];
   if (yyn == YYPACT_NINF)
     goto yydefault;
 
-  /* Not known => get a lookahead token if don't already have one.  */
+  /* Not known => get a look-ahead token if don't already have one.  */
 
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
   if (yychar == YYEMPTY)
     {
       YYDPRINTF ((stderr, "Reading a token: "));
@@ -1201,7 +1261,7 @@
   else
     {
       yytoken = YYTRANSLATE (yychar);
-      YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
     }
 
   /* If the proper action on seeing token YYTOKEN is to reduce or to
@@ -1221,8 +1281,8 @@
   if (yyn == YYFINAL)
     YYACCEPT;
 
-  /* Shift the lookahead token.  */
-  YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
 
   /* Discard the token being shifted unless it is eof.  */
   if (yychar != YYEOF)
@@ -1273,35 +1333,47 @@
     {
         case 8:
 
-    { zconfprint("unexpected 'endmenu' statement"); ;}
+    { zconf_error("unexpected end statement"); ;}
     break;
 
   case 9:
 
-    { zconfprint("unexpected 'endif' statement"); ;}
+    { zconf_error("unknown statement \"%s\"", (yyvsp[-2].string)); ;}
     break;
 
   case 10:
 
-    { zconfprint("unexpected 'endchoice' statement"); ;}
+    {
+	zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[-2].id)->name);
+;}
     break;
 
   case 11:
 
-    { zconfprint("syntax error"); yyerrok; ;}
+    { zconf_error("invalid statement"); ;}
     break;
 
-  case 18:
+  case 25:
+
+    { zconf_error("unknown option \"%s\"", (yyvsp[-2].string)); ;}
+    break;
+
+  case 26:
+
+    { zconf_error("invalid option"); ;}
+    break;
+
+  case 27:
 
     {
-	struct symbol *sym = sym_lookup(yyvsp[-1].string, 0);
+	struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
 	sym->flags |= SYMBOL_OPTIONAL;
 	menu_add_entry(sym);
-	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string);
+	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
 ;}
     break;
 
-  case 19:
+  case 28:
 
     {
 	menu_end_entry();
@@ -1309,17 +1381,17 @@
 ;}
     break;
 
-  case 20:
+  case 29:
 
     {
-	struct symbol *sym = sym_lookup(yyvsp[-1].string, 0);
+	struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
 	sym->flags |= SYMBOL_OPTIONAL;
 	menu_add_entry(sym);
-	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string);
+	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
 ;}
     break;
 
-  case 21:
+  case 30:
 
     {
 	if (current_entry->prompt)
@@ -1331,99 +1403,55 @@
 ;}
     break;
 
-  case 27:
-
-    {
-	menu_set_type(S_TRISTATE);
-	printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 28:
-
-    {
-	menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr);
-	menu_set_type(S_TRISTATE);
-	printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 29:
-
-    {
-	menu_set_type(S_BOOLEAN);
-	printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 30:
-
-    {
-	menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr);
-	menu_set_type(S_BOOLEAN);
-	printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 31:
-
-    {
-	menu_set_type(S_INT);
-	printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 32:
-
-    {
-	menu_set_type(S_HEX);
-	printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 33:
-
-    {
-	menu_set_type(S_STRING);
-	printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 34:
-
-    {
-	menu_add_prompt(P_PROMPT, yyvsp[-2].string, yyvsp[-1].expr);
-	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 35:
-
-    {
-	menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr);
-	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 36:
-
-    {
-	menu_add_symbol(P_SELECT, sym_lookup(yyvsp[-2].string, 0), yyvsp[-1].expr);
-	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
   case 37:
 
     {
-	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,yyvsp[-3].symbol, yyvsp[-2].symbol), yyvsp[-1].expr);
-	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+	menu_set_type((yyvsp[-2].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[-2].id)->stype);
 ;}
     break;
 
   case 38:
 
     {
+	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 39:
+
+    {
+	menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr));
+	if ((yyvsp[-3].id)->stype != S_UNKNOWN)
+		menu_set_type((yyvsp[-3].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[-3].id)->stype);
+;}
+    break;
+
+  case 40:
+
+    {
+	menu_add_symbol(P_SELECT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 41:
+
+    {
+	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), (yyvsp[-2].symbol)), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 42:
+
+    {
 	struct symbol *sym = sym_lookup(NULL, 0);
 	sym->flags |= SYMBOL_CHOICE;
 	menu_add_entry(sym);
@@ -1432,57 +1460,45 @@
 ;}
     break;
 
-  case 39:
+  case 43:
 
     {
-	menu_end_entry();
-	menu_add_menu();
+	(yyval.menu) = menu_add_menu();
 ;}
     break;
 
-  case 40:
+  case 44:
 
     {
-	if (zconf_endtoken(yyvsp[0].token, T_CHOICE, T_ENDCHOICE)) {
+	if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) {
 		menu_end_menu();
 		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
 	}
 ;}
     break;
 
-  case 42:
+  case 52:
 
     {
-	printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
-	zconfnerrs++;
-;}
-    break;
-
-  case 48:
-
-    {
-	menu_add_prompt(P_PROMPT, yyvsp[-2].string, yyvsp[-1].expr);
+	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
 	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
-  case 49:
+  case 53:
 
     {
-	menu_set_type(S_TRISTATE);
-	printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
+	if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == S_TRISTATE) {
+		menu_set_type((yyvsp[-2].id)->stype);
+		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+			zconf_curname(), zconf_lineno(),
+			(yyvsp[-2].id)->stype);
+	} else
+		YYERROR;
 ;}
     break;
 
-  case 50:
-
-    {
-	menu_set_type(S_BOOLEAN);
-	printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 51:
+  case 54:
 
     {
 	current_entry->sym->flags |= SYMBOL_OPTIONAL;
@@ -1490,115 +1506,89 @@
 ;}
     break;
 
-  case 52:
-
-    {
-	menu_add_symbol(P_DEFAULT, sym_lookup(yyvsp[-2].string, 0), yyvsp[-1].expr);
-	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
   case 55:
 
     {
-	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
-	menu_add_entry(NULL);
-	menu_add_dep(yyvsp[-1].expr);
-	menu_end_entry();
-	menu_add_menu();
-;}
-    break;
-
-  case 56:
-
-    {
-	if (zconf_endtoken(yyvsp[0].token, T_IF, T_ENDIF)) {
-		menu_end_menu();
-		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
-	}
+	if ((yyvsp[-3].id)->stype == S_UNKNOWN) {
+		menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+		printd(DEBUG_PARSE, "%s:%d:default\n",
+			zconf_curname(), zconf_lineno());
+	} else
+		YYERROR;
 ;}
     break;
 
   case 58:
 
     {
-	printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
-	zconfnerrs++;
-;}
-    break;
-
-  case 63:
-
-    {
+	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
 	menu_add_entry(NULL);
-	menu_add_prompt(P_MENU, yyvsp[-1].string, NULL);
-	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+	menu_add_dep((yyvsp[-1].expr));
+	(yyval.menu) = menu_add_menu();
 ;}
     break;
 
-  case 64:
+  case 59:
 
     {
-	menu_end_entry();
-	menu_add_menu();
+	if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+	}
 ;}
     break;
 
   case 65:
 
     {
-	if (zconf_endtoken(yyvsp[0].token, T_MENU, T_ENDMENU)) {
-		menu_end_menu();
-		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
-	}
+	menu_add_entry(NULL);
+	menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 66:
+
+    {
+	(yyval.menu) = menu_add_menu();
 ;}
     break;
 
   case 67:
 
     {
-	printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
-	zconfnerrs++;
+	if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+	}
 ;}
     break;
 
-  case 72:
-
-    { zconfprint("invalid menu option"); yyerrok; ;}
-    break;
-
   case 73:
 
     {
-	yyval.string = yyvsp[-1].string;
-	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string);
+	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+	zconf_nextfile((yyvsp[-1].string));
 ;}
     break;
 
   case 74:
 
     {
-	zconf_nextfile(yyvsp[0].string);
+	menu_add_entry(NULL);
+	menu_add_prompt(P_COMMENT, (yyvsp[-1].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
   case 75:
 
     {
-	menu_add_entry(NULL);
-	menu_add_prompt(P_COMMENT, yyvsp[-1].string, NULL);
-	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 76:
-
-    {
 	menu_end_entry();
 ;}
     break;
 
-  case 77:
+  case 76:
 
     {
 	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
@@ -1606,17 +1596,17 @@
 ;}
     break;
 
-  case 78:
+  case 77:
 
     {
-	current_entry->sym->help = yyvsp[0].string;
+	current_entry->sym->help = (yyvsp[0].string);
 ;}
     break;
 
   case 82:
 
     {
-	menu_add_dep(yyvsp[-1].expr);
+	menu_add_dep((yyvsp[-1].expr));
 	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
 ;}
     break;
@@ -1624,7 +1614,7 @@
   case 83:
 
     {
-	menu_add_dep(yyvsp[-1].expr);
+	menu_add_dep((yyvsp[-1].expr));
 	printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
 ;}
     break;
@@ -1632,7 +1622,7 @@
   case 84:
 
     {
-	menu_add_dep(yyvsp[-1].expr);
+	menu_add_dep((yyvsp[-1].expr));
 	printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
 ;}
     break;
@@ -1640,84 +1630,84 @@
   case 86:
 
     {
-	menu_add_prompt(P_PROMPT, yyvsp[-1].string, yyvsp[0].expr);
+	menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr));
 ;}
     break;
 
   case 89:
 
-    { yyval.token = T_ENDMENU; ;}
+    { (yyval.id) = (yyvsp[-1].id); ;}
     break;
 
   case 90:
 
-    { yyval.token = T_ENDCHOICE; ;}
+    { (yyval.id) = (yyvsp[-1].id); ;}
     break;
 
   case 91:
 
-    { yyval.token = T_ENDIF; ;}
+    { (yyval.id) = (yyvsp[-1].id); ;}
     break;
 
   case 94:
 
-    { yyval.expr = NULL; ;}
+    { (yyval.expr) = NULL; ;}
     break;
 
   case 95:
 
-    { yyval.expr = yyvsp[0].expr; ;}
+    { (yyval.expr) = (yyvsp[0].expr); ;}
     break;
 
   case 96:
 
-    { yyval.expr = expr_alloc_symbol(yyvsp[0].symbol); ;}
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); ;}
     break;
 
   case 97:
 
-    { yyval.expr = expr_alloc_comp(E_EQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;}
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
     break;
 
   case 98:
 
-    { yyval.expr = expr_alloc_comp(E_UNEQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;}
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
     break;
 
   case 99:
 
-    { yyval.expr = yyvsp[-1].expr; ;}
+    { (yyval.expr) = (yyvsp[-1].expr); ;}
     break;
 
   case 100:
 
-    { yyval.expr = expr_alloc_one(E_NOT, yyvsp[0].expr); ;}
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); ;}
     break;
 
   case 101:
 
-    { yyval.expr = expr_alloc_two(E_OR, yyvsp[-2].expr, yyvsp[0].expr); ;}
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
     break;
 
   case 102:
 
-    { yyval.expr = expr_alloc_two(E_AND, yyvsp[-2].expr, yyvsp[0].expr); ;}
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
     break;
 
   case 103:
 
-    { yyval.symbol = sym_lookup(yyvsp[0].string, 0); free(yyvsp[0].string); ;}
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); ;}
     break;
 
   case 104:
 
-    { yyval.symbol = sym_lookup(yyvsp[0].string, 1); free(yyvsp[0].string); ;}
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 1); free((yyvsp[0].string)); ;}
     break;
 
 
     }
 
-/* Line 999 of yacc.c.  */
+/* Line 1037 of yacc.c.  */
 
 
   yyvsp -= yylen;
@@ -1759,18 +1749,33 @@
 	{
 	  YYSIZE_T yysize = 0;
 	  int yytype = YYTRANSLATE (yychar);
+	  const char* yyprefix;
 	  char *yymsg;
-	  int yyx, yycount;
+	  int yyx;
 
-	  yycount = 0;
 	  /* Start YYX at -YYN if negative to avoid negative indexes in
 	     YYCHECK.  */
-	  for (yyx = yyn < 0 ? -yyn : 0;
-	       yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+	  int yyxbegin = yyn < 0 ? -yyn : 0;
+
+	  /* Stay within bounds of both yycheck and yytname.  */
+	  int yychecklim = YYLAST - yyn;
+	  int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+	  int yycount = 0;
+
+	  yyprefix = ", expecting ";
+	  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
 	    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-	      yysize += yystrlen (yytname[yyx]) + 15, yycount++;
-	  yysize += yystrlen ("syntax error, unexpected ") + 1;
-	  yysize += yystrlen (yytname[yytype]);
+	      {
+		yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+		yycount += 1;
+		if (yycount == 5)
+		  {
+		    yysize = 0;
+		    break;
+		  }
+	      }
+	  yysize += (sizeof ("syntax error, unexpected ")
+		     + yystrlen (yytname[yytype]));
 	  yymsg = (char *) YYSTACK_ALLOC (yysize);
 	  if (yymsg != 0)
 	    {
@@ -1779,16 +1784,13 @@
 
 	      if (yycount < 5)
 		{
-		  yycount = 0;
-		  for (yyx = yyn < 0 ? -yyn : 0;
-		       yyx < (int) (sizeof (yytname) / sizeof (char *));
-		       yyx++)
+		  yyprefix = ", expecting ";
+		  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
 		    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
 		      {
-			const char *yyq = ! yycount ? ", expecting " : " or ";
-			yyp = yystpcpy (yyp, yyq);
+			yyp = yystpcpy (yyp, yyprefix);
 			yyp = yystpcpy (yyp, yytname[yyx]);
-			yycount++;
+			yyprefix = " or ";
 		      }
 		}
 	      yyerror (yymsg);
@@ -1806,38 +1808,57 @@
 
   if (yyerrstatus == 3)
     {
-      /* If just tried and failed to reuse lookahead token after an
+      /* If just tried and failed to reuse look-ahead token after an
 	 error, discard it.  */
 
-      /* Return failure if at end of input.  */
-      if (yychar == YYEOF)
+      if (yychar <= YYEOF)
         {
-	  /* Pop the error token.  */
-          YYPOPSTACK;
-	  /* Pop the rest of the stack.  */
-	  while (yyss < yyssp)
-	    {
-	      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-	      yydestruct (yystos[*yyssp], yyvsp);
-	      YYPOPSTACK;
-	    }
-	  YYABORT;
+          /* If at end of input, pop the error token,
+	     then the rest of the stack, then return failure.  */
+	  if (yychar == YYEOF)
+	     for (;;)
+	       {
+
+		 YYPOPSTACK;
+		 if (yyssp == yyss)
+		   YYABORT;
+		 yydestruct ("Error: popping",
+                             yystos[*yyssp], yyvsp);
+	       }
         }
-
-      YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
-      yydestruct (yytoken, &yylval);
-      yychar = YYEMPTY;
-
+      else
+	{
+	  yydestruct ("Error: discarding", yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
     }
 
-  /* Else will try to reuse lookahead token after shifting the error
+  /* Else will try to reuse look-ahead token after shifting the error
      token.  */
   goto yyerrlab1;
 
 
-/*----------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action.  |
-`----------------------------------------------------*/
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#ifdef __GNUC__
+  /* Pacify GCC when the user code never invokes YYERROR and the label
+     yyerrorlab therefore never appears in user code.  */
+  if (0)
+     goto yyerrorlab;
+#endif
+
+yyvsp -= yylen;
+  yyssp -= yylen;
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
 yyerrlab1:
   yyerrstatus = 3;	/* Each real token shifted decrements this.  */
 
@@ -1859,22 +1880,22 @@
       if (yyssp == yyss)
 	YYABORT;
 
-      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-      yydestruct (yystos[yystate], yyvsp);
-      yyvsp--;
-      yystate = *--yyssp;
 
+      yydestruct ("Error: popping", yystos[yystate], yyvsp);
+      YYPOPSTACK;
+      yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
     }
 
   if (yyn == YYFINAL)
     YYACCEPT;
 
-  YYDPRINTF ((stderr, "Shifting error token, "));
-
   *++yyvsp = yylval;
 
 
+  /* Shift the error token. */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
   yystate = yyn;
   goto yynewstate;
 
@@ -1890,6 +1911,9 @@
 | yyabortlab -- YYABORT comes here.  |
 `-----------------------------------*/
 yyabortlab:
+  yydestruct ("Error: discarding lookahead",
+              yytoken, &yylval);
+  yychar = YYEMPTY;
   yyresult = 1;
   goto yyreturn;
 
@@ -1927,16 +1951,16 @@
 	modules_sym = sym_lookup("MODULES", 0);
 	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
-	//zconfdebug = 1;
+#if YYDEBUG
+	if (getenv("ZCONF_DEBUG"))
+		zconfdebug = 1;
+#endif
 	zconfparse();
 	if (zconfnerrs)
 		exit(1);
 	menu_finalize(&rootmenu);
 	for_all_symbols(i, sym) {
-                if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym))
-                        printf("\n");
-		else
-			sym->flags |= SYMBOL_CHECK_DONE;
+		sym_check_deps(sym);
         }
 
 	sym_change_count = 1;
@@ -1951,20 +1975,25 @@
 	case T_ENDCHOICE:	return "endchoice";
 	case T_IF:		return "if";
 	case T_ENDIF:		return "endif";
+	case T_DEPENDS:		return "depends";
 	}
 	return "<token>";
 }
 
-static bool zconf_endtoken(int token, int starttoken, int endtoken)
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
 {
-	if (token != endtoken) {
-		zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken));
+	if (id->token != endtoken) {
+		zconf_error("unexpected '%s' within %s block",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
 		zconfnerrs++;
 		return false;
 	}
 	if (current_menu->file != current_file) {
-		zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken));
-		zconfprint("location of the '%s'", zconf_tokenname(starttoken));
+		zconf_error("'%s' in different file than '%s'",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		fprintf(stderr, "%s:%d: location of the '%s'\n",
+			current_menu->file->name, current_menu->lineno,
+			zconf_tokenname(starttoken));
 		zconfnerrs++;
 		return false;
 	}
@@ -1975,7 +2004,19 @@
 {
 	va_list ap;
 
-	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1);
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+	va_list ap;
+
+	zconfnerrs++;
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
 	va_start(ap, err);
 	vfprintf(stderr, err, ap);
 	va_end(ap);
@@ -1984,7 +2025,9 @@
 
 static void zconferror(const char *err)
 {
+#if YYDEBUG
 	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
 }
 
 void print_quoted_string(FILE *out, const char *str)
diff --git a/scripts/kconfig/zconf.tab.h_shipped b/scripts/kconfig/zconf.tab.h_shipped
deleted file mode 100644
index 3b191ef..0000000
--- a/scripts/kconfig/zconf.tab.h_shipped
+++ /dev/null
@@ -1,125 +0,0 @@
-/* A Bison parser, made from zconf.y, by GNU bison 1.75.  */
-
-/* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, 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, 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.  */
-
-/* As a special exception, when this file is copied by Bison into a
-   Bison output file, you may use that output file without restriction.
-   This special exception was added by the Free Software Foundation
-   in version 1.24 of Bison.  */
-
-#ifndef BISON_ZCONF_TAB_H
-# define BISON_ZCONF_TAB_H
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     T_MAINMENU = 258,
-     T_MENU = 259,
-     T_ENDMENU = 260,
-     T_SOURCE = 261,
-     T_CHOICE = 262,
-     T_ENDCHOICE = 263,
-     T_COMMENT = 264,
-     T_CONFIG = 265,
-     T_HELP = 266,
-     T_HELPTEXT = 267,
-     T_IF = 268,
-     T_ENDIF = 269,
-     T_DEPENDS = 270,
-     T_REQUIRES = 271,
-     T_OPTIONAL = 272,
-     T_PROMPT = 273,
-     T_DEFAULT = 274,
-     T_TRISTATE = 275,
-     T_BOOLEAN = 276,
-     T_INT = 277,
-     T_HEX = 278,
-     T_WORD = 279,
-     T_STRING = 280,
-     T_UNEQUAL = 281,
-     T_EOF = 282,
-     T_EOL = 283,
-     T_CLOSE_PAREN = 284,
-     T_OPEN_PAREN = 285,
-     T_ON = 286,
-     T_OR = 287,
-     T_AND = 288,
-     T_EQUAL = 289,
-     T_NOT = 290
-   };
-#endif
-#define T_MAINMENU 258
-#define T_MENU 259
-#define T_ENDMENU 260
-#define T_SOURCE 261
-#define T_CHOICE 262
-#define T_ENDCHOICE 263
-#define T_COMMENT 264
-#define T_CONFIG 265
-#define T_HELP 266
-#define T_HELPTEXT 267
-#define T_IF 268
-#define T_ENDIF 269
-#define T_DEPENDS 270
-#define T_REQUIRES 271
-#define T_OPTIONAL 272
-#define T_PROMPT 273
-#define T_DEFAULT 274
-#define T_TRISTATE 275
-#define T_BOOLEAN 276
-#define T_INT 277
-#define T_HEX 278
-#define T_WORD 279
-#define T_STRING 280
-#define T_UNEQUAL 281
-#define T_EOF 282
-#define T_EOL 283
-#define T_CLOSE_PAREN 284
-#define T_OPEN_PAREN 285
-#define T_ON 286
-#define T_OR 287
-#define T_AND 288
-#define T_EQUAL 289
-#define T_NOT 290
-
-
-
-
-#ifndef YYSTYPE
-#line 33 "zconf.y"
-typedef union {
-	int token;
-	char *string;
-	struct symbol *symbol;
-	struct expr *expr;
-	struct menu *menu;
-} yystype;
-/* Line 1281 of /usr/share/bison/yacc.c.  */
-#line 118 "zconf.tab.h"
-# define YYSTYPE yystype
-#endif
-
-extern YYSTYPE zconflval;
-
-
-#endif /* not BISON_ZCONF_TAB_H */
-
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index e1a0f45..1f61fba 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -11,6 +11,11 @@
 #include <string.h>
 #include <stdbool.h>
 
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
 
 #define PRINTD		0x0001
@@ -20,61 +25,59 @@
 
 extern int zconflex(void);
 static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
 static void zconferror(const char *err);
-static bool zconf_endtoken(int token, int starttoken, int endtoken);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
 
 struct symbol *symbol_hash[257];
 
 static struct menu *current_menu, *current_entry;
 
+#define YYDEBUG 0
+#if YYDEBUG
 #define YYERROR_VERBOSE
+#endif
 %}
-%expect 40
+%expect 26
 
 %union
 {
-	int token;
 	char *string;
+	struct file *file;
 	struct symbol *symbol;
 	struct expr *expr;
 	struct menu *menu;
+	struct kconf_id *id;
 }
 
-%token T_MAINMENU
-%token T_MENU
-%token T_ENDMENU
-%token T_SOURCE
-%token T_CHOICE
-%token T_ENDCHOICE
-%token T_COMMENT
-%token T_CONFIG
-%token T_MENUCONFIG
-%token T_HELP
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
 %token <string> T_HELPTEXT
-%token T_IF
-%token T_ENDIF
-%token T_DEPENDS
-%token T_REQUIRES
-%token T_OPTIONAL
-%token T_PROMPT
-%token T_DEFAULT
-%token T_TRISTATE
-%token T_DEF_TRISTATE
-%token T_BOOLEAN
-%token T_DEF_BOOLEAN
-%token T_STRING
-%token T_INT
-%token T_HEX
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_REQUIRES
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_ON
 %token <string> T_WORD
 %token <string> T_WORD_QUOTE
 %token T_UNEQUAL
-%token T_EOF
-%token T_EOL
 %token T_CLOSE_PAREN
 %token T_OPEN_PAREN
-%token T_ON
-%token T_SELECT
-%token T_RANGE
+%token T_EOL
 
 %left T_OR
 %left T_AND
@@ -82,38 +85,54 @@
 %nonassoc T_NOT
 
 %type <string> prompt
-%type <string> source
 %type <symbol> symbol
 %type <expr> expr
 %type <expr> if_expr
-%type <token> end
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
 
-%{
-#define LKC_DIRECT_LINK
-#include "lkc.h"
-%}
+%destructor {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		$$->file->name, $$->lineno);
+	if (current_menu == $$)
+		menu_end_menu();
+} if_entry menu_entry choice_entry
+
 %%
-input:	  /* empty */
-	| input block
+input: stmt_list;
+
+stmt_list:
+	  /* empty */
+	| stmt_list common_stmt
+	| stmt_list choice_stmt
+	| stmt_list menu_stmt
+	| stmt_list T_MAINMENU prompt nl
+	| stmt_list end			{ zconf_error("unexpected end statement"); }
+	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); }
+	| stmt_list option_name error T_EOL
+{
+	zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+	| stmt_list error T_EOL		{ zconf_error("invalid statement"); }
 ;
 
-block:	  common_block
-	| choice_stmt
-	| menu_stmt
-	| T_MAINMENU prompt nl_or_eof
-	| T_ENDMENU		{ zconfprint("unexpected 'endmenu' statement"); }
-	| T_ENDIF		{ zconfprint("unexpected 'endif' statement"); }
-	| T_ENDCHOICE		{ zconfprint("unexpected 'endchoice' statement"); }
-	| error nl_or_eof	{ zconfprint("syntax error"); yyerrok; }
+option_name:
+	T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT
 ;
 
-common_block:
-	  if_stmt
+common_stmt:
+	  T_EOL
+	| if_stmt
 	| comment_stmt
 	| config_stmt
 	| menuconfig_stmt
 	| source_stmt
-	| nl_or_eof
+;
+
+option_error:
+	  T_WORD error T_EOL		{ zconf_error("unknown option \"%s\"", $1); }
+	| error T_EOL			{ zconf_error("invalid option"); }
 ;
 
 
@@ -156,51 +175,16 @@
 	| config_option_list config_option
 	| config_option_list depends
 	| config_option_list help
+	| config_option_list option_error
 	| config_option_list T_EOL
 ;
 
-config_option: T_TRISTATE prompt_stmt_opt T_EOL
+config_option: T_TYPE prompt_stmt_opt T_EOL
 {
-	menu_set_type(S_TRISTATE);
-	printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_DEF_TRISTATE expr if_expr T_EOL
-{
-	menu_add_expr(P_DEFAULT, $2, $3);
-	menu_set_type(S_TRISTATE);
-	printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_BOOLEAN prompt_stmt_opt T_EOL
-{
-	menu_set_type(S_BOOLEAN);
-	printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_DEF_BOOLEAN expr if_expr T_EOL
-{
-	menu_add_expr(P_DEFAULT, $2, $3);
-	menu_set_type(S_BOOLEAN);
-	printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_INT prompt_stmt_opt T_EOL
-{
-	menu_set_type(S_INT);
-	printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_HEX prompt_stmt_opt T_EOL
-{
-	menu_set_type(S_HEX);
-	printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_STRING prompt_stmt_opt T_EOL
-{
-	menu_set_type(S_STRING);
-	printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
+	menu_set_type($1->stype);
+	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		$1->stype);
 };
 
 config_option: T_PROMPT prompt if_expr T_EOL
@@ -212,7 +196,11 @@
 config_option: T_DEFAULT expr if_expr T_EOL
 {
 	menu_add_expr(P_DEFAULT, $2, $3);
-	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+	if ($1->stype != S_UNKNOWN)
+		menu_set_type($1->stype);
+	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		$1->stype);
 };
 
 config_option: T_SELECT T_WORD if_expr T_EOL
@@ -240,8 +228,7 @@
 
 choice_entry: choice choice_option_list
 {
-	menu_end_entry();
-	menu_add_menu();
+	$$ = menu_add_menu();
 };
 
 choice_end: end
@@ -252,13 +239,8 @@
 	}
 };
 
-choice_stmt:
-	  choice_entry choice_block choice_end
-	| choice_entry choice_block
-{
-	printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
-	zconfnerrs++;
-};
+choice_stmt: choice_entry choice_block choice_end
+;
 
 choice_option_list:
 	  /* empty */
@@ -266,6 +248,7 @@
 	| choice_option_list depends
 	| choice_option_list help
 	| choice_option_list T_EOL
+	| choice_option_list option_error
 ;
 
 choice_option: T_PROMPT prompt if_expr T_EOL
@@ -274,16 +257,15 @@
 	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
 };
 
-choice_option: T_TRISTATE prompt_stmt_opt T_EOL
+choice_option: T_TYPE prompt_stmt_opt T_EOL
 {
-	menu_set_type(S_TRISTATE);
-	printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
-};
-
-choice_option: T_BOOLEAN prompt_stmt_opt T_EOL
-{
-	menu_set_type(S_BOOLEAN);
-	printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
+	if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+		menu_set_type($1->stype);
+		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+			zconf_curname(), zconf_lineno(),
+			$1->stype);
+	} else
+		YYERROR;
 };
 
 choice_option: T_OPTIONAL T_EOL
@@ -294,24 +276,27 @@
 
 choice_option: T_DEFAULT T_WORD if_expr T_EOL
 {
-	menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
-	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+	if ($1->stype == S_UNKNOWN) {
+		menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+		printd(DEBUG_PARSE, "%s:%d:default\n",
+			zconf_curname(), zconf_lineno());
+	} else
+		YYERROR;
 };
 
 choice_block:
 	  /* empty */
-	| choice_block common_block
+	| choice_block common_stmt
 ;
 
 /* if entry */
 
-if: T_IF expr T_EOL
+if_entry: T_IF expr nl
 {
 	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
 	menu_add_entry(NULL);
 	menu_add_dep($2);
-	menu_end_entry();
-	menu_add_menu();
+	$$ = menu_add_menu();
 };
 
 if_end: end
@@ -322,17 +307,12 @@
 	}
 };
 
-if_stmt:
-	  if if_block if_end
-	| if if_block
-{
-	printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
-	zconfnerrs++;
-};
+if_stmt: if_entry if_block if_end
+;
 
 if_block:
 	  /* empty */
-	| if_block common_block
+	| if_block common_stmt
 	| if_block menu_stmt
 	| if_block choice_stmt
 ;
@@ -348,8 +328,7 @@
 
 menu_entry: menu depends_list
 {
-	menu_end_entry();
-	menu_add_menu();
+	$$ = menu_add_menu();
 };
 
 menu_end: end
@@ -360,31 +339,20 @@
 	}
 };
 
-menu_stmt:
-	  menu_entry menu_block menu_end
-	| menu_entry menu_block
-{
-	printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
-	zconfnerrs++;
-};
+menu_stmt: menu_entry menu_block menu_end
+;
 
 menu_block:
 	  /* empty */
-	| menu_block common_block
+	| menu_block common_stmt
 	| menu_block menu_stmt
 	| menu_block choice_stmt
-	| menu_block error T_EOL		{ zconfprint("invalid menu option"); yyerrok; }
 ;
 
-source: T_SOURCE prompt T_EOL
+source_stmt: T_SOURCE prompt T_EOL
 {
-	$$ = $2;
 	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
-};
-
-source_stmt: source
-{
-	zconf_nextfile($1);
+	zconf_nextfile($2);
 };
 
 /* comment entry */
@@ -416,9 +384,11 @@
 
 /* depends option */
 
-depends_list:	  /* empty */
-		| depends_list depends
-		| depends_list T_EOL
+depends_list:
+	  /* empty */
+	| depends_list depends
+	| depends_list T_EOL
+	| depends_list option_error
 ;
 
 depends: T_DEPENDS T_ON expr T_EOL
@@ -450,13 +420,15 @@
 	| T_WORD_QUOTE
 ;
 
-end:	  T_ENDMENU nl_or_eof	{ $$ = T_ENDMENU; }
-	| T_ENDCHOICE nl_or_eof	{ $$ = T_ENDCHOICE; }
-	| T_ENDIF nl_or_eof	{ $$ = T_ENDIF; }
+end:	  T_ENDMENU T_EOL	{ $$ = $1; }
+	| T_ENDCHOICE T_EOL	{ $$ = $1; }
+	| T_ENDIF T_EOL		{ $$ = $1; }
 ;
 
-nl_or_eof:
-	T_EOL | T_EOF;
+nl:
+	  T_EOL
+	| nl T_EOL
+;
 
 if_expr:  /* empty */			{ $$ = NULL; }
 	| T_IF expr			{ $$ = $2; }
@@ -489,16 +461,16 @@
 	modules_sym = sym_lookup("MODULES", 0);
 	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
-	//zconfdebug = 1;
+#if YYDEBUG
+	if (getenv("ZCONF_DEBUG"))
+		zconfdebug = 1;
+#endif
 	zconfparse();
 	if (zconfnerrs)
 		exit(1);
 	menu_finalize(&rootmenu);
 	for_all_symbols(i, sym) {
-                if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym))
-                        printf("\n");
-		else
-			sym->flags |= SYMBOL_CHECK_DONE;
+		sym_check_deps(sym);
         }
 
 	sym_change_count = 1;
@@ -513,20 +485,25 @@
 	case T_ENDCHOICE:	return "endchoice";
 	case T_IF:		return "if";
 	case T_ENDIF:		return "endif";
+	case T_DEPENDS:		return "depends";
 	}
 	return "<token>";
 }
 
-static bool zconf_endtoken(int token, int starttoken, int endtoken)
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
 {
-	if (token != endtoken) {
-		zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken));
+	if (id->token != endtoken) {
+		zconf_error("unexpected '%s' within %s block",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
 		zconfnerrs++;
 		return false;
 	}
 	if (current_menu->file != current_file) {
-		zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken));
-		zconfprint("location of the '%s'", zconf_tokenname(starttoken));
+		zconf_error("'%s' in different file than '%s'",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		fprintf(stderr, "%s:%d: location of the '%s'\n",
+			current_menu->file->name, current_menu->lineno,
+			zconf_tokenname(starttoken));
 		zconfnerrs++;
 		return false;
 	}
@@ -537,7 +514,19 @@
 {
 	va_list ap;
 
-	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1);
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+	va_list ap;
+
+	zconfnerrs++;
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
 	va_start(ap, err);
 	vfprintf(stderr, err, ap);
 	va_end(ap);
@@ -546,7 +535,9 @@
 
 static void zconferror(const char *err)
 {
+#if YYDEBUG
 	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
 }
 
 void print_quoted_string(FILE *out, const char *str)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 45c4149..fc77443 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1986,6 +1986,9 @@
 
 	inode_security_set_sid(inode, newsid);
 
+	if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+		return -EOPNOTSUPP;
+
 	if (name) {
 		namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL);
 		if (!namep)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index fdc3823..0e1352a 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -271,46 +271,38 @@
 	.write		= sel_write_load,
 };
 
-
-static ssize_t sel_write_context(struct file * file, const char __user * buf,
-				 size_t count, loff_t *ppos)
-
+static ssize_t sel_write_context(struct file * file, char *buf, size_t size)
 {
-	char *page;
-	u32 sid;
+	char *canon;
+	u32 sid, len;
 	ssize_t length;
 
 	length = task_has_security(current, SECURITY__CHECK_CONTEXT);
 	if (length)
 		return length;
 
-	if (count >= PAGE_SIZE)
-		return -ENOMEM;
-	if (*ppos != 0) {
-		/* No partial writes. */
-		return -EINVAL;
-	}
-	page = (char*)get_zeroed_page(GFP_KERNEL);
-	if (!page)
-		return -ENOMEM;
-	length = -EFAULT;
-	if (copy_from_user(page, buf, count))
-		goto out;
-
-	length = security_context_to_sid(page, count, &sid);
+	length = security_context_to_sid(buf, size, &sid);
 	if (length < 0)
-		goto out;
+		return length;
 
-	length = count;
+	length = security_sid_to_context(sid, &canon, &len);
+	if (length < 0)
+		return length;
+
+	if (len > SIMPLE_TRANSACTION_LIMIT) {
+		printk(KERN_ERR "%s:  context size (%u) exceeds payload "
+		       "max\n", __FUNCTION__, len);
+		length = -ERANGE;
+		goto out;
+	}
+
+	memcpy(buf, canon, len);
+	length = len;
 out:
-	free_page((unsigned long) page);
+	kfree(canon);
 	return length;
 }
 
-static struct file_operations sel_context_ops = {
-	.write		= sel_write_context,
-};
-
 static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
 				     size_t count, loff_t *ppos)
 {
@@ -375,6 +367,7 @@
 	[SEL_RELABEL] = sel_write_relabel,
 	[SEL_USER] = sel_write_user,
 	[SEL_MEMBER] = sel_write_member,
+	[SEL_CONTEXT] = sel_write_context,
 };
 
 static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
@@ -1220,7 +1213,7 @@
 	static struct tree_descr selinux_files[] = {
 		[SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
 		[SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR},
-		[SEL_CONTEXT] = {"context", &sel_context_ops, S_IRUGO|S_IWUGO},
+		[SEL_CONTEXT] = {"context", &transaction_ops, S_IRUGO|S_IWUGO},
 		[SEL_ACCESS] = {"access", &transaction_ops, S_IRUGO|S_IWUGO},
 		[SEL_CREATE] = {"create", &transaction_ops, S_IRUGO|S_IWUGO},
 		[SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO},
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index aaefac2..640d0bf 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -262,8 +262,11 @@
 	struct cat_datum *catdatum, *rngdatum;
 	int l, rc = -EINVAL;
 
-	if (!selinux_mls_enabled)
+	if (!selinux_mls_enabled) {
+		if (def_sid != SECSID_NULL && oldc)
+			*scontext += strlen(*scontext);
 		return 0;
+	}
 
 	/*
 	 * No MLS component to the security context, try and map to
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index d1f9da4..c96c8a2 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -275,9 +275,9 @@
 	return 0;
 }
 
-static int pxa2xx_ac97_suspend(struct device *_dev, pm_message_t state)
+static int pxa2xx_ac97_suspend(struct platform_device *dev, pm_message_t state)
 {
-	snd_card_t *card = dev_get_drvdata(_dev);
+	snd_card_t *card = platform_get_drvdata(dev);
 	int ret = 0;
 
 	if (card)
@@ -286,9 +286,9 @@
 	return ret;
 }
 
-static int pxa2xx_ac97_resume(struct device *_dev)
+static int pxa2xx_ac97_resume(struct platform_device *dev)
 {
-	snd_card_t *card = dev_get_drvdata(_dev);
+	snd_card_t *card = platform_get_drvdata(dev);
 	int ret = 0;
 
 	if (card)
@@ -302,7 +302,7 @@
 #define pxa2xx_ac97_resume	NULL
 #endif
 
-static int pxa2xx_ac97_probe(struct device *dev)
+static int pxa2xx_ac97_probe(struct platform_device *dev)
 {
 	snd_card_t *card;
 	ac97_bus_t *ac97_bus;
@@ -315,8 +315,8 @@
 	if (!card)
 		goto err;
 
-	card->dev = dev;
-	strncpy(card->driver, dev->driver->name, sizeof(card->driver));
+	card->dev = &dev->dev;
+	strncpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
 
 	ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
 	if (ret)
@@ -347,13 +347,13 @@
 	snprintf(card->shortname, sizeof(card->shortname),
 		 "%s", snd_ac97_get_short_name(pxa2xx_ac97_ac97));
 	snprintf(card->longname, sizeof(card->longname),
-		 "%s (%s)", dev->driver->name, card->mixername);
+		 "%s (%s)", dev->dev.driver->name, card->mixername);
 
 	snd_card_set_pm_callback(card, pxa2xx_ac97_do_suspend,
 				 pxa2xx_ac97_do_resume, NULL);
 	ret = snd_card_register(card);
 	if (ret == 0) {
-		dev_set_drvdata(dev, card);
+		platform_set_drvdata(dev, card);
 		return 0;
 	}
 
@@ -368,13 +368,13 @@
 	return ret;
 }
 
-static int pxa2xx_ac97_remove(struct device *dev)
+static int pxa2xx_ac97_remove(struct platform_device *dev)
 {
-	snd_card_t *card = dev_get_drvdata(dev);
+	snd_card_t *card = platform_get_drvdata(dev);
 
 	if (card) {
 		snd_card_free(card);
-		dev_set_drvdata(dev, NULL);
+		platform_set_drvdata(dev, NULL);
 		GCR |= GCR_ACLINK_OFF;
 		free_irq(IRQ_AC97, NULL);
 		pxa_set_cken(CKEN2_AC97, 0);
@@ -383,23 +383,24 @@
 	return 0;
 }
 
-static struct device_driver pxa2xx_ac97_driver = {
-	.name		= "pxa2xx-ac97",
-	.bus		= &platform_bus_type,
+static struct platform_driver pxa2xx_ac97_driver = {
 	.probe		= pxa2xx_ac97_probe,
 	.remove		= pxa2xx_ac97_remove,
 	.suspend	= pxa2xx_ac97_suspend,
 	.resume		= pxa2xx_ac97_resume,
+	.driver		= {
+		.name	= "pxa2xx-ac97",
+	},
 };
 
 static int __init pxa2xx_ac97_init(void)
 {
-	return driver_register(&pxa2xx_ac97_driver);
+	return platform_driver_register(&pxa2xx_ac97_driver);
 }
 
 static void __exit pxa2xx_ac97_exit(void)
 {
-	driver_unregister(&pxa2xx_ac97_driver);
+	platform_driver_unregister(&pxa2xx_ac97_driver);
 }
 
 module_init(pxa2xx_ac97_init);
diff --git a/sound/core/init.c b/sound/core/init.c
index d9ee27a..33813f9 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -674,23 +674,24 @@
 	snd_card_t *card;
 };
 
-#define get_snd_generic_card(dev)	container_of(to_platform_device(dev), struct snd_generic_device, pdev)->card
+#define get_snd_generic_card(dev)	container_of(dev, struct snd_generic_device, pdev)->card
 
 #define SND_GENERIC_NAME	"snd_generic"
 
 #ifdef CONFIG_PM
-static int snd_generic_suspend(struct device *dev, pm_message_t state);
-static int snd_generic_resume(struct device *dev);
+static int snd_generic_suspend(struct platform_device *dev, pm_message_t state);
+static int snd_generic_resume(struct platform_device *dev);
 #endif
 
 /* initialized in sound.c */
-struct device_driver snd_generic_driver = {
-	.name		= SND_GENERIC_NAME,
-	.bus		= &platform_bus_type,
+struct platform_driver snd_generic_driver = {
 #ifdef CONFIG_PM
 	.suspend	= snd_generic_suspend,
 	.resume		= snd_generic_resume,
 #endif
+	.driver		= {
+		.name	= SND_GENERIC_NAME,
+	},
 };
 
 void snd_generic_device_release(struct device *dev)
@@ -821,7 +822,7 @@
 
 #ifdef CONFIG_SND_GENERIC_DRIVER
 /* suspend/resume callbacks for snd_generic platform device */
-static int snd_generic_suspend(struct device *dev, pm_message_t state)
+static int snd_generic_suspend(struct platform_device *dev, pm_message_t state)
 {
 	snd_card_t *card;
 
@@ -834,7 +835,7 @@
 	return 0;
 }
 
-static int snd_generic_resume(struct device *dev)
+static int snd_generic_resume(struct platform_device *dev)
 {
 	snd_card_t *card;
 
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 1139dd8..6e7cad1e 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -32,7 +32,7 @@
 #include <sound/initval.h>
 #include <linux/kmod.h>
 #include <linux/devfs_fs_kernel.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 
 #define SNDRV_OS_MINORS 256
 
@@ -329,7 +329,7 @@
  */
 
 #ifdef CONFIG_SND_GENERIC_DRIVER
-extern struct device_driver snd_generic_driver;
+extern struct platform_driver snd_generic_driver;
 #endif
 
 static int __init alsa_sound_init(void)
@@ -357,7 +357,7 @@
 	}
 	snd_info_minor_register();
 #ifdef CONFIG_SND_GENERIC_DRIVER
-	driver_register(&snd_generic_driver);
+	platform_driver_register(&snd_generic_driver);
 #endif
 	for (controlnum = 0; controlnum < cards_limit; controlnum++)
 		devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum);
@@ -375,7 +375,7 @@
 		devfs_remove("snd/controlC%d", controlnum);
 
 #ifdef CONFIG_SND_GENERIC_DRIVER
-	driver_unregister(&snd_generic_driver);
+	platform_driver_unregister(&snd_generic_driver);
 #endif
 	snd_info_minor_unregister();
 	snd_info_done();
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c
index 9a3dc3c..c4993b0 100644
--- a/sound/drivers/vx/vx_hwdep.c
+++ b/sound/drivers/vx/vx_hwdep.c
@@ -23,6 +23,7 @@
 #include <sound/driver.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/vmalloc.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
 #include <sound/vx_core.h>
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 953e5f3..88e52dc 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -4,9 +4,24 @@
 # More hacking for modularisation.
 #
 # Prompt user for primary drivers.
+
+config OBSOLETE_OSS_DRIVER
+	bool "Obsolete OSS drivers"
+	depends on SOUND_PRIME
+	help
+	  This option enables support for obsolete OSS drivers that
+	  are scheduled for removal in the near future since there
+	  are ALSA drivers for the same hardware.
+
+	  Please contact Adrian Bunk <bunk@stusta.de> if you had to
+	  say Y here because your soundcard is not properly supported
+	  by ALSA.
+
+	  If unsure, say N.
+
 config SOUND_BT878
 	tristate "BT878 audio dma"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	---help---
 	  Audio DMA support for bt878 based grabber boards.  As you might have
 	  already noticed, bt878 is listed with two functions in /proc/pci.
@@ -22,7 +37,7 @@
 
 config SOUND_CMPCI
 	tristate "C-Media PCI (CMI8338/8738)"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a PCI sound card using the CMI8338
 	  or the CMI8738 chipset.  Data on these chips are available at
@@ -61,7 +76,7 @@
 
 config SOUND_EMU10K1
 	tristate "Creative SBLive! (EMU10K1)"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	---help---
 	  Say Y or M if you have a PCI sound card using the EMU10K1 chipset,
 	  such as the Creative SBLive!, SB PCI512 or Emu-APS.
@@ -95,7 +110,7 @@
 
 config SOUND_CS4281
 	tristate "Crystal Sound CS4281"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Picture and feature list at
 	  <http://www.pcbroker.com/crystal4281.html>.
@@ -112,7 +127,7 @@
 
 config SOUND_ES1370
 	tristate "Ensoniq AudioPCI (ES1370)"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a PCI sound card utilizing the Ensoniq
 	  ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find
@@ -125,7 +140,7 @@
 
 config SOUND_ES1371
 	tristate "Creative Ensoniq AudioPCI 97 (ES1371)"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a PCI sound card utilizing the Ensoniq
 	  ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
@@ -138,7 +153,7 @@
 
 config SOUND_ESSSOLO1
 	tristate "ESS Technology Solo1" 
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a PCI sound card utilizing the ESS Technology
 	  Solo1 chip. To find out if your sound card uses a
@@ -149,7 +164,7 @@
 
 config SOUND_MAESTRO
 	tristate "ESS Maestro, Maestro2, Maestro2E driver"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a sound system driven by ESS's Maestro line
 	  of PCI sound chips.  These include the Maestro 1, Maestro 2, and
@@ -158,7 +173,7 @@
 
 config SOUND_MAESTRO3
 	tristate "ESS Maestro3/Allegro driver (EXPERIMENTAL)"
-	depends on SOUND_PRIME && PCI && EXPERIMENTAL
+	depends on SOUND_PRIME && PCI && EXPERIMENTAL && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a sound system driven by ESS's Maestro 3
 	  PCI sound chip.
@@ -172,14 +187,14 @@
 
 config SOUND_HARMONY
 	tristate "PA Harmony audio driver"
-	depends on GSC_LASI && SOUND_PRIME
+	depends on GSC_LASI && SOUND_PRIME && OBSOLETE_OSS_DRIVER
 	help
 	  Say 'Y' or 'M' to include support for Harmony soundchip
 	  on HP 712, 715/new and many other GSC based machines.
 
 config SOUND_SONICVIBES
 	tristate "S3 SonicVibes"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a PCI sound card utilizing the S3
 	  SonicVibes chipset. To find out if your sound card uses a
@@ -218,7 +233,7 @@
 
 config SOUND_AU1000
 	tristate "Au1000 Sound"
-	depends on SOUND_PRIME && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500)
+	depends on SOUND_PRIME && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && OBSOLETE_OSS_DRIVER
 
 config SOUND_AU1550_AC97
 	tristate "Au1550 AC97 Sound"
@@ -492,7 +507,7 @@
 
 config SOUND_VIA82CXXX
 	tristate "VIA 82C686 Audio Codec"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y here to include support for the audio codec found on VIA
 	  82Cxxx-based chips. Typically these are built into a motherboard.
@@ -563,7 +578,7 @@
 
 config SOUND_SGALAXY
 	tristate "Aztech Sound Galaxy (non-PnP) cards"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	help
 	  This module initializes the older non Plug and Play sound galaxy
 	  cards from Aztech. It supports the Waverider Pro 32 - 3D and the
@@ -599,7 +614,7 @@
 
 config SOUND_CS4232
 	tristate "Crystal CS4232 based (PnP) cards"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y here if you have a card based on the Crystal CS4232 chip set,
 	  which uses its own Plug and Play protocol.
@@ -613,7 +628,7 @@
 
 config SOUND_SSCAPE
 	tristate "Ensoniq SoundScape support"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	help
 	  Answer Y if you have a sound card based on the Ensoniq SoundScape
 	  chipset. Such cards are being manufactured at least by Ensoniq, Spea
@@ -625,7 +640,7 @@
 
 config SOUND_GUS
 	tristate "Gravis Ultrasound support"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y here for any type of Gravis Ultrasound card, including the GUS
 	  or GUS MAX.  See also <file:Documentation/sound/oss/ultrasound> for more
@@ -727,7 +742,7 @@
 
 config SOUND_NM256
 	tristate "NM256AV/NM256ZX audio support"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	help
 	  Say M here to include audio support for the NeoMagic 256AV/256ZX
 	  chipsets. These are the audio chipsets found in the Sony
@@ -739,7 +754,7 @@
 
 config SOUND_MAD16
 	tristate "OPTi MAD16 and/or Mozart based cards"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	---help---
 	  Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi
 	  82C928 or 82C929 or 82C931) audio interface chip. These chips are
@@ -860,7 +875,7 @@
 
 config SOUND_AWE32_SYNTH
 	tristate "AWE32 synth"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or
 	  similar sound card. See <file:Documentation/sound/oss/README.awe>,
@@ -870,7 +885,7 @@
 
 config SOUND_WAVEFRONT
 	tristate "Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards"
-	depends on SOUND_OSS && m
+	depends on SOUND_OSS && m && OBSOLETE_OSS_DRIVER
 	help
 	  Answer Y or M if you have a Tropez Plus, Tropez or Maui sound card
 	  and read the files <file:Documentation/sound/oss/Wavefront> and
@@ -878,7 +893,7 @@
 
 config SOUND_MAUI
 	tristate "Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y here if you have a Turtle Beach Wave Front, Maui, or Tropez
 	  sound card.
@@ -904,7 +919,7 @@
 
 config SOUND_YM3812
 	tristate "Yamaha FM synthesizer (YM3812/OPL-3) support"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	---help---
 	  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
 	  Answering Y is usually a safe and recommended choice, however some
@@ -920,7 +935,7 @@
 
 config SOUND_OPL3SA1
 	tristate "Yamaha OPL3-SA1 audio controller"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is
 	  usually built into motherboards. Read
@@ -946,7 +961,7 @@
 
 config SOUND_YMFPCI
 	tristate "Yamaha YMF7xx PCI audio (native mode)"
-	depends on SOUND_OSS && PCI
+	depends on SOUND_OSS && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Support for Yamaha cards including the YMF711, YMF715, YMF718,
 	  YMF719, YMF724, Waveforce 192XG, and Waveforce 192 Digital.
@@ -1088,11 +1103,11 @@
 
 config SOUND_ALI5455
 	tristate "ALi5455 audio support"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 
 config SOUND_FORTE
 	tristate "ForteMedia FM801 driver"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you want driver support for the ForteMedia FM801 PCI
 	  audio controller (Abit AU10, Genius Sound Maker, HP Workstation
@@ -1100,7 +1115,7 @@
 
 config SOUND_RME96XX
 	tristate "RME Hammerfall (RME96XX) support"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 	help
 	  Say Y or M if you have a Hammerfall or Hammerfall light
 	  multichannel card from RME. If you want to access advanced
@@ -1108,7 +1123,7 @@
 
 config SOUND_AD1980
 	tristate "AD1980 front/back switch plugin"
-	depends on SOUND_PRIME
+	depends on SOUND_PRIME && OBSOLETE_OSS_DRIVER
 
 config SOUND_SH_DAC_AUDIO
 	tristate "SuperH DAC audio support"
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c
index 4f1ff1b..a7ad2b0 100644
--- a/sound/oss/msnd.c
+++ b/sound/oss/msnd.c
@@ -24,7 +24,6 @@
  *
  ********************************************************************/
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
diff --git a/sound/oss/os.h b/sound/oss/os.h
index 80dce32..0490562 100644
--- a/sound/oss/os.h
+++ b/sound/oss/os.h
@@ -5,10 +5,8 @@
 #undef  DO_TIMINGS
 
 #include <linux/module.h>
-#include <linux/version.h>
 
 #ifdef __KERNEL__
-#include <linux/utsname.h>
 #include <linux/string.h>
 #include <linux/fs.h>
 #include <asm/dma.h>
diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c
index 7609c68..318dc51 100644
--- a/sound/oss/rme96xx.c
+++ b/sound/oss/rme96xx.c
@@ -44,7 +44,6 @@
 #define RMEVERSION "0.8"
 #endif
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/sched.h>
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
index c09cdee..8a9917c9 100644
--- a/sound/oss/sh_dac_audio.c
+++ b/sound/oss/sh_dac_audio.c
@@ -2,7 +2,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/linkage.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index e72ccd1..1fdae67 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -1067,7 +1067,6 @@
 
 static struct pci_driver ad1889_pci = {
 	.name = "AD1889 Audio",
-	.owner = THIS_MODULE,
 	.id_table = snd_ad1889_ids,
 	.probe = snd_ad1889_probe,
 	.remove = __devexit_p(snd_ad1889_remove),
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 4e76c4a..feffbe7 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -2403,7 +2403,6 @@
 
 static struct pci_driver driver = {
 	.name = "ALI 5451",
-	.owner = THIS_MODULE,
 	.id_table = snd_ali_ids,
 	.probe = snd_ali_probe,
 	.remove = __devexit_p(snd_ali_remove),
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 7c61561f..1904df6 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -768,7 +768,6 @@
 
 static struct pci_driver driver = {
 	.name = "ALS4000",
-	.owner = THIS_MODULE,
 	.id_table = snd_als4000_ids,
 	.probe = snd_card_als4000_probe,
 	.remove = __devexit_p(snd_card_als4000_remove),
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index f5dad92..8bae10d 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1635,7 +1635,6 @@
 
 static struct pci_driver driver = {
 	.name = "ATI IXP AC97 controller",
-	.owner = THIS_MODULE,
 	.id_table = snd_atiixp_ids,
 	.probe = snd_atiixp_probe,
 	.remove = __devexit_p(snd_atiixp_remove),
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 0cf2020..3174b66 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1309,7 +1309,6 @@
 
 static struct pci_driver driver = {
 	.name = "ATI IXP MC97 controller",
-	.owner = THIS_MODULE,
 	.id_table = snd_atiixp_ids,
 	.probe = snd_atiixp_probe,
 	.remove = __devexit_p(snd_atiixp_remove),
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 6af3b13..d965609 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -373,7 +373,6 @@
 // pci_driver definition
 static struct pci_driver driver = {
 	.name = CARD_NAME_SHORT,
-	.owner = THIS_MODULE,
 	.id_table = snd_vortex_ids,
 	.probe = snd_vortex_probe,
 	.remove = __devexit_p(snd_vortex_remove),
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index da99b1b..ab737d6 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1838,7 +1838,6 @@
 
 static struct pci_driver driver = {
 	.name = "AZF3328",
-	.owner = THIS_MODULE,
 	.id_table = snd_azf3328_ids,
 	.probe = snd_azf3328_probe,
 	.remove = __devexit_p(snd_azf3328_remove),
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 01d98ee..8feca22 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -897,14 +897,13 @@
 /* default entries for all Bt87x cards - it's not exported */
 /* driver_data is set to 0 to call detection */
 static struct pci_device_id snd_bt87x_default_ids[] = {
-	BT_DEVICE(878, PCI_ANY_ID, PCI_ANY_ID, 0),
-	BT_DEVICE(879, PCI_ANY_ID, PCI_ANY_ID, 0),
+	BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, 0),
+	BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, 0),
 	{ }
 };
 
 static struct pci_driver driver = {
 	.name = "Bt87x",
-	.owner = THIS_MODULE,
 	.id_table = snd_bt87x_ids,
 	.probe = snd_bt87x_probe,
 	.remove = __devexit_p(snd_bt87x_remove),
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index ee58d16..389d967 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1499,7 +1499,6 @@
 // pci_driver definition
 static struct pci_driver driver = {
 	.name = "CA0106",
-	.owner = THIS_MODULE,
 	.id_table = snd_ca0106_ids,
 	.probe = snd_ca0106_probe,
 	.remove = __devexit_p(snd_ca0106_remove),
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 57e8e43..db60537 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -3053,7 +3053,6 @@
 
 static struct pci_driver driver = {
 	.name = "C-Media PCI",
-	.owner = THIS_MODULE,
 	.id_table = snd_cmipci_ids,
 	.probe = snd_cmipci_probe,
 	.remove = __devexit_p(snd_cmipci_remove),
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index aea2c47..034ff37 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -2106,7 +2106,6 @@
 
 static struct pci_driver driver = {
 	.name = "CS4281",
-	.owner = THIS_MODULE,
 	.id_table = snd_cs4281_ids,
 	.probe = snd_cs4281_probe,
 	.remove = __devexit_p(snd_cs4281_remove),
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 32b4f84..b9fff4e 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -163,7 +163,6 @@
 
 static struct pci_driver driver = {
 	.name = "Sound Fusion CS46xx",
-	.owner = THIS_MODULE,
 	.id_table = snd_cs46xx_ids,
 	.probe = snd_card_cs46xx_probe,
 	.remove = __devexit_p(snd_card_cs46xx_remove),
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index dd1ea9d..78270f8 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -223,7 +223,6 @@
 
 static struct pci_driver driver = {
 	.name = "EMU10K1_Audigy",
-	.owner = THIS_MODULE,
 	.id_table = snd_emu10k1_ids,
 	.probe = snd_card_emu10k1_probe,
 	.remove = __devexit_p(snd_card_emu10k1_remove),
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index cbb6894..7955777 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1613,7 +1613,6 @@
 // pci_driver definition
 static struct pci_driver driver = {
 	.name = "EMU10K1X",
-	.owner = THIS_MODULE,
 	.id_table = snd_emu10k1x_ids,
 	.probe = snd_emu10k1x_probe,
 	.remove = __devexit_p(snd_emu10k1x_remove),
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 92ff7c5..2daa575 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -2386,7 +2386,6 @@
 
 static struct pci_driver driver = {
 	.name = DRIVER_NAME,
-	.owner = THIS_MODULE,
 	.id_table = snd_audiopci_ids,
 	.probe = snd_audiopci_probe,
 	.remove = __devexit_p(snd_audiopci_remove),
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 78f90de..c134f48 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1758,7 +1758,6 @@
 
 static struct pci_driver driver = {
 	.name = "ESS ES1938 (Solo-1)",
-	.owner = THIS_MODULE,
 	.id_table = snd_es1938_ids,
 	.probe = snd_es1938_probe,
 	.remove = __devexit_p(snd_es1938_remove),
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index ac8294e..50079dc 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -2761,7 +2761,6 @@
 
 static struct pci_driver driver = {
 	.name = "ES1968 (ESS Maestro)",
-	.owner = THIS_MODULE,
 	.id_table = snd_es1968_ids,
 	.probe = snd_es1968_probe,
 	.remove = __devexit_p(snd_es1968_remove),
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 4c7c8d2..4e1d343 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1459,7 +1459,6 @@
 
 static struct pci_driver driver = {
 	.name = "FM801",
-	.owner = THIS_MODULE,
 	.id_table = snd_fm801_ids,
 	.probe = snd_card_fm801_probe,
 	.remove = __devexit_p(snd_card_fm801_remove),
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 9d1412a..ed525c0 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1616,7 +1616,6 @@
 /* pci_driver definition */
 static struct pci_driver driver = {
 	.name = "HDA Intel",
-	.owner = THIS_MODULE,
 	.id_table = azx_ids,
 	.probe = azx_probe,
 	.remove = __devexit_p(azx_remove),
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 5aca377..bd71bf4 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -2735,7 +2735,6 @@
 
 static struct pci_driver driver = {
 	.name = "ICE1712",
-	.owner = THIS_MODULE,
 	.id_table = snd_ice1712_ids,
 	.probe = snd_ice1712_probe,
 	.remove = __devexit_p(snd_ice1712_remove),
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 5b4293f..0b5389e 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2332,7 +2332,6 @@
 
 static struct pci_driver driver = {
 	.name = "ICE1724",
-	.owner = THIS_MODULE,
 	.id_table = snd_vt1724_ids,
 	.probe = snd_vt1724_probe,
 	.remove = __devexit_p(snd_vt1724_remove),
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 0801083..cf7801d 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -2876,7 +2876,6 @@
 
 static struct pci_driver driver = {
 	.name = "Intel ICH",
-	.owner = THIS_MODULE,
 	.id_table = snd_intel8x0_ids,
 	.probe = snd_intel8x0_probe,
 	.remove = __devexit_p(snd_intel8x0_remove),
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index acfb197..a420918 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -1317,7 +1317,6 @@
 
 static struct pci_driver driver = {
 	.name = "Intel ICH Modem",
-	.owner = THIS_MODULE,
 	.id_table = snd_intel8x0m_ids,
 	.probe = snd_intel8x0m_probe,
 	.remove = __devexit_p(snd_intel8x0m_remove),
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 5561fd4..a110d66 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2534,7 +2534,6 @@
 
 static struct pci_driver driver = {
 	.name = "korg1212",
-	.owner = THIS_MODULE,
 	.id_table = snd_korg1212_ids,
 	.probe = snd_korg1212_probe,
 	.remove = __devexit_p(snd_korg1212_remove),
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 99eb76c5..ede7a75 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -2858,7 +2858,6 @@
 
 static struct pci_driver driver = {
 	.name = "Maestro3",
-	.owner = THIS_MODULE,
 	.id_table = snd_m3_ids,
 	.probe = snd_m3_probe,
 	.remove = __devexit_p(snd_m3_remove),
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index c341c99..b3090a1 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1423,7 +1423,6 @@
 
 static struct pci_driver driver = {
 	.name = "Digigram miXart",
-	.owner = THIS_MODULE,
 	.id_table = snd_mixart_ids,
 	.probe = snd_mixart_probe,
 	.remove = __devexit_p(snd_mixart_remove),
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index e7aa151..089d23b 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1673,7 +1673,6 @@
 
 static struct pci_driver driver = {
 	.name = "NeoMagic 256",
-	.owner = THIS_MODULE,
 	.id_table = snd_nm256_ids,
 	.probe = snd_nm256_probe,
 	.remove = __devexit_p(snd_nm256_remove),
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index e6627b0..783df76 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -2012,7 +2012,6 @@
 
 static struct pci_driver driver = {
 	.name =		"RME Digi32",
-	.owner =	THIS_MODULE,
 	.id_table =	snd_rme32_ids,
 	.probe =	snd_rme32_probe,
 	.remove =	__devexit_p(snd_rme32_remove),
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 0eddeb1..6d422ef 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -2413,7 +2413,6 @@
 
 static struct pci_driver driver = {
 	.name = "RME Digi96",
-	.owner = THIS_MODULE,
 	.id_table = snd_rme96_ids,
 	.probe = snd_rme96_probe,
 	.remove = __devexit_p(snd_rme96_remove),
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 845158b..d15ffb3 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -5062,7 +5062,6 @@
 
 static struct pci_driver driver = {
 	.name =     "RME Hammerfall DSP",
-	.owner =    THIS_MODULE,
 	.id_table = snd_hdsp_ids,
 	.probe =    snd_hdsp_probe,
 	.remove = __devexit_p(snd_hdsp_remove),
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 60a1141..a1aef6f 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -3639,7 +3639,6 @@
 
 static struct pci_driver driver = {
 	.name = "RME Hammerfall DSP MADI",
-	.owner = THIS_MODULE,
 	.id_table = snd_hdspm_ids,
 	.probe = snd_hdspm_probe,
 	.remove = __devexit_p(snd_hdspm_remove),
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index 59fcef9..f9d0c12 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -2654,7 +2654,6 @@
 
 static struct pci_driver driver = {
 	.name	  = "RME Digi9652 (Hammerfall)",
-	.owner	  = THIS_MODULE,
 	.id_table = snd_rme9652_ids,
 	.probe	  = snd_rme9652_probe,
 	.remove	  = __devexit_p(snd_rme9652_remove),
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 9a35474..e92ef3a 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -1502,7 +1502,6 @@
 
 static struct pci_driver driver = {
 	.name = "S3 SonicVibes",
-	.owner = THIS_MODULE,
 	.id_table = snd_sonic_ids,
 	.probe = snd_sonic_probe,
 	.remove = __devexit_p(snd_sonic_remove),
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index a8ca8e1..940d531 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -177,7 +177,6 @@
 
 static struct pci_driver driver = {
 	.name = "Trident4DWaveAudio",
-	.owner = THIS_MODULE,
 	.id_table = snd_trident_ids,
 	.probe = snd_trident_probe,
 	.remove = __devexit_p(snd_trident_remove),
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 523eace..fad2a24 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -2478,7 +2478,6 @@
 
 static struct pci_driver driver = {
 	.name = "VIA 82xx Audio",
-	.owner = THIS_MODULE,
 	.id_table = snd_via82xx_ids,
 	.probe = snd_via82xx_probe,
 	.remove = __devexit_p(snd_via82xx_remove),
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 011f0fb..b83660b 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -1198,7 +1198,6 @@
 
 static struct pci_driver driver = {
 	.name = "VIA 82xx Modem",
-	.owner = THIS_MODULE,
 	.id_table = snd_via82xx_modem_ids,
 	.probe = snd_via82xx_probe,
 	.remove = __devexit_p(snd_via82xx_remove),
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 2a7ad9d..dca6bd2 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -252,7 +252,6 @@
 
 static struct pci_driver driver = {
 	.name = "Digigram VX222",
-	.owner = THIS_MODULE,
 	.id_table = snd_vx222_ids,
 	.probe = snd_vx222_probe,
 	.remove = __devexit_p(snd_vx222_remove),
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 1bbba32..d013237 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -344,7 +344,6 @@
 
 static struct pci_driver driver = {
 	.name = "Yamaha DS-XG PCI",
-	.owner = THIS_MODULE,
 	.id_table = snd_ymfpci_ids,
 	.probe = snd_card_ymfpci_probe,
 	.remove = __devexit_p(snd_card_ymfpci_remove),
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
index ae3bb6c..bfff788 100644
--- a/sound/ppc/pmac.h
+++ b/sound/ppc/pmac.h
@@ -22,7 +22,6 @@
 #ifndef __PMAC_H
 #define __PMAC_H
 
-#include <linux/version.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include "awacs.h"