Pull memoryless-node-allocation into release branch
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/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/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 995bfd8..5541f99 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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/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..ec77721 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -356,6 +356,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/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/scoop.c b/arch/arm/common/scoop.c
index bb4eff6..c7fdf39 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;
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/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
index be283cd..399010c 100644
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap1/leds-h2p2-debug.c
@@ -13,7 +13,6 @@
 #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>
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/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/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/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/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/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/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 b48ac63..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 47ec767..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/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/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..640d690 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -197,11 +197,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 +267,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 +288,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();
 	}
 }
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/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/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..13d1093 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..ed31062 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -599,6 +599,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..c04bbd3 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,15 +12,21 @@
 endif
 
 obj-y				:= semaphore.o cputable.o ptrace.o syscalls.o \
-				   signal_32.o pmc.o
+				   irq.o signal_32.o pmc.o
 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
 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
 
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index b757572..8793102 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -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 */
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 1fb673c..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_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 98%
rename from arch/ppc64/kernel/lparcfg.c
rename to arch/powerpc/kernel/lparcfg.c
index 3e7b2f2..5e954fa 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/systemcfg.h>
 
 #define MODULE_VERS "1.6"
 #define MODULE_NAME "lparcfg"
@@ -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,
@@ -273,7 +274,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
@@ -371,7 +372,7 @@
 	lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity", NULL);
 
 	if (lrdrp == NULL) {
-		partition_potential_processors = systemcfg->processorCount;
+		partition_potential_processors = _systemcfg->processorCount;
 	} else {
 		partition_potential_processors = *(lrdrp + 4);
 	}
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 97%
rename from arch/ppc64/kernel/pacaData.c
rename to arch/powerpc/kernel/paca.c
index 3133c72..3cf2517 100644
--- a/arch/ppc64/kernel/pacaData.c
+++ b/arch/powerpc/kernel/paca.c
@@ -15,7 +15,7 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/page.h>
-
+#include <asm/systemcfg.h>
 #include <asm/lppaca.h>
 #include <asm/iseries/it_lp_queue.h>
 #include <asm/paca.h>
@@ -24,15 +24,14 @@
 	struct systemcfg	data;
 	u8			page[PAGE_SIZE];
 } systemcfg_store __attribute__((__section__(".data.page.aligned")));
-struct systemcfg *systemcfg = &systemcfg_store.data;
-EXPORT_SYMBOL(systemcfg);
+struct systemcfg *_systemcfg = &systemcfg_store.data;
 
 
 /* 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 95%
rename from arch/ppc64/kernel/proc_ppc64.c
rename to arch/powerpc/kernel/proc_ppc64.c
index 24e955e..a1c1950 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
@@ -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 = _systemcfg;
 	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..ae1a364 100644
--- a/arch/powerpc/kernel/rtas-proc.c
+++ b/arch/powerpc/kernel/rtas-proc.c
@@ -259,7 +259,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..bae4bff 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/systemcfg.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
  */ 
@@ -510,8 +521,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 +566,27 @@
 			cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]);
 	}
 
-	systemcfg->processorCount = num_present_cpus();
+	_systemcfg->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..6791668 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -61,6 +61,8 @@
 #include <asm/xmon.h>
 #include <asm/udbg.h>
 
+#include "setup.h"
+
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
 #else
@@ -94,15 +96,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 +247,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 +282,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 +329,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 +355,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,8 +375,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 =
+			_systemcfg->dcache_size = ppc64_caches.dsize = size;
+			_systemcfg->dcache_line_size =
 				ppc64_caches.dline_size = lsize;
 			ppc64_caches.log_dline_size = __ilog2(lsize);
 			ppc64_caches.dlines_per_page = PAGE_SIZE / lsize;
@@ -378,8 +393,8 @@
 				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 =
+			_systemcfg->icache_size = ppc64_caches.isize = size;
+			_systemcfg->icache_line_size =
 				ppc64_caches.iline_size = lsize;
 			ppc64_caches.log_iline_size = __ilog2(lsize);
 			ppc64_caches.ilines_per_page = PAGE_SIZE / lsize;
@@ -387,10 +402,12 @@
 	}
 
 	/* 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);
+	strcpy(_systemcfg->eye_catcher, "SYSTEMCFG:PPC64");
+	_systemcfg->version.major = SYSTEMCFG_MAJOR;
+	_systemcfg->version.minor = SYSTEMCFG_MINOR;
+	_systemcfg->processor = mfspr(SPRN_PVR);
+	_systemcfg->platform = _machine;
+	_systemcfg->physicalMemorySize = lmb_phys_mem_size();
 
 	DBG(" <- initialize_cache_info()\n");
 }
@@ -479,10 +496,10 @@
 	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("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_caches.dcache_line_size = 0x%x\n",
 			ppc64_caches.dline_size);
 	printk("ppc64_caches.icache_line_size = 0x%x\n",
@@ -564,12 +581,12 @@
 	for (i = 0; i < __NR_syscalls; i++) {
 		if (sys_call_table[i*2] != sys_ni_syscall) {
 			count64++;
-			systemcfg->syscall_map_64[i >> 5] |=
+			_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] |=
+			_systemcfg->syscall_map_32[i >> 5] |=
 				0x80000000UL >> (i & 0x1f);
 		}
 	}
@@ -858,26 +875,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..a7c4515 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -42,6 +42,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
+#include <asm/sigcontext.h>
 #ifdef CONFIG_PPC64
 #include "ppc32.h"
 #include <asm/unistd.h>
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 5c330c3..e28a139 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/systemcfg.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
+	_systemcfg->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..850af19 100644
--- a/arch/ppc64/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -232,7 +232,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..260b6ec 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -271,13 +271,13 @@
 	 * 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);
+	++(_systemcfg->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;
+	_systemcfg->tb_orig_stamp = new_tb_stamp;
+	_systemcfg->stamp_xsec = new_stamp_xsec;
+	_systemcfg->tb_to_xs = new_tb_to_xs;
 	smp_wmb();
-	++(systemcfg->tb_update_count);
+	++(_systemcfg->tb_update_count);
 #endif
 }
 
@@ -357,8 +357,9 @@
 				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;
+				_systemcfg->tb_ticks_per_sec =
+					tb_ticks_per_sec;
+				_systemcfg->tb_to_xs = tb_to_xs;
 			}
 			else {
 				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
@@ -483,6 +484,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;
@@ -559,8 +562,8 @@
 	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;
+	_systemcfg->tz_minuteswest = sys_tz.tz_minuteswest;
+	_systemcfg->tz_dsttime = sys_tz.tz_dsttime;
 #endif
 
 	write_sequnlock_irqrestore(&xtime_lock, flags);
@@ -711,11 +714,11 @@
 	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;
+	_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
 
 	time_freq = 0;
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 32f2158..2020bb7 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -129,7 +129,7 @@
 	nl = 1;
 #endif
 #ifdef CONFIG_PPC64
-	switch (systemcfg->platform) {
+	switch (_machine) {
 	case PLATFORM_PSERIES:
 		printk("PSERIES ");
 		nl = 1;
@@ -887,10 +887,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/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..1dd3cc6 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -110,6 +110,7 @@
 void online_page(struct page *page)
 {
 	ClearPageReserved(page);
+	set_page_count(page, 0);
 	free_cold_page(page);
 	totalram_pages++;
 	num_physpages++;
@@ -127,6 +128,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;
 
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..e3a024e 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -233,8 +233,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..00cf331 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -482,10 +482,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..e94247c 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;
@@ -378,7 +378,7 @@
 
 	fw_feature_init();
 	
-	if (systemcfg->platform & PLATFORM_LPAR)
+	if (platform_is_lpar())
 		hpte_init_lpar();
 	else {
 		hpte_init_native();
@@ -388,7 +388,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 +469,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 +482,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 +494,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 +507,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 +530,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 +581,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 +592,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..3ba794c 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/systemcfg.h>
 
 #include "plpar_wrappers.h"
 
@@ -96,7 +97,7 @@
 	int cpu = smp_processor_id();
 
 	cpu_clear(cpu, cpu_online_map);
-	systemcfg->processorCount--;
+	_systemcfg->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..cfcb2a5 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();
@@ -1797,7 +1792,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 +1971,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 +2147,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 +2367,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 +2521,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/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/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/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..c9d32db 100644
--- a/arch/ppc64/Kconfig
+++ b/arch/ppc64/Kconfig
@@ -297,6 +297,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..58b19f1 100644
--- a/arch/ppc64/kernel/Makefile
+++ b/arch/ppc64/kernel/Makefile
@@ -11,12 +11,11 @@
 
 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 \
+			udbg.o \
 			rtc.o \
-			cpu_setup_power4.o \
-			iommu.o sysfs.o vdso.o firmware.o
+			iommu.o vdso.o
 obj-y += vdso32/ vdso64/
 
 pci-obj-$(CONFIG_PPC_MULTIPLATFORM)	+= pci_dn.o pci_direct_iommu.o
@@ -31,15 +30,10 @@
 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
@@ -52,8 +46,6 @@
 
 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..492bca6 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
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 e4c880d..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/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index c9f2f60..dee6ab5 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..78b64fe 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/smp.c b/arch/sparc64/kernel/smp.c
index 5d90ee9..797a654 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -168,6 +168,9 @@
 		rmb();
 
 	cpu_set(cpuid, cpu_online_map);
+
+	/* idle thread is expected to have preempt disabled */
+	preempt_disable();
 }
 
 void cpu_panic(void)
@@ -1149,20 +1152,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..4cf31a2 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
@@ -359,7 +343,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/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..96b9bb4 100644
--- a/arch/xtensa/platform-iss/network.c
+++ b/arch/xtensa/platform-iss/network.c
@@ -611,38 +611,6 @@
 	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)
 {
 }
@@ -730,7 +698,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/processor_idle.c b/drivers/acpi/processor_idle.c
index 161db4a..573b6a9 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/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/floppy.c b/drivers/block/floppy.c
index 5eadbb9..28002de 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/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/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..34a4446 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 = {
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index bf4cc9f..027161a 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);
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/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/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/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/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/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/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/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-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index c9366b5..a2237d4 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");
 	}
 
@@ -462,9 +463,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/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/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/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/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 d538a99..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 a5ed99b..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..d54bc01
--- /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..57c1826
--- /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/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index 9c4dd68..bc2b72b 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>
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 165f340..4bb4617 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>
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/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/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/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/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/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..5c69d57 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
@@ -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/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/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..f8c9bcd 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>
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/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..54d294a 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>
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..7263395 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>
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..be191d8 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>
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/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/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/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/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/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/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/airo.c b/drivers/net/wireless/airo.c
index 6afc6e5..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..a3e2352 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -2217,7 +2217,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;
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 195cb36..1bd1314 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -180,12 +180,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 +203,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 */
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/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index fcb66b9..e8593a6 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -306,7 +306,7 @@
 {
 	struct pci_controller *phb;
 
-	if (PCI_DN(dn)->phb) {
+	if (PCI_DN(dn) && PCI_DN(dn)->phb) {
 		/* PHB already exists */
 		return -EINVAL;
 	}
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/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..2c86a4b 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -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/a2091.c b/drivers/scsi/a2091.c
index f7a1751..30a14ba 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>
 
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 4612312..10c470e 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,
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.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/amiga7xx.c b/drivers/scsi/amiga7xx.c
index 5f13546..dea8446 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>
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 7f8aa1b..a1bd8d9 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>
 
@@ -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/bvme6000.c b/drivers/scsi/bvme6000.c
index 29c7ed3..130f30f 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>
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index d12342f..ab22387 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>
 
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 887a5c3..8d97999 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>
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index c888af4..3553da0 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))
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index 505e967..adc6eab 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>
 
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 1c1a7ca..a74b407 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.
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index eb604b0..bb30fcd 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -37,9 +37,9 @@
 #include <linux/blkdev.h>
 #include <linux/spinlock.h>
 #include <scsi/scsi.h>
-#include "scsi.h"
 #include <scsi/scsi_host.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 +131,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:
@@ -217,7 +217,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:
@@ -416,6 +416,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
@@ -2231,7 +2232,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/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 69df1a9..8e54713 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>
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..801a63b 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>
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index 2fb31ee..33380ce 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>
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
index b2d8d8e..29ec699 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>
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/pci2000.h b/drivers/scsi/pci2000.h
index c65afc9..6c962d7 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))
 
 /************************************************/
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index a50588c..78b4ff1 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,
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index 0f469e3..93d5523 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,
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index d573888..37a4fae 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>
 
@@ -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..9edc9d9 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,
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 65502c1..d274ab2 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,
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 435f7e0..d0e3c3c 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>
 
@@ -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..4682a50 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>
 
@@ -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..42d7c4e 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>
 
@@ -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..9895d1c 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,
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index f859bbd..d5a3878 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,
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index a5e245c..cf0baaa 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>
 
@@ -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..ab19d2b 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>
@@ -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..ce8a2fd 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,
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index aadf051..b61fb12 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"
 
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..f37147f 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>
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/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..9045190 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>
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/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index ee9cd78..510d28a 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>
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/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/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/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/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/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/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/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/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/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/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/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/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-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-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/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/firmware.h b/include/asm-powerpc/firmware.h
index 806c142..12fabbc 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..c9fbced 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -429,7 +429,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 +487,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..f6f186b 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
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..58d2aab 100644
--- a/include/asm-powerpc/sparsemem.h
+++ b/include/asm-powerpc/sparsemem.h
@@ -11,6 +11,10 @@
 #define MAX_PHYSADDR_BITS       38
 #define MAX_PHYSMEM_BITS        36
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+extern void create_section_mapping(unsigned long start, unsigned long end);
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
 #endif /* CONFIG_SPARSEMEM */
 
 #endif /* _ASM_POWERPC_SPARSEMEM_H */
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/systemcfg.h b/include/asm-powerpc/systemcfg.h
similarity index 95%
rename from include/asm-ppc64/systemcfg.h
rename to include/asm-powerpc/systemcfg.h
index 9b86b53..36b5cbe 100644
--- a/include/asm-ppc64/systemcfg.h
+++ b/include/asm-powerpc/systemcfg.h
@@ -1,7 +1,7 @@
 #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
@@ -12,7 +12,7 @@
 
 /* Change Activity:
  * 2002/09/30 : bergner  : Created
- * End Change Activity 
+ * End Change Activity
  */
 
 /*
@@ -56,7 +56,7 @@
 };
 
 #ifdef __KERNEL__
-extern struct systemcfg *systemcfg;
+extern struct systemcfg *_systemcfg; /* to be renamed */
 #endif
 
 #endif /* __ASSEMBLY__ */
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/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-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-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..15e777c 100644
--- a/include/asm-ppc64/mmzone.h
+++ b/include/asm-ppc64/mmzone.h
@@ -33,6 +33,9 @@
 extern char *numa_memory_lookup_table;
 extern cpumask_t numa_cpumask_lookup_table[];
 extern int nr_cpus_in_node[];
+#ifdef CONFIG_MEMORY_HOTPLUG
+extern unsigned long max_pfn;
+#endif
 
 /* 16MB regions */
 #define MEMORY_INCREMENT_SHIFT 24
@@ -45,6 +48,11 @@
 {
 	int nid;
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+	/* kludge hot added sections default to node 0 */
+	if (pa >= (max_pfn << PAGE_SHIFT))
+		return 0;
+#endif
 	nid = numa_memory_lookup_table[pa >> MEMORY_INCREMENT_SHIFT];
 
 #ifdef DEBUG_NUMA
diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
index 82ce187..e32f118 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
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-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..db0606c 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 6fd514d..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/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/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..77ae55d 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)
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..6f07522 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -214,7 +214,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,7 +398,7 @@
 };
 
 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;
@@ -433,7 +433,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/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_ids.h b/include/linux/pci_ids.h
index 9a96f05..4e06eb0 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
@@ -487,6 +488,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
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/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/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..8301023 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
@@ -1313,10 +1316,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..22cf5e1 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
 {
@@ -925,6 +963,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/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..ff13c4c 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;							\
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/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/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/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 0353206..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/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/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/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/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_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..5198f3a 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -151,13 +151,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 +166,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 +174,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 +190,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)
@@ -296,7 +296,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 +305,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/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 49d67cd..634dabb 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -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)
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/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..651c79b 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);
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/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..a84f9221 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/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/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/xdr.c b/net/sunrpc/xdr.c
index 32df433..aaf08cd 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/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..8a9917c 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/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"